diff --git a/examples/176-build-block-convert.sx b/examples/176-build-block-convert.sx new file mode 100644 index 0000000..7d774bd --- /dev/null +++ b/examples/176-build-block-convert.sx @@ -0,0 +1,35 @@ +// FFI plan step 5.1 — `build_block_convert(args: []Type, $ret: Type) +// -> string` emits the per-shape source body for the generic +// `Into(Block) for Closure(..$args) -> $R` impl that lands in step +// 5.2. Per-call-shape monomorphisation of the impl body re-runs the +// builder with concrete types bound, so each closure shape gets its +// own dedicated `__invoke` trampoline + Block literal. +// +// This test exercises the builder directly (no `#insert`, no impl +// wiring) — three pack shapes through the same `void`-returning +// wrapper plus one non-void `s32`-returning wrapper to pin the +// `return typed_fn(...)` branch. The expected output captures the +// generated source verbatim so any formatting drift surfaces here +// rather than as a downstream compile error inside the eventual +// step-5.2 impl. + +#import "modules/std.sx"; +#import "modules/std/objc_block.sx"; + +preview_void :: (..$args) -> string { + return build_block_convert($args, void); +} + +preview_s32 :: (..$args) -> string { + return build_block_convert($args, s32); +} + +run_all :: () { + print("--- void / 0 args ---\n{}\n", preview_void()); + print("--- void / bool ---\n{}\n", preview_void(true)); + print("--- void / s64, string ---\n{}\n", preview_void(42, "hi")); + print("--- s32 / f64 ---\n{}\n", preview_s32(3.14)); +} +#run run_all(); + +main :: () { print("rt\n"); } diff --git a/tests/expected/176-build-block-convert.exit b/tests/expected/176-build-block-convert.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/expected/176-build-block-convert.exit @@ -0,0 +1 @@ +0 diff --git a/tests/expected/176-build-block-convert.txt b/tests/expected/176-build-block-convert.txt new file mode 100644 index 0000000..e22ba0f --- /dev/null +++ b/tests/expected/176-build-block-convert.txt @@ -0,0 +1,10 @@ +--- void / 0 args --- +__invoke :: (block_self: *Block) -> void callconv(.c) { typed_fn : (*void) -> void = xx block_self.sx_fn; typed_fn(block_self.sx_env); } return .{ isa = @_NSConcreteStackBlock, flags = 0, reserved = 0, invoke = xx @__invoke, descriptor = xx @__sx_block_descriptor, sx_env = self.env, sx_fn = self.fn_ptr, }; +--- void / bool --- +__invoke :: (block_self: *Block, arg0: bool) -> void callconv(.c) { typed_fn : (*void, bool) -> void = xx block_self.sx_fn; typed_fn(block_self.sx_env, arg0); } return .{ isa = @_NSConcreteStackBlock, flags = 0, reserved = 0, invoke = xx @__invoke, descriptor = xx @__sx_block_descriptor, sx_env = self.env, sx_fn = self.fn_ptr, }; +--- void / s64, string --- +__invoke :: (block_self: *Block, arg0: s64, arg1: string) -> void callconv(.c) { typed_fn : (*void, s64, string) -> void = xx block_self.sx_fn; typed_fn(block_self.sx_env, arg0, arg1); } return .{ isa = @_NSConcreteStackBlock, flags = 0, reserved = 0, invoke = xx @__invoke, descriptor = xx @__sx_block_descriptor, sx_env = self.env, sx_fn = self.fn_ptr, }; +--- s32 / f64 --- +__invoke :: (block_self: *Block, arg0: f64) -> s32 callconv(.c) { typed_fn : (*void, f64) -> s32 = xx block_self.sx_fn; return typed_fn(block_self.sx_env, arg0); } return .{ isa = @_NSConcreteStackBlock, flags = 0, reserved = 0, invoke = xx @__invoke, descriptor = xx @__sx_block_descriptor, sx_env = self.env, sx_fn = self.fn_ptr, }; +--- build done --- +rt