diff options
| author | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-15 12:11:02 +0000 |
|---|---|---|
| committer | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-15 12:11:02 +0000 |
| commit | 7411d71fbde5d652f04cc8851ed93bd15513968b (patch) | |
| tree | 2fe1e8fa9a604dc558a0528d8f465bef8b597aab /docs | |
| parent | 1925cf6f1a8c134cbfae728023ac325f03e4c14f (diff) | |
Some docs for plugins, among other things.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/PLUGINS.md | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/docs/PLUGINS.md b/docs/PLUGINS.md new file mode 100644 index 0000000..ea21485 --- /dev/null +++ b/docs/PLUGINS.md @@ -0,0 +1,170 @@ +# Zen C Plugin System Guide + +Zen C offers a plugin system that allows you to extend the language syntax and transpilation process. Plugins act as compile-time hooks that can parse arbitrary text blocks and generate C code. + +## Quick Start + +### Using a Plugin + +To use a plugin, import it using the `import plugin` syntax: + +```zc +import plugin "regex" as re +// or simple: import plugin "regex" (uses "regex" as identifier) + +fn main() { + var valid = re! { ^[a-z]+$ }; +} +``` + +The syntax `alias! { ... }` invokes the plugin. The content inside the braces is passed as a raw string to the plugin's transpiler function. + +## Creating a Plugin + +Plugins are written in C and compiled into shared objects (or built-in to the compiler). + +### API Reference (`zprep_plugin.h`) + +The core API is simple. A plugin exposes a `ZPlugin` struct containing its name and a transpiler function. + +```c +typedef struct { + // -> Context information + const char *filename; // Current file being compiled + int current_line; // Line number of the invocation + FILE *out; // Output stream (injects code at call site) + FILE *hoist_out; // Hoisted output (injects code at file scope) +} ZApi; + +// -> The transpiler function +// input_body: The raw text inside the plugin block { ... } +// api: Access to transpiler context and output streams +typedef void (*ZPluginTranspileFn)(const char *input_body, const ZApi *api); + +typedef struct { + char name[32]; + ZPluginTranspileFn fn; +} ZPlugin; +``` + +### Writing a Brainfuck Plugin + +Let's implement a plugin that compiles Brainfuck code directly into C logic at compile time. + +#### 1. Include the API + +```c +#include "zprep_plugin.h" +``` + +#### 2. Implement the transpiler + +The transpiler function reads the Brainfuck source code and writes equivalent C code to `api->out`. + +```c +void bf_transpile(const char *input_body, const ZApi *api) +{ + FILE *out = api->out; + + // Initialize tape and pointer in a local block. + fprintf(out, "{\n"); + fprintf(out, " static unsigned char tape[30000] = {0};\n"); + fprintf(out, " unsigned char *ptr = tape;\n"); + + const char *c = input_body; + while (*c) + { + switch (*c) + { + case '>': fprintf(out, " ++ptr;\n"); break; + case '<': fprintf(out, " --ptr;\n"); break; + case '+': fprintf(out, " ++*ptr;\n"); break; + case '-': fprintf(out, " --*ptr;\n"); break; + case '.': fprintf(out, " putchar(*ptr);\n"); break; + case ',': fprintf(out, " *ptr = getchar();\n"); break; + case '[': fprintf(out, " while (*ptr) {\n"); break; + case ']': fprintf(out, " }\n"); break; + } + c++; + } + fprintf(out, "}\n"); +} +``` + +#### 3. Register the Plugin + +For dynamic plugins, you must export a `z_plugin_init` function that returns a pointer to your `ZPlugin` struct. + +```c +ZPlugin brainfuck_plugin = { + .name = "brainfuck", + .fn = bf_transpile +}; + +// Entry point for the dynamic loader +ZPlugin *z_plugin_init(void) +{ + return &brainfuck_plugin; +} +``` + +### Building the Plugin + +Compile your plugin as a shared object (`.so`). You'll need access to `zprep_plugin.h`. + +```bash +# If building from source repository: +gcc -shared -fPIC -o brainfuck.so brainfuck.c -I./plugins + +# If Zen C is installed system-wide: +gcc -shared -fPIC -o brainfuck.so brainfuck.c -I/usr/local/include/zenc +``` + +### Using the Plugin + +You can import plugins using relative paths or system-wide lookups: + +```zc +// Relative import (finds .so relative to this file) +import plugin "./brainfuck.so" as bf + +// System import (finds .so in CWD or library path) +import plugin "brainfuck.so" as bf2 + +fn main() { + bf! { + ++++++++++[>+++++++>++++++++++>+++<<<-]>++. + } +} +``` + +### Output example + +When you write: + +```zc +bf! { + ++++++++++[>+++++++>++++++++++>+++<<<-]>++. +} +``` + +The plugin generates: + +```c +{ + static unsigned char tape[30000] = {0}; + unsigned char *ptr = tape; + ++*ptr; + ++*ptr; + // ... (logic for + and [ ) + while (*ptr) { + ++ptr; + // ... + } + ptr++; + // ... + putchar(*ptr); +} +``` + +This C code is then compiled by the backend, resulting in a highly optimized native binary from your DSL! |
