|
| 1 | +# WokeLang ABI/FFI Architecture |
| 2 | + |
| 3 | +This document describes the WokeLang ABI (Application Binary Interface) and FFI (Foreign Function Interface) architecture. |
| 4 | + |
| 5 | +## Architecture Overview |
| 6 | + |
| 7 | +WokeLang follows the **Idris2 ABI + Zig FFI** universal standard: |
| 8 | + |
| 9 | +``` |
| 10 | +┌─────────────────────────────────────────────┐ |
| 11 | +│ Idris2 ABI Layer (src/abi/) │ |
| 12 | +│ - Type definitions with proofs │ |
| 13 | +│ - Memory layout verification │ |
| 14 | +│ - Platform-specific ABI guarantees │ |
| 15 | +└─────────────────────────────────────────────┘ |
| 16 | + ↓ |
| 17 | +┌─────────────────────────────────────────────┐ |
| 18 | +│ Zig FFI Layer (ffi/zig/) │ |
| 19 | +│ - C-compatible implementation │ |
| 20 | +│ - Zero-cost abstractions │ |
| 21 | +│ - Cross-platform compilation │ |
| 22 | +└─────────────────────────────────────────────┘ |
| 23 | + ↓ |
| 24 | +┌─────────────────────────────────────────────┐ |
| 25 | +│ Rust Core (src/ffi/c_api.rs) │ |
| 26 | +│ - Core interpreter implementation │ |
| 27 | +│ - Memory management │ |
| 28 | +│ - Language semantics │ |
| 29 | +└─────────────────────────────────────────────┘ |
| 30 | +``` |
| 31 | + |
| 32 | +## Directory Structure |
| 33 | + |
| 34 | +``` |
| 35 | +wokelang/ |
| 36 | +├── src/ |
| 37 | +│ └── abi/ # Idris2 ABI definitions |
| 38 | +│ ├── Types.idr # Type definitions with dependent type proofs |
| 39 | +│ ├── Layout.idr # Memory layout verification |
| 40 | +│ └── Foreign.idr # FFI declarations |
| 41 | +│ |
| 42 | +├── ffi/ |
| 43 | +│ └── zig/ # Zig FFI implementation |
| 44 | +│ ├── build.zig # Build configuration |
| 45 | +│ ├── src/ |
| 46 | +│ │ └── main.zig # C-compatible FFI functions |
| 47 | +│ └── test/ |
| 48 | +│ └── integration_test.zig |
| 49 | +│ |
| 50 | +├── generated/ |
| 51 | +│ └── abi/ # Auto-generated C headers |
| 52 | +│ └── wokelang.h # (Generated from Idris2) |
| 53 | +│ |
| 54 | +└── bindings/ # Language-specific wrappers (future) |
| 55 | + ├── rescript/ |
| 56 | + └── julia/ |
| 57 | +``` |
| 58 | + |
| 59 | +## Layer Responsibilities |
| 60 | + |
| 61 | +### 1. Idris2 ABI Layer (`src/abi/`) |
| 62 | + |
| 63 | +**Purpose**: Formal specification with compile-time proofs |
| 64 | + |
| 65 | +**Guarantees**: |
| 66 | +- Non-null pointer types (using dependent types) |
| 67 | +- Correct memory layout across platforms |
| 68 | +- ABI compatibility between versions |
| 69 | +- Type-safe foreign function declarations |
| 70 | + |
| 71 | +**Files**: |
| 72 | +- `Types.idr`: Core type definitions (`InterpreterHandle`, `ValueHandle`, `Result`, `ValueType`) |
| 73 | +- `Layout.idr`: Platform-specific layout proofs |
| 74 | +- `Foreign.idr`: FFI function declarations |
| 75 | + |
| 76 | +**Example Proof**: |
| 77 | +```idris |
| 78 | +-- Non-null pointer guaranteed at type level |
| 79 | +data InterpreterHandle : Type where |
| 80 | + MkInterpreterHandle : (ptr : Bits64) -> {auto 0 nonNull : So (ptr /= 0)} -> InterpreterHandle |
| 81 | +``` |
| 82 | + |
| 83 | +### 2. Zig FFI Layer (`ffi/zig/`) |
| 84 | + |
| 85 | +**Purpose**: C-compatible implementation with safety |
| 86 | + |
| 87 | +**Features**: |
| 88 | +- Native C ABI compatibility |
| 89 | +- Memory-safe by default |
| 90 | +- Cross-compilation support |
| 91 | +- Zero runtime overhead |
| 92 | + |
| 93 | +**Functions**: |
| 94 | +- Interpreter lifecycle: `woke_interpreter_new`, `woke_interpreter_free` |
| 95 | +- Execution: `woke_exec`, `woke_eval` |
| 96 | +- Value operations: `woke_value_*` functions |
| 97 | +- Utility: `woke_version`, `woke_last_error` |
| 98 | + |
| 99 | +**Example**: |
| 100 | +```zig |
| 101 | +export fn woke_interpreter_new() ?*InterpreterHandle { |
| 102 | + return rust_woke_interpreter_new(); |
| 103 | +} |
| 104 | +``` |
| 105 | + |
| 106 | +### 3. Rust Core (`src/ffi/c_api.rs`) |
| 107 | + |
| 108 | +**Purpose**: Core language implementation |
| 109 | + |
| 110 | +**Responsibilities**: |
| 111 | +- Lexer, parser, interpreter |
| 112 | +- Memory management (Box allocation) |
| 113 | +- Error handling |
| 114 | +- Value representation |
| 115 | + |
| 116 | +## Building |
| 117 | + |
| 118 | +### Build Rust Core |
| 119 | +```bash |
| 120 | +cargo build --release |
| 121 | +``` |
| 122 | + |
| 123 | +### Build Zig FFI |
| 124 | +```bash |
| 125 | +cd ffi/zig |
| 126 | +zig build |
| 127 | +zig build test # Run integration tests |
| 128 | +zig build example # Run example |
| 129 | +``` |
| 130 | + |
| 131 | +### Verify ABI Compliance |
| 132 | +```bash |
| 133 | +# Compile Idris2 ABI (generates C headers) |
| 134 | +cd src/abi |
| 135 | +idris2 --build wokelang-abi.ipkg |
| 136 | +``` |
| 137 | + |
| 138 | +## API Reference |
| 139 | + |
| 140 | +### Interpreter Lifecycle |
| 141 | + |
| 142 | +```c |
| 143 | +// Create interpreter (returns NULL on failure) |
| 144 | +InterpreterHandle* woke_interpreter_new(void); |
| 145 | + |
| 146 | +// Free interpreter |
| 147 | +void woke_interpreter_free(InterpreterHandle* interp); |
| 148 | +``` |
| 149 | +
|
| 150 | +### Execution |
| 151 | +
|
| 152 | +```c |
| 153 | +// Execute code (returns Result code) |
| 154 | +Result woke_exec(InterpreterHandle* interp, const char* source); |
| 155 | +
|
| 156 | +// Evaluate expression and get value |
| 157 | +Result woke_eval(InterpreterHandle* interp, const char* source, ValueHandle** out_value); |
| 158 | +``` |
| 159 | + |
| 160 | +### Value Operations |
| 161 | + |
| 162 | +```c |
| 163 | +// Free value |
| 164 | +void woke_value_free(ValueHandle* value); |
| 165 | + |
| 166 | +// Get value type |
| 167 | +ValueType woke_value_type(const ValueHandle* value); |
| 168 | + |
| 169 | +// Extract values |
| 170 | +Result woke_value_as_int(const ValueHandle* value, long long* out); |
| 171 | +Result woke_value_as_float(const ValueHandle* value, double* out); |
| 172 | +Result woke_value_as_bool(const ValueHandle* value, int* out); |
| 173 | +char* woke_value_as_string(const ValueHandle* value); // Must free with woke_string_free |
| 174 | + |
| 175 | +// Create values |
| 176 | +ValueHandle* woke_value_from_int(long long n); |
| 177 | +ValueHandle* woke_value_from_float(double f); |
| 178 | +ValueHandle* woke_value_from_bool(int b); |
| 179 | +ValueHandle* woke_value_from_string(const char* s); |
| 180 | +``` |
| 181 | +
|
| 182 | +### Utility |
| 183 | +
|
| 184 | +```c |
| 185 | +// Get version string |
| 186 | +const char* woke_version(void); |
| 187 | +
|
| 188 | +// Get last error message (NULL if no error) |
| 189 | +const char* woke_last_error(void); |
| 190 | +``` |
| 191 | + |
| 192 | +## Example Usage |
| 193 | + |
| 194 | +### Zig |
| 195 | +```zig |
| 196 | +const woke = @import("wokelang"); |
| 197 | +
|
| 198 | +pub fn main() !void { |
| 199 | + var interp = woke.woke_interpreter_new() orelse return error.InitFailed; |
| 200 | + defer woke.woke_interpreter_free(interp); |
| 201 | +
|
| 202 | + const result = woke.woke_exec(interp, |
| 203 | + \\to greet(name: String) -> String { |
| 204 | + \\ give back "Hello, " + name + "!"; |
| 205 | + \\} |
| 206 | + \\to main() { |
| 207 | + \\ hello greet("World"); |
| 208 | + \\} |
| 209 | + ); |
| 210 | +
|
| 211 | + if (result != .ok) return error.ExecutionFailed; |
| 212 | +} |
| 213 | +``` |
| 214 | + |
| 215 | +### C |
| 216 | +```c |
| 217 | +#include "wokelang.h" |
| 218 | + |
| 219 | +int main(void) { |
| 220 | + InterpreterHandle* interp = woke_interpreter_new(); |
| 221 | + if (!interp) return 1; |
| 222 | + |
| 223 | + Result result = woke_exec(interp, "remember x = 42;"); |
| 224 | + |
| 225 | + woke_interpreter_free(interp); |
| 226 | + return (result == Ok) ? 0 : 1; |
| 227 | +} |
| 228 | +``` |
| 229 | +
|
| 230 | +## Safety Guarantees |
| 231 | +
|
| 232 | +### Compile-Time (Idris2) |
| 233 | +- Non-null pointers |
| 234 | +- Correct struct alignment |
| 235 | +- Platform ABI compatibility |
| 236 | +- Type-safe foreign calls |
| 237 | +
|
| 238 | +### Runtime (Zig) |
| 239 | +- Null pointer checks |
| 240 | +- Memory safety |
| 241 | +- No undefined behavior |
| 242 | +
|
| 243 | +### Implementation (Rust) |
| 244 | +- Memory safety via ownership |
| 245 | +- No data races |
| 246 | +- Safe FFI boundary |
| 247 | +
|
| 248 | +## Migration from Old FFI |
| 249 | +
|
| 250 | +The old FFI (`zig/wokelang.zig`) is deprecated. Use the new structure: |
| 251 | +
|
| 252 | +**Old**: `zig/wokelang.zig` (wrapper around Rust) |
| 253 | +**New**: `ffi/zig/src/main.zig` (proper FFI layer with ABI definitions) |
| 254 | +
|
| 255 | +The new structure provides: |
| 256 | +- Formal ABI guarantees (Idris2 proofs) |
| 257 | +- Better separation of concerns |
| 258 | +- Cross-platform compatibility |
| 259 | +- Standard directory layout |
| 260 | +
|
| 261 | +## References |
| 262 | +
|
| 263 | +- [ABI/FFI Universal Standard](../../ffi-migration-guide.md) |
| 264 | +- [Idris2 FFI Documentation](https://idris2.readthedocs.io/en/latest/ffi/ffi.html) |
| 265 | +- [Zig FFI Guide](https://ziglang.org/documentation/master/#C) |
0 commit comments