diff --git a/examples/ffi-09-foreign-result-chain.c b/examples/ffi-09-foreign-result-chain.c new file mode 100644 index 0000000..5a0c62a --- /dev/null +++ b/examples/ffi-09-foreign-result-chain.c @@ -0,0 +1,22 @@ +#include "ffi-09-foreign-result-chain.h" +#include + +void *ffi_chain_make(int seed) { + int *p = (int *)malloc(sizeof(int)); + if (p) *p = seed; + return p; +} + +int ffi_chain_bump(void *h, int delta) { + int *p = (int *)h; + *p += delta; + return *p; +} + +int ffi_chain_peek(void *h) { + return *(int *)h; +} + +void ffi_chain_dispose(void *h) { + free(h); +} diff --git a/examples/ffi-09-foreign-result-chain.h b/examples/ffi-09-foreign-result-chain.h new file mode 100644 index 0000000..9bf283a --- /dev/null +++ b/examples/ffi-09-foreign-result-chain.h @@ -0,0 +1,10 @@ +// Trivial opaque-handle pattern — `make` produces a heap-allocated +// counter, `bump` returns the new value, `peek` reads without +// mutating, `dispose` frees. Mirrors the shape of real C handles +// (MTLBuffer*, AAssetManager*, file pointers, etc.) without pulling +// in any platform deps. + +void *ffi_chain_make (int seed); +int ffi_chain_bump (void *h, int delta); +int ffi_chain_peek (void *h); +void ffi_chain_dispose (void *h); diff --git a/examples/ffi-09-foreign-result-chain.sx b/examples/ffi-09-foreign-result-chain.sx new file mode 100644 index 0000000..f3c5c26 --- /dev/null +++ b/examples/ffi-09-foreign-result-chain.sx @@ -0,0 +1,79 @@ +// Phase 0 baseline (PLAN-FFI.md step 0.9): FFI result chains. The +// shapes that real sx code uses for opaque C handles (MTLBuffer*, +// AAssetManager*, file pointers, ...) — passing a C-returned +// pointer into another C call, stashing it in a struct field, +// pushing into a `List(*void)`, and iterating that list to feed each +// handle back through C. +// +// No new ABI shape — pointer-in, pointer-out. The lemma locked in: +// handle-shaped flows survive sx's struct-field assignment, List +// storage, and iteration-then-call cycles. + +#import "modules/std.sx"; + +#import c { + #include "ffi-09-foreign-result-chain.h"; + #source "ffi-09-foreign-result-chain.c"; +}; + +// Struct field hosts an FFI-returned handle. +Counter :: struct { + handle: *void = null; + label: string; +} + +main :: () -> s32 { + // ── 1. Chain: make → bump → peek ─────────────────────────────── + a := ffi_chain_make(100); + print("peek after make = {}\n", ffi_chain_peek(a)); + print("bump(+5) = {}\n", ffi_chain_bump(a, 5)); + print("bump(+3) = {}\n", ffi_chain_bump(a, 3)); + print("peek after bumps = {}\n", ffi_chain_peek(a)); + + // ── 2. Stash handle in a struct field, use through `.handle` ── + c : Counter = .{ handle = ffi_chain_make(50), label = "ctr-a" }; + print("ctr label = {}\n", c.label); + print("ctr peek = {}\n", ffi_chain_peek(c.handle)); + ffi_chain_bump(c.handle, 7); + print("ctr after bump = {}\n", ffi_chain_peek(c.handle)); + + // ── 3. Push handles into a List, iterate, feed back to C ────── + handles : List(*void) = .{}; + i : s32 = 0; + while i < 3 { + h := ffi_chain_make(i * 10); + handles.append(h); + i += 1; + } + + j : s64 = 0; + while j < handles.len { + h := handles.items[j]; + v := ffi_chain_peek(h); + print("list[{}] peek = {}\n", j, v); + j += 1; + } + + // Iterate again, bump each, observe the cumulative effect. + j = 0; + while j < handles.len { + ffi_chain_bump(handles.items[j], 1); + j += 1; + } + j = 0; + while j < handles.len { + print("list[{}] after bump= {}\n", j, ffi_chain_peek(handles.items[j])); + j += 1; + } + + // ── Cleanup ───────────────────────────────────────────────────── + ffi_chain_dispose(a); + ffi_chain_dispose(c.handle); + j = 0; + while j < handles.len { + ffi_chain_dispose(handles.items[j]); + j += 1; + } + + 0; +} diff --git a/tests/expected/ffi-09-foreign-result-chain.exit b/tests/expected/ffi-09-foreign-result-chain.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/expected/ffi-09-foreign-result-chain.exit @@ -0,0 +1 @@ +0 diff --git a/tests/expected/ffi-09-foreign-result-chain.txt b/tests/expected/ffi-09-foreign-result-chain.txt new file mode 100644 index 0000000..91bf857 --- /dev/null +++ b/tests/expected/ffi-09-foreign-result-chain.txt @@ -0,0 +1,13 @@ +peek after make = 100 +bump(+5) = 105 +bump(+3) = 108 +peek after bumps = 108 +ctr label = ctr-a +ctr peek = 50 +ctr after bump = 57 +list[0] peek = 0 +list[1] peek = 10 +list[2] peek = 20 +list[0] after bump= 1 +list[1] after bump= 11 +list[2] after bump= 21