Iter 9a/9b: dogfood (list_map) + ail run

Iter 9a — dogfood. examples/list_map.ail.json exercises everything
Iter 1-8 shipped in one program: ADTs (IntList = Nil | Cons Int IntList),
recursive fns over the ADT (map_int, print_list), pattern matching with
nested Var fields, a closure (`\\x. x * 2`, no captures), fn-typed
parameters, IO effects propagating through recursion, and `let`-
sequencing of an effectful sub-expression inside a match arm.

Result: nothing broke. The full pipeline (typecheck → IR emit →
clang → run) produces "2\\n4\\n6\\n". The language is now sufficient
for "small but real" programs.

Iter 9b — `ail run`. Convenience subcommand that builds into a
tempdir and executes, propagating the binary's exit code. Equivalent
to `ail build && ./bin` in one step. Build logic factored out of
`Cmd::Build` into a shared `build_to` helper used by both Build and
Run.

Tests: 50 green (was 49). New e2e `list_map_doubles_then_prints`.
No test for `ail run` itself — the existing build_and_run helper in
e2e.rs already exercises the same build+exec sequence path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-07 13:09:18 +02:00
parent 91b9bf0581
commit 849eca4fcf
3 changed files with 297 additions and 42 deletions
+207
View File
@@ -0,0 +1,207 @@
{
"schema": "ailang/v0",
"name": "list_map",
"imports": [],
"defs": [
{
"kind": "type",
"name": "IntList",
"doc": "Singly-linked list of Int, boxed.",
"ctors": [
{ "name": "Nil", "fields": [] },
{
"name": "Cons",
"fields": [
{ "k": "con", "name": "Int" },
{ "k": "con", "name": "IntList" }
]
}
]
},
{
"kind": "fn",
"name": "map_int",
"type": {
"k": "fn",
"params": [
{
"k": "fn",
"params": [{ "k": "con", "name": "Int" }],
"ret": { "k": "con", "name": "Int" },
"effects": []
},
{ "k": "con", "name": "IntList" }
],
"ret": { "k": "con", "name": "IntList" },
"effects": []
},
"params": ["f", "xs"],
"doc": "Apply f to every element. Recursive on the tail.",
"body": {
"t": "match",
"scrutinee": { "t": "var", "name": "xs" },
"arms": [
{
"pat": { "p": "ctor", "ctor": "Nil", "fields": [] },
"body": {
"t": "ctor",
"type": "IntList",
"ctor": "Nil",
"args": []
}
},
{
"pat": {
"p": "ctor",
"ctor": "Cons",
"fields": [
{ "p": "var", "name": "h" },
{ "p": "var", "name": "t" }
]
},
"body": {
"t": "ctor",
"type": "IntList",
"ctor": "Cons",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "f" },
"args": [{ "t": "var", "name": "h" }]
},
{
"t": "app",
"fn": { "t": "var", "name": "map_int" },
"args": [
{ "t": "var", "name": "f" },
{ "t": "var", "name": "t" }
]
}
]
}
}
]
}
},
{
"kind": "fn",
"name": "print_list",
"type": {
"k": "fn",
"params": [{ "k": "con", "name": "IntList" }],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": ["xs"],
"doc": "Print each Int on its own line.",
"body": {
"t": "match",
"scrutinee": { "t": "var", "name": "xs" },
"arms": [
{
"pat": { "p": "ctor", "ctor": "Nil", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "unit" } }
},
{
"pat": {
"p": "ctor",
"ctor": "Cons",
"fields": [
{ "p": "var", "name": "h" },
{ "p": "var", "name": "t" }
]
},
"body": {
"t": "let",
"name": "_print_h",
"value": {
"t": "do",
"op": "io/print_int",
"args": [{ "t": "var", "name": "h" }]
},
"body": {
"t": "app",
"fn": { "t": "var", "name": "print_list" },
"args": [{ "t": "var", "name": "t" }]
}
}
}
]
}
},
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"doc": "Build [1,2,3], double each, print result.",
"body": {
"t": "let",
"name": "xs",
"value": {
"t": "ctor",
"type": "IntList",
"ctor": "Cons",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 1 } },
{
"t": "ctor",
"type": "IntList",
"ctor": "Cons",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 2 } },
{
"t": "ctor",
"type": "IntList",
"ctor": "Cons",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 3 } },
{
"t": "ctor",
"type": "IntList",
"ctor": "Nil",
"args": []
}
]
}
]
}
]
},
"body": {
"t": "app",
"fn": { "t": "var", "name": "print_list" },
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "map_int" },
"args": [
{
"t": "lam",
"params": ["x"],
"paramTypes": [{ "k": "con", "name": "Int" }],
"retType": { "k": "con", "name": "Int" },
"effects": [],
"body": {
"t": "app",
"fn": { "t": "var", "name": "*" },
"args": [
{ "t": "var", "name": "x" },
{ "t": "lit", "lit": { "kind": "int", "value": 2 } }
]
}
},
{ "t": "var", "name": "xs" }
]
}
]
}
}
}
]
}