c6c0a10788
Top-level fn names are now usable as values, fn-typed parameters can be called as `f(args)`. KISS slice of "closures + HOFs + TIR": no TIR, no heap, no ABI shift — that bundle stays in Iter 8 where closure-with-capture and lambdas land together. Codegen: - Type::Fn lowers to LLVM `ptr`; sig travels via a per-fn-body `ssa_fn_sigs` sidetable on `Emitter`. - Term::Var falls through to `resolve_top_level_fn` when the name is not a local; emits `@ail_<m>_<def>` and registers the sig. - Term::App splits: static callee (builtin / current-module / qualified) keeps the existing direct path; otherwise lower the callee, look up the sig, emit indirect `call <ret> (<param-tys>) %fn(args...)`. - emit_fn registers fn-typed params in the sidetable on entry. - If branches propagate a fn-pointer sig to their phi when both arms match. Typechecker: unchanged. It already accepted `synth(callee)` against Type::Fn; the only blocker was codegen rejecting non-Var callees. Tests: 48 green (was 47). New `examples/hof.ail.json` and e2e `higher_order_apply_inc` exercise `apply(inc, 41) == 42` end-to-end. DESIGN.md: "What is not (yet) supported" rewritten — closures-with- capture and lambdas remain pending, first-class fn-refs added as positive bullet. Smoke-test list extended with `hof.ail.json`. JOURNAL.md: Iter 7 entry with rationale, scope choice, architecture self-check, Iter 8 plan. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
78 lines
1.7 KiB
JSON
78 lines
1.7 KiB
JSON
{
|
|
"schema": "ailang/v0",
|
|
"name": "hof",
|
|
"imports": [],
|
|
"defs": [
|
|
{
|
|
"kind": "fn",
|
|
"name": "inc",
|
|
"type": {
|
|
"k": "fn",
|
|
"params": [{ "k": "con", "name": "Int" }],
|
|
"ret": { "k": "con", "name": "Int" },
|
|
"effects": []
|
|
},
|
|
"params": ["x"],
|
|
"doc": "increment by one",
|
|
"body": {
|
|
"t": "app",
|
|
"fn": { "t": "var", "name": "+" },
|
|
"args": [
|
|
{ "t": "var", "name": "x" },
|
|
{ "t": "lit", "lit": { "kind": "int", "value": 1 } }
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"kind": "fn",
|
|
"name": "apply",
|
|
"type": {
|
|
"k": "fn",
|
|
"params": [
|
|
{
|
|
"k": "fn",
|
|
"params": [{ "k": "con", "name": "Int" }],
|
|
"ret": { "k": "con", "name": "Int" },
|
|
"effects": []
|
|
},
|
|
{ "k": "con", "name": "Int" }
|
|
],
|
|
"ret": { "k": "con", "name": "Int" },
|
|
"effects": []
|
|
},
|
|
"params": ["f", "x"],
|
|
"doc": "apply a fn-of-Int to an Int",
|
|
"body": {
|
|
"t": "app",
|
|
"fn": { "t": "var", "name": "f" },
|
|
"args": [{ "t": "var", "name": "x" }]
|
|
}
|
|
},
|
|
{
|
|
"kind": "fn",
|
|
"name": "main",
|
|
"type": {
|
|
"k": "fn",
|
|
"params": [],
|
|
"ret": { "k": "con", "name": "Unit" },
|
|
"effects": ["IO"]
|
|
},
|
|
"params": [],
|
|
"body": {
|
|
"t": "do",
|
|
"op": "io/print_int",
|
|
"args": [
|
|
{
|
|
"t": "app",
|
|
"fn": { "t": "var", "name": "apply" },
|
|
"args": [
|
|
{ "t": "var", "name": "inc" },
|
|
{ "t": "lit", "lit": { "kind": "int", "value": 41 } }
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|