diff --git a/lang/el-compiler/src/codegen.el b/lang/el-compiler/src/codegen.el index bd90b266..eaaa4def 100644 --- a/lang/el-compiler/src/codegen.el +++ b/lang/el-compiler/src/codegen.el @@ -3215,44 +3215,15 @@ fn cg_entry_seam(stmt: Map, fn_name: String) -> Void { // cg_exit_target / cg_exit_construct — the first construct on this fn that // injects at exit, or "" if none. -fn cg_wrap_target(stmt: Map) -> String { - let wdl = stmt["decorators"] - let n_wdl: Int = native_list_len(wdl) - let wi = 0 - let found: String = "" - while wi < n_wdl { - if str_eq(found, "") { - let wd = native_list_get(wdl, wi) - let wdn: String = wd["name"] - let wt: String = decorator_wrap(wdn) - if !str_eq(wt, "") { let found = wt } - } - let wi = wi + 1 - } - found -} -fn cg_wrap_construct(stmt: Map) -> String { - let wdl = stmt["decorators"] - let n_wdl: Int = native_list_len(wdl) - let wi = 0 - let found: String = "" - while wi < n_wdl { - if str_eq(found, "") { - let wd = native_list_get(wdl, wi) - let wdn: String = wd["name"] - let wt: String = decorator_wrap(wdn) - if !str_eq(wt, "") { let found = wdn } - } - let wi = wi + 1 - } - found -} // params_to_env_fields / params_to_env_init / params_to_env_args — the captured // environment. This IS the closure: a struct of captured values, a function // pointer that takes it, and the pair handed to the wrap target. fn params_to_env_fields(params: [Any]) -> String { + // A zero-param fn would emit `struct __env_f { };` -- an empty struct is a + // GNU extension, not C99, and an empty initialiser is C23. + if native_list_len(params) == 0 { return " char __e0;" } let out: String = "" let n: Int = native_list_len(params) let i = 0 @@ -3266,6 +3237,7 @@ fn params_to_env_fields(params: [Any]) -> String { } fn params_to_env_init(params: [Any]) -> String { + if native_list_len(params) == 0 { return "0" } let out: String = "" let n: Int = native_list_len(params) let i = 0 @@ -3296,19 +3268,6 @@ fn params_to_env_args(params: [Any]) -> String { // params_to_call_args — "a, b, c" from the param list, for the wrapper's call // into the body helper. -fn params_to_call_args(params: [Any]) -> String { - let out: String = "" - let n: Int = native_list_len(params) - let i = 0 - while i < n { - let p = native_list_get(params, i) - let pn: String = p["name"] - if i > 0 { let out = out + ", " } - let out = out + pn - let i = i + 1 - } - out -} fn cg_fn(stmt: Map) -> Void { let fn_name: String = stmt["name"] @@ -3358,11 +3317,7 @@ fn cg_fn(stmt: Map) -> Void { // silently miss every early return — which is precisely the class of // failure this seam exists to remove. Fns with no exit construct emit // exactly as before, byte for byte. - let wrap_target: String = cg_wrap_target(stmt) - let wrap_construct: String = cg_wrap_construct(stmt) - let has_wrap: Bool = !str_eq(wrap_target, "") - let has_exit: Bool = true - if has_exit { + if true { emit_line("static el_val_t __el_body_" + fn_name + "(" + params_c + ") {") } else { emit_line("el_val_t " + fn_name + "(" + params_c + ") {") @@ -3393,27 +3348,21 @@ fn cg_fn(stmt: Map) -> Void { // The wrapper: guards, entry injection, the body call, then the exit // injection, which receives the result so it can observe what the fn // actually returned. - if has_wrap { - // Codegen defines the wrap calling convention, so codegen declares it. - // El has ONE type -- el_val_t = int64_t -- so El's own `extern fn` cannot - // describe a callable, and asking it to produces an int/pointer - // mismatch. The convention is not El-expressible; it is emitted. - emit_line("extern el_val_t " + wrap_target + "(el_val_t, el_val_t, el_val_t(*)(void*), void*);") + if true { + // EVERY fn gets an env struct and a thunk. Codegen cannot know which fns + // a wrap construct will be bound to after the binary exists, and the + // wrapper unconditionally calls through el_seam_wrap. emit_line("struct __env_" + fn_name + " { " + params_to_env_fields(params) + " };") emit_line("static el_val_t __thunk_" + fn_name + "(void* __v) {") emit_line(" struct __env_" + fn_name + "* __e = (struct __env_" + fn_name + "*)__v; (void)__e;") emit_line(" return __el_body_" + fn_name + "(" + params_to_env_args(params) + ");") emit_line("}") } - if has_exit { + if true { emit_line("el_val_t " + fn_name + "(" + params_c + ") {") cg_entry_seam(stmt, fn_name) - if has_wrap { - emit_line(" struct __env_" + fn_name + " __env = { " + params_to_env_init(params) + " };") - emit_line(" el_val_t __r = " + wrap_target + "(EL_STR(" + c_str_lit(fn_name) + "), EL_STR(" + c_str_lit(wrap_construct) + "), __thunk_" + fn_name + ", &__env);") - } else { - emit_line(" el_val_t __r = __el_body_" + fn_name + "(" + params_to_call_args(params) + ");") - } + emit_line(" struct __env_" + fn_name + " __env = { " + params_to_env_init(params) + " };") + emit_line(" el_val_t __r = el_seam_wrap(EL_STR(" + c_str_lit(fn_name) + "), __thunk_" + fn_name + ", &__env);") emit_line(" __r = el_seam_run(EL_STR(" + c_str_lit(fn_name) + "), 1, __r);") emit_line(" return __r;") emit_line("}") @@ -4291,13 +4240,7 @@ fn program_has_routes(recs: [Map]) -> Bool { // only decide whether to repeat — no timeout, no rollback-and-retry, no // parallel, no memoize-on-arguments. It would also have crippled the JS backend, // which has closures natively, for a limit in the C one. -fn declare_wrap(name: String, wraps: String) -> Void { - state_set("__dec_wrap_" + name, wraps) -} -fn decorator_wrap(name: String) -> String { - state_get("__dec_wrap_" + name) -} // A PROHIBITION is the other half of a boundary: not what runs when something // crosses, but what may not cross at all. @@ -4340,8 +4283,6 @@ fn prohibiting_constructs() -> String { fn scan_declared_decorators(tokens: [Any]) -> Void { declare_prohibition("manager", "dharma_emit,dharma_field") let total: Int = native_list_len(tokens) / 2 - let has_pending_w: Bool = false - let pending_wrap: String = "" let has_pending_p: Bool = false let pending_prohibit: String = "" let pos: Int = 0 @@ -4382,10 +4323,6 @@ fn scan_declared_decorators(tokens: [Any]) -> Void { if str_eq(dname, "decorator") { if native_list_len(args) >= 2 { let dkind: String = native_list_get(args, 0) - if str_eq(dkind, "wraps_body") { - let has_pending_w = true - let pending_wrap = native_list_get(args, 1) - } if str_eq(dkind, "prohibits_outside") { let has_pending_p = true let pending_prohibit = native_list_get(args, 1) @@ -4396,10 +4333,6 @@ fn scan_declared_decorators(tokens: [Any]) -> Void { } else { if str_eq(k, "Fn") { let fname: String = tok_value(tokens, pos + 1) - if has_pending_w { - declare_wrap(fname, pending_wrap) - let has_pending_w = false - } if has_pending_p { declare_prohibition(fname, pending_prohibit) let has_pending_p = false