ffi M5.A.next.5.1.B: build_block_convert added to stdlib — make-green
`build_block_convert(args: []Type, $ret: Type) -> string` emits
the convert-body source for the generic `Into(Block) for
Closure(..$args) -> $R` impl (step 5.2):
1. A nested `__invoke :: (block_self: *Block, arg0: T0, ...) ->
R callconv(.c) { ... }` trampoline matching the per-shape
Apple Block ABI.
2. A `return Block.{ ... };` literal whose `invoke` slot points
at the nested trampoline via `xx @__invoke`.
Void-returning shapes emit `typed_fn(block_self.sx_env, args...)`;
non-void emits `return typed_fn(...)`. Per-position arg names
follow `arg0`, `arg1`, ... in declaration order; the typed-fn
cast reconstructs the closure's call signature so the trampoline
hands control back to `sx_fn` with the right argument layout.
`examples/176-build-block-convert.sx` flips green (216/216).
This commit is contained in:
@@ -107,3 +107,70 @@ impl Into(Block) for Closure(bool) -> void {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Comptime builder for the generic `Into(Block) for Closure(..$args)
|
||||
// -> $R` impl body. Receives the closure's per-position pack types
|
||||
// (`args`, a comptime `[]Type`) and the closure's return type
|
||||
// (`$ret`), emits source that:
|
||||
//
|
||||
// 1. Declares a nested `__invoke` `callconv(.c)` trampoline whose
|
||||
// signature matches the per-shape Apple Block ABI: first arg is
|
||||
// `block_self: *Block`, then the pack types verbatim. The body
|
||||
// reconstructs a typed fn-pointer from `block_self.sx_fn`,
|
||||
// prepends `block_self.sx_env`, and tail-calls the sx closure.
|
||||
// 2. Returns a stack Block literal whose `invoke` slot points at
|
||||
// the nested trampoline via `xx @__invoke`.
|
||||
//
|
||||
// The host impl wraps the emitted source via `#insert
|
||||
// build_block_convert($args, $R);`. Per-call-shape monomorphisation
|
||||
// of the impl body re-runs this builder with the concrete types
|
||||
// bound, so each closure shape gets its own dedicated trampoline.
|
||||
//
|
||||
// Void return type emits `typed_fn(...)`; non-void emits
|
||||
// `return typed_fn(...)`.
|
||||
build_block_convert :: (args: []Type, $ret: Type) -> string {
|
||||
ret_name := type_name(ret);
|
||||
code := "__invoke :: (block_self: *Block";
|
||||
i : s64 = 0;
|
||||
while i < args.len {
|
||||
code = concat(code, ", arg");
|
||||
code = concat(code, int_to_string(i));
|
||||
code = concat(code, ": ");
|
||||
code = concat(code, type_name(args[i]));
|
||||
i = i + 1;
|
||||
}
|
||||
code = concat(code, ") -> ");
|
||||
code = concat(code, ret_name);
|
||||
code = concat(code, " callconv(.c) { typed_fn : (*void");
|
||||
i = 0;
|
||||
while i < args.len {
|
||||
code = concat(code, ", ");
|
||||
code = concat(code, type_name(args[i]));
|
||||
i = i + 1;
|
||||
}
|
||||
code = concat(code, ") -> ");
|
||||
code = concat(code, ret_name);
|
||||
code = concat(code, " = xx block_self.sx_fn; ");
|
||||
if ret_name == "void" {
|
||||
code = concat(code, "typed_fn(block_self.sx_env");
|
||||
} else {
|
||||
code = concat(code, "return typed_fn(block_self.sx_env");
|
||||
}
|
||||
i = 0;
|
||||
while i < args.len {
|
||||
code = concat(code, ", arg");
|
||||
code = concat(code, int_to_string(i));
|
||||
i = i + 1;
|
||||
}
|
||||
code = concat(code, "); } ");
|
||||
code = concat(code, "return .{ ");
|
||||
code = concat(code, "isa = @_NSConcreteStackBlock, ");
|
||||
code = concat(code, "flags = 0, ");
|
||||
code = concat(code, "reserved = 0, ");
|
||||
code = concat(code, "invoke = xx @__invoke, ");
|
||||
code = concat(code, "descriptor = xx @__sx_block_descriptor, ");
|
||||
code = concat(code, "sx_env = self.env, ");
|
||||
code = concat(code, "sx_fn = self.fn_ptr, ");
|
||||
code = concat(code, "};");
|
||||
return code;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user