From 4534e03a40c70dcac56bcdc274c9116a7f5d4791 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 26 Jun 2026 22:04:05 +0000 Subject: [PATCH] P1: fix Zig FFI to compile and match the Idris2 ABI The Zig FFI reference implementation (src/interface/ffi/src/main.zig) failed to compile under Zig 0.14.0. Two fixes, both confined to the FFI layer; the Idris2 ABI remains the source of truth. 1. Syntax error (the reported `expected statement, found ';'`): the `if (!h.initialized) { ... }` block at the end of anvomidaviser_get_string was terminated with a stray `;`. An `if` used as a statement takes no trailing semicolon, so the `};` following the block body was parsed as an empty statement. Removed the spurious semicolon. 2. `Handle` was declared as a Zig `opaque {}` type but given fields (`allocator`, `initialized`) and instantiated with `handle.* = .{...}` plus field access (`h.allocator`, `h.initialized`). Zig `opaque` types are unsized and cannot hold or expose fields, so this could never compile once the parser advanced past the syntax error. Changed `Handle` to a concrete `struct`, matching the house idiom in alloyiser's exemplar (its `Model` struct). It is still only ever handed to C as a pointer, so it stays opaque across the C ABI. No exported C symbol names changed and no Result codes changed: every `C:anvomidaviser_*` symbol in Foreign.idr still has a matching `export fn`, and the Result enum integer values (ok=0, error=1, invalid_param=2, out_of_memory=3, null_pointer=4, rule_violation=5) match Types.idr's resultToInt exactly. Verification: - zig test src/main.zig -lc -> all 3 tests pass, 0 errors/warnings - idris2 --build anvomidaviser-abi.ipkg -> exit 0 Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_019xMKB3T4Vo5FYC7Czx3JSH --- src/interface/ffi/src/main.zig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/interface/ffi/src/main.zig b/src/interface/ffi/src/main.zig index 950c5e3..901d307 100644 --- a/src/interface/ffi/src/main.zig +++ b/src/interface/ffi/src/main.zig @@ -38,12 +38,12 @@ pub const Result = enum(c_int) { rule_violation = 5, }; -/// Library handle (opaque to prevent direct access) -pub const Handle = opaque { - // Internal state hidden from C +/// Library handle. Opaque to C (passed as a pointer); fields are private to +/// this module. A concrete struct (not Zig `opaque`) so internal state can be +/// stored and accessed here. +pub const Handle = struct { allocator: std.mem.Allocator, initialized: bool, - // Add your fields here }; //============================================================================== @@ -285,7 +285,7 @@ export fn anvomidaviser_get_string(handle: ?*Handle) ?[*:0]const u8 { if (!h.initialized) { setError("Handle not initialized"); return null; - }; + } const result = h.allocator.dupeZ(u8, "Anvomidaviser score pending") catch { setError("Failed to allocate string");