feat(cma): revive cross-model harness corpus to current language (refs #68)
The cma authoring-form harness corpus had gone dead against the language as it evolved since May. The plan modelled it as merely schema-dead (missing param_modes/ret_mode); it was also drift-dead in the example BODIES. Fixed in place, with `ail check` + both test suites as the oracle: - Schema: param_modes/ret_mode completed on every fn type; existing borrow annotations preserved (data_with_match's borrow over List). - Symbol drift: `<`/`==` -> `lt`/`eq` (operator-routing); the removed `io/print_int` op -> print_str(int_to_str n) followed by a newline print, preserving the trailing newline the references' expected_stdout needs. - Ownership/ADT restructures: data_simple's reuse-as now wraps the source in a match arm (ctor must be statically visible); data_with_match's count_via_letrec + local go switched borrow->own (consume-while-borrowed under the tightened ownership analysis; head_or_zero still exercises borrow over the boxed List). - param_modes_all rewritten to own (Int) + borrow over a boxed ADT -- (borrow Int) is now a borrow-over-value error. - Two new author-facing examples (loop_sum: Loop/Recur; new_rawbuf: New) cover the Term variants that landed since May. - spec_completeness.rs: drop the deleted ParamMode::Implicit; cover Loop/Recur/New; allowlist the non-authorable Term::Intrinsic out. - spec.md section 4 rewritten to own/borrow (mandatory, no implicit) with the borrow-over-value rule; rendered/ regenerated. - mock_full_run fixture's t3 turn-2 program migrated so the harness score assertions hold; usage fields untouched. Both render/ and harness/ cargo test suites green in mock mode; no live IONOS call. Run the harness budget/reference tests with AIL_BIN pointing at target/debug/ail (ail is not on PATH in the test env).
This commit is contained in:
+1
-1
@@ -30,7 +30,7 @@
|
||||
}
|
||||
},
|
||||
"2": {
|
||||
"content": "{\n \"schema\": \"ailang/v0\",\n \"name\": \"t3_main_prints\",\n \"imports\": [],\n \"defs\": [\n {\n \"kind\": \"fn\",\n \"name\": \"main\",\n \"type\": {\n \"k\": \"fn\",\n \"params\": [],\n \"ret\": { \"k\": \"con\", \"name\": \"Unit\" },\n \"effects\": [\"IO\"]\n },\n \"params\": [],\n \"body\": {\n \"t\": \"seq\",\n \"lhs\": {\n \"t\": \"do\",\n \"op\": \"io/print_int\",\n \"args\": [{ \"t\": \"lit\", \"lit\": { \"kind\": \"int\", \"value\": 42 } }]\n },\n \"rhs\": {\n \"t\": \"do\",\n \"op\": \"io/print_int\",\n \"args\": [{ \"t\": \"lit\", \"lit\": { \"kind\": \"int\", \"value\": 1337 } }]\n }\n }\n }\n ]\n}\n",
|
||||
"content": "{\n \"schema\": \"ailang/v0\",\n \"name\": \"t3_main_prints\",\n \"imports\": [],\n \"defs\": [\n {\n \"kind\": \"fn\",\n \"name\": \"main\",\n \"type\": {\n \"k\": \"fn\",\n \"params\": [],\n \"param_modes\": [],\n \"ret\": {\n \"k\": \"con\",\n \"name\": \"Unit\"\n },\n \"ret_mode\": \"own\",\n \"effects\": [\n \"IO\"\n ]\n },\n \"params\": [],\n \"body\": {\n \"t\": \"seq\",\n \"lhs\": {\n \"t\": \"seq\",\n \"lhs\": {\n \"t\": \"do\",\n \"op\": \"io/print_str\",\n \"args\": [\n {\n \"t\": \"app\",\n \"fn\": {\n \"t\": \"var\",\n \"name\": \"int_to_str\"\n },\n \"args\": [\n {\n \"t\": \"lit\",\n \"lit\": {\n \"kind\": \"int\",\n \"value\": 42\n }\n }\n ]\n }\n ]\n },\n \"rhs\": {\n \"t\": \"do\",\n \"op\": \"io/print_str\",\n \"args\": [\n {\n \"t\": \"lit\",\n \"lit\": {\n \"kind\": \"str\",\n \"value\": \"\\n\"\n }\n }\n ]\n }\n },\n \"rhs\": {\n \"t\": \"seq\",\n \"lhs\": {\n \"t\": \"do\",\n \"op\": \"io/print_str\",\n \"args\": [\n {\n \"t\": \"app\",\n \"fn\": {\n \"t\": \"var\",\n \"name\": \"int_to_str\"\n },\n \"args\": [\n {\n \"t\": \"lit\",\n \"lit\": {\n \"kind\": \"int\",\n \"value\": 1337\n }\n }\n ]\n }\n ]\n },\n \"rhs\": {\n \"t\": \"do\",\n \"op\": \"io/print_str\",\n \"args\": [\n {\n \"t\": \"lit\",\n \"lit\": {\n \"kind\": \"str\",\n \"value\": \"\\n\"\n }\n }\n ]\n }\n }\n }\n }\n ]\n}\n",
|
||||
"usage": {
|
||||
"prompt_tokens": 1200,
|
||||
"completion_tokens": 200,
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"param_modes": [],
|
||||
"ret": { "k": "con", "name": "Bool" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": [],
|
||||
@@ -23,7 +25,9 @@
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"param_modes": [],
|
||||
"ret": { "k": "con", "name": "Str" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": [],
|
||||
@@ -36,7 +40,9 @@
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"param_modes": [],
|
||||
"ret": { "k": "con", "name": "Unit" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": [],
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "var", "name": "a" } ],
|
||||
"param_modes": ["own"],
|
||||
"ret": { "k": "con", "name": "Str" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +1 @@
|
||||
{
|
||||
"schema": "ailang/v0",
|
||||
"name": "data_simple",
|
||||
"imports": [],
|
||||
"defs": [
|
||||
{
|
||||
"kind": "type",
|
||||
"name": "Box",
|
||||
"vars": ["a"],
|
||||
"doc": "A unary box around a polymorphic value.",
|
||||
"ctors": [
|
||||
{
|
||||
"name": "MkBox",
|
||||
"fields": [ { "k": "var", "name": "a" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "fn",
|
||||
"name": "wrap_one",
|
||||
"doc": "Construct a Box Int via MkBox. The body uses (reuse-as src body) — a hint that the freshly-allocated Box should reuse the source's memory slot under --alloc=rc. Exercises TermCtor, ReuseAs, and Type::Var inside a ctor field position.",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [
|
||||
{ "k": "con", "name": "Box", "args": [ { "k": "con", "name": "Int" } ] }
|
||||
],
|
||||
"param_modes": ["own"],
|
||||
"ret": { "k": "con", "name": "Box", "args": [ { "k": "con", "name": "Int" } ] },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["src"],
|
||||
"body": {
|
||||
"t": "reuse-as",
|
||||
"source": { "t": "var", "name": "src" },
|
||||
"body": {
|
||||
"t": "ctor",
|
||||
"type": "Box",
|
||||
"ctor": "MkBox",
|
||||
"args": [ { "t": "lit", "lit": { "kind": "int", "value": 1 } } ]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
{"defs":[{"ctors":[{"fields":[{"k":"var","name":"a"}],"name":"MkBox"}],"kind":"type","name":"Box","vars":["a"]},{"body":{"arms":[{"body":{"body":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"ctor":"MkBox","t":"ctor","type":"Box"},"source":{"name":"src","t":"var"},"t":"reuse-as"},"pat":{"ctor":"MkBox","fields":[{"name":"v","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"src","t":"var"},"t":"match"},"kind":"fn","name":"wrap_one","params":["src"],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"args":[{"k":"con","name":"Int"}],"k":"con","name":"Box"}],"ret":{"args":[{"k":"con","name":"Int"}],"k":"con","name":"Box"},"ret_mode":"own"}}],"imports":[],"name":"data_simple","schema":"ailang/v0"}
|
||||
|
||||
+145
-33
@@ -6,14 +6,23 @@
|
||||
{
|
||||
"kind": "type",
|
||||
"name": "List",
|
||||
"doc": "Monomorphic singly-linked Int list — boxed, recursive.",
|
||||
"doc": "Monomorphic singly-linked Int list \u2014 boxed, recursive.",
|
||||
"ctors": [
|
||||
{ "name": "Nil", "fields": [] },
|
||||
{
|
||||
"name": "Nil",
|
||||
"fields": []
|
||||
},
|
||||
{
|
||||
"name": "Cons",
|
||||
"fields": [
|
||||
{ "k": "con", "name": "Int" },
|
||||
{ "k": "con", "name": "List" }
|
||||
{
|
||||
"k": "con",
|
||||
"name": "Int"
|
||||
},
|
||||
{
|
||||
"k": "con",
|
||||
"name": "List"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -24,30 +33,64 @@
|
||||
"doc": "Return the head of xs, or 0 if empty. Exercises TermMatch with two arms, PatternCtor (both nullary Nil and binary Cons), and PatternWild on the tail field.",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "List" } ],
|
||||
"param_modes": ["borrow"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"params": [
|
||||
{
|
||||
"k": "con",
|
||||
"name": "List"
|
||||
}
|
||||
],
|
||||
"param_modes": [
|
||||
"borrow"
|
||||
],
|
||||
"ret": {
|
||||
"k": "con",
|
||||
"name": "Int"
|
||||
},
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["xs"],
|
||||
"params": [
|
||||
"xs"
|
||||
],
|
||||
"body": {
|
||||
"t": "match",
|
||||
"scrutinee": { "t": "var", "name": "xs" },
|
||||
"scrutinee": {
|
||||
"t": "var",
|
||||
"name": "xs"
|
||||
},
|
||||
"arms": [
|
||||
{
|
||||
"pat": { "p": "ctor", "ctor": "Nil", "fields": [] },
|
||||
"body": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
|
||||
"pat": {
|
||||
"p": "ctor",
|
||||
"ctor": "Nil",
|
||||
"fields": []
|
||||
},
|
||||
"body": {
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"pat": {
|
||||
"p": "ctor",
|
||||
"ctor": "Cons",
|
||||
"fields": [
|
||||
{ "p": "var", "name": "h" },
|
||||
{ "p": "wild" }
|
||||
{
|
||||
"p": "var",
|
||||
"name": "h"
|
||||
},
|
||||
{
|
||||
"p": "wild"
|
||||
}
|
||||
]
|
||||
},
|
||||
"body": { "t": "var", "name": "h" }
|
||||
"body": {
|
||||
"t": "var",
|
||||
"name": "h"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -58,49 +101,110 @@
|
||||
"doc": "Walk xs counting nodes using a local recursive let. Exercises TermLetRec and TermVar; the recursive `go` is bound locally.",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "List" } ],
|
||||
"param_modes": ["borrow"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"params": [
|
||||
{
|
||||
"k": "con",
|
||||
"name": "List"
|
||||
}
|
||||
],
|
||||
"param_modes": [
|
||||
"own"
|
||||
],
|
||||
"ret": {
|
||||
"k": "con",
|
||||
"name": "Int"
|
||||
},
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["xs"],
|
||||
"params": [
|
||||
"xs"
|
||||
],
|
||||
"body": {
|
||||
"t": "letrec",
|
||||
"name": "go",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "List" } ],
|
||||
"param_modes": ["borrow"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"params": [
|
||||
{
|
||||
"k": "con",
|
||||
"name": "List"
|
||||
}
|
||||
],
|
||||
"param_modes": [
|
||||
"own"
|
||||
],
|
||||
"ret": {
|
||||
"k": "con",
|
||||
"name": "Int"
|
||||
},
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["ys"],
|
||||
"params": [
|
||||
"ys"
|
||||
],
|
||||
"body": {
|
||||
"t": "match",
|
||||
"scrutinee": { "t": "var", "name": "ys" },
|
||||
"scrutinee": {
|
||||
"t": "var",
|
||||
"name": "ys"
|
||||
},
|
||||
"arms": [
|
||||
{
|
||||
"pat": { "p": "ctor", "ctor": "Nil", "fields": [] },
|
||||
"body": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
|
||||
"pat": {
|
||||
"p": "ctor",
|
||||
"ctor": "Nil",
|
||||
"fields": []
|
||||
},
|
||||
"body": {
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"pat": {
|
||||
"p": "ctor",
|
||||
"ctor": "Cons",
|
||||
"fields": [
|
||||
{ "p": "wild" },
|
||||
{ "p": "var", "name": "t" }
|
||||
{
|
||||
"p": "wild"
|
||||
},
|
||||
{
|
||||
"p": "var",
|
||||
"name": "t"
|
||||
}
|
||||
]
|
||||
},
|
||||
"body": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "+" },
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "+"
|
||||
},
|
||||
"args": [
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 1 } },
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "go" },
|
||||
"args": [ { "t": "var", "name": "t" } ]
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "go"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "var",
|
||||
"name": "t"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -109,8 +213,16 @@
|
||||
},
|
||||
"in": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "go" },
|
||||
"args": [ { "t": "var", "name": "xs" } ]
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "go"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "var",
|
||||
"name": "xs"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
{ "k": "con", "name": "Int" },
|
||||
{ "k": "con", "name": "Int" }
|
||||
],
|
||||
"param_modes": ["own", "own"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["x", "y"],
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"param_modes": [],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": [],
|
||||
|
||||
+79
-6
@@ -10,21 +10,94 @@
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"ret": { "k": "con", "name": "Unit" },
|
||||
"effects": ["IO"]
|
||||
"param_modes": [],
|
||||
"ret": {
|
||||
"k": "con",
|
||||
"name": "Unit"
|
||||
},
|
||||
"ret_mode": "own",
|
||||
"effects": [
|
||||
"IO"
|
||||
]
|
||||
},
|
||||
"params": [],
|
||||
"body": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_int",
|
||||
"args": [ { "t": "lit", "lit": { "kind": "int", "value": 1 } } ]
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "app",
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "int_to_str"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"rhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_int",
|
||||
"args": [ { "t": "lit", "lit": { "kind": "int", "value": 2 } } ]
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "str",
|
||||
"value": "\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"rhs": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "app",
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "int_to_str"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"rhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "str",
|
||||
"value": "\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,12 +10,16 @@
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "Int" } ],
|
||||
"param_modes": ["own"],
|
||||
"ret": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "Int" } ],
|
||||
"param_modes": ["own"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["x"],
|
||||
|
||||
+2
@@ -13,7 +13,9 @@
|
||||
"body": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "var", "name": "a" } ],
|
||||
"param_modes": ["own"],
|
||||
"ret": { "k": "var", "name": "a" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "var", "name": "a" } ],
|
||||
"param_modes": ["own"],
|
||||
"ret": { "k": "con", "name": "Str" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"defs":[{"body":{"binders":[{"init":{"lit":{"kind":"int","value":0},"t":"lit"},"name":"acc","type":{"k":"con","name":"Int"}},{"init":{"lit":{"kind":"int","value":1},"t":"lit"},"name":"i","type":{"k":"con","name":"Int"}}],"body":{"cond":{"args":[{"name":"i","t":"var"},{"name":"n","t":"var"}],"fn":{"name":"gt","t":"var"},"t":"app"},"else":{"args":[{"args":[{"name":"acc","t":"var"},{"name":"i","t":"var"}],"fn":{"name":"+","t":"var"},"t":"app"},{"args":[{"name":"i","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"+","t":"var"},"t":"app"}],"t":"recur"},"t":"if","then":{"name":"acc","t":"var"}},"t":"loop"},"kind":"fn","name":"sum_to","params":["n"],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"},"ret_mode":"own"}}],"imports":[],"name":"loop_sum","schema":"ailang/v0"}
|
||||
+6
-2
@@ -10,7 +10,9 @@
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "Int" } ],
|
||||
"param_modes": ["own"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["n"],
|
||||
@@ -36,7 +38,9 @@
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "Int" } ],
|
||||
"param_modes": ["own"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["n"],
|
||||
@@ -44,7 +48,7 @@
|
||||
"t": "if",
|
||||
"cond": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "<" },
|
||||
"fn": { "t": "var", "name": "lt" },
|
||||
"args": [
|
||||
{ "t": "var", "name": "n" },
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 0 } }
|
||||
@@ -55,7 +59,7 @@
|
||||
"t": "if",
|
||||
"cond": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "==" },
|
||||
"fn": { "t": "var", "name": "eq" },
|
||||
"args": [
|
||||
{ "t": "var", "name": "n" },
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 0 } }
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"defs":[{"body":{"body":{"args":[{"args":[{"name":"b","t":"var"}],"fn":{"name":"RawBuf.size","t":"var"},"t":"app"}],"fn":{"name":"print","t":"var"},"t":"app"},"name":"b","t":"let","value":{"args":[{"kind":"type","value":{"k":"con","name":"Int"}},{"kind":"value","value":{"lit":{"kind":"int","value":3},"t":"lit"}}],"t":"new","type":"RawBuf"}},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","param_modes":[],"params":[],"ret":{"k":"con","name":"Unit"},"ret_mode":"own"}}],"imports":[],"name":"new_rawbuf","schema":"ailang/v0"}
|
||||
+1
-48
@@ -1,48 +1 @@
|
||||
{
|
||||
"schema": "ailang/v0",
|
||||
"name": "param_modes_all",
|
||||
"imports": [],
|
||||
"defs": [
|
||||
{
|
||||
"kind": "fn",
|
||||
"name": "f_implicit",
|
||||
"doc": "Implicit mode is the legacy default — `param_modes` is omitted from canonical JSON when every entry is Implicit, which is the case here. The visitor still observes ParamMode::Implicit via the (defaulted) ret_mode field on Type::Fn.",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "Int" } ],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"effects": []
|
||||
},
|
||||
"params": ["x"],
|
||||
"body": { "t": "var", "name": "x" }
|
||||
},
|
||||
{
|
||||
"kind": "fn",
|
||||
"name": "f_own",
|
||||
"doc": "(own T) — caller transfers ownership; callee consumes.",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "Int" } ],
|
||||
"param_modes": ["own"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"effects": []
|
||||
},
|
||||
"params": ["x"],
|
||||
"body": { "t": "var", "name": "x" }
|
||||
},
|
||||
{
|
||||
"kind": "fn",
|
||||
"name": "f_borrow",
|
||||
"doc": "(borrow T) — caller retains ownership; callee may not consume.",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "Int" } ],
|
||||
"param_modes": ["borrow"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"effects": []
|
||||
},
|
||||
"params": ["x"],
|
||||
"body": { "t": "var", "name": "x" }
|
||||
}
|
||||
]
|
||||
}
|
||||
{"defs":[{"ctors":[{"fields":[],"name":"Nil"},{"fields":[{"k":"con","name":"Int"},{"k":"con","name":"List"}],"name":"Cons"}],"kind":"type","name":"List"},{"body":{"name":"x","t":"var"},"doc":"(own Int) — unboxed value types (Int/Bool/Float/Unit) are always own; borrow over them is a borrow-over-value error.","kind":"fn","name":"f_own_value","params":["x"],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"},"ret_mode":"own"}},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":0},"t":"lit"},"pat":{"ctor":"Nil","fields":[],"p":"ctor"}},{"body":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"},{"args":[{"name":"t","t":"var"}],"fn":{"name":"f_borrow_boxed","t":"var"},"t":"app"}],"fn":{"name":"+","t":"var"},"t":"app"},"pat":{"ctor":"Cons","fields":[{"name":"h","p":"var"},{"name":"t","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"xs","t":"var"},"t":"match"},"doc":"(borrow List) — boxed types may be borrowed; the callee reads without consuming.","kind":"fn","name":"f_borrow_boxed","params":["xs"],"type":{"effects":[],"k":"fn","param_modes":["borrow"],"params":[{"k":"con","name":"List"}],"ret":{"k":"con","name":"Int"},"ret_mode":"own"}}],"imports":[],"name":"param_modes_all","schema":"ailang/v0"}
|
||||
|
||||
@@ -133,38 +133,30 @@ BODY-TYPE)`.
|
||||
|
||||
## 4. Mode annotations
|
||||
|
||||
Every function parameter carries a mode. The mode says how the
|
||||
callee may treat the value: `implicit` is the legacy default
|
||||
(treated as `own`), `own` means the caller transfers ownership and
|
||||
the callee consumes the value, `borrow` means the caller retains
|
||||
ownership and the callee may inspect but not consume.
|
||||
Every function parameter carries a mode, and so does the return
|
||||
position. There are exactly two modes. `own` means the caller
|
||||
transfers ownership and the callee consumes the value; `borrow`
|
||||
means the caller retains ownership and the callee may inspect but
|
||||
not consume. `borrow` is legal only over a boxed type (an algebraic
|
||||
data type): unboxed value types (`Int`, `Bool`, `Float`, `Unit`)
|
||||
are always `own`, and borrowing one is a `borrow-over-value` error.
|
||||
|
||||
The mode also applies to the return value: `ret_mode` says whether
|
||||
the function transfers ownership to the caller (`own`) or returns a
|
||||
borrow (`borrow`). For most functions the return mode is `own` or
|
||||
implicit; `borrow` returns are rare and used only for accessor-style
|
||||
functions.
|
||||
The return position is always `own` — a function returns a fresh
|
||||
owned value; borrow-returns are not permitted.
|
||||
|
||||
Modes are mandatory on every parameter and on the return position.
|
||||
The schema rejects unannotated fn signatures only when annotations
|
||||
are explicitly requested; for compatibility the legacy form (no
|
||||
mode field at all) is treated as all-implicit.
|
||||
Modes are mandatory: every parameter and the return position carries
|
||||
exactly one mode. There is no default or omitted mode.
|
||||
|
||||
{form-only: json}
|
||||
On `Type::Fn`, two optional fields carry modes:
|
||||
On `Type::Fn`, two required fields carry modes:
|
||||
|
||||
- `param_modes`: array of strings `"implicit"`, `"own"`, or
|
||||
`"borrow"`, one per parameter, in the same order as `params`. The
|
||||
array is omitted from the canonical bytes when every entry is
|
||||
`"implicit"`; this is purely a serialisation optimisation. Author
|
||||
the field explicitly when at least one parameter is `own` or
|
||||
`borrow`.
|
||||
- `ret_mode`: a single string of the same vocabulary. Omitted when
|
||||
it would be `"implicit"`.
|
||||
- `param_modes`: an array of strings, each `"own"` or `"borrow"`,
|
||||
one per parameter, in the same order as `params`.
|
||||
- `ret_mode`: a single string, always `"own"`.
|
||||
|
||||
Example: a fn that borrows two ints and returns an int:
|
||||
`"param_modes": ["borrow", "borrow"]`, `ret_mode` omitted (implicit).
|
||||
A fn that consumes a list and returns a new list:
|
||||
Both are present on every fn type. Example — a fn that borrows a
|
||||
boxed list and returns an int: `"param_modes": ["borrow"]`,
|
||||
`"ret_mode": "own"`. A fn that consumes an int and returns an int:
|
||||
`"param_modes": ["own"]`, `"ret_mode": "own"`.
|
||||
{/form-only}
|
||||
|
||||
@@ -173,21 +165,13 @@ Modes are surface wrappers around the type in parameter and return
|
||||
position. Inside a `(fn-type ...)`:
|
||||
|
||||
- `(params (own T1) (borrow T2))` — `T1` is owned, `T2` is borrowed.
|
||||
- `(ret (own T))` — the function returns an owned value.
|
||||
- A bare type with no mode wrapper is implicit (legacy default).
|
||||
- `(ret (own T))` — the return is always owned.
|
||||
|
||||
When all parameters and the return are implicit, the surface omits
|
||||
the mode wrappers entirely; this is the canonical form for fns that
|
||||
do not yet need explicit annotations. Adding modes is a forward
|
||||
change: an existing fn keeps the same canonical bytes as long as no
|
||||
annotation is added.
|
||||
|
||||
Writing `(borrow T)` on a parameter the typechecker wants `own`
|
||||
for surfaces as the `over-strict-mode` diagnostic — advisory, and
|
||||
suppressable via the fn def's `suppress` clause. The mode is part
|
||||
of the fn's signature and contributes to its content hash, so
|
||||
making the choice explicit at authoring time avoids surprise
|
||||
hash changes when the typechecker's defaults shift.
|
||||
Every parameter and the return carries a mode wrapper; there is no
|
||||
bare-type (mode-less) form. `borrow` is legal only over a boxed
|
||||
type: `(borrow (con Int))` is a `borrow-over-value` error — write
|
||||
`(own (con Int))`. The mode is part of the fn's signature and
|
||||
contributes to its content hash.
|
||||
{/form-only}
|
||||
|
||||
{example: param_modes_all}
|
||||
|
||||
+168
-28
@@ -9,25 +9,62 @@
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [
|
||||
{ "k": "con", "name": "Int" },
|
||||
{ "k": "con", "name": "Int" },
|
||||
{ "k": "con", "name": "Int" }
|
||||
{
|
||||
"k": "con",
|
||||
"name": "Int"
|
||||
},
|
||||
{
|
||||
"k": "con",
|
||||
"name": "Int"
|
||||
},
|
||||
{
|
||||
"k": "con",
|
||||
"name": "Int"
|
||||
}
|
||||
],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"param_modes": [
|
||||
"own",
|
||||
"own",
|
||||
"own"
|
||||
],
|
||||
"ret": {
|
||||
"k": "con",
|
||||
"name": "Int"
|
||||
},
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["a", "b", "c"],
|
||||
"params": [
|
||||
"a",
|
||||
"b",
|
||||
"c"
|
||||
],
|
||||
"body": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "+" },
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "+"
|
||||
},
|
||||
"args": [
|
||||
{ "t": "var", "name": "a" },
|
||||
{
|
||||
"t": "var",
|
||||
"name": "a"
|
||||
},
|
||||
{
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "+" },
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "+"
|
||||
},
|
||||
"args": [
|
||||
{ "t": "var", "name": "b" },
|
||||
{ "t": "var", "name": "c" }
|
||||
{
|
||||
"t": "var",
|
||||
"name": "b"
|
||||
},
|
||||
{
|
||||
"t": "var",
|
||||
"name": "c"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -39,37 +76,140 @@
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"ret": { "k": "con", "name": "Unit" },
|
||||
"effects": ["IO"]
|
||||
"param_modes": [],
|
||||
"ret": {
|
||||
"k": "con",
|
||||
"name": "Unit"
|
||||
},
|
||||
"ret_mode": "own",
|
||||
"effects": [
|
||||
"IO"
|
||||
]
|
||||
},
|
||||
"params": [],
|
||||
"body": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_int",
|
||||
"args": [{
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "add_three" },
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 1 } },
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 2 } },
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 3 } }
|
||||
{
|
||||
"t": "app",
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "int_to_str"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "app",
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "add_three"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 3
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}]
|
||||
},
|
||||
"rhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_int",
|
||||
"args": [{
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "add_three" },
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 10 } },
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 20 } },
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 30 } }
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "str",
|
||||
"value": "\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}]
|
||||
}
|
||||
},
|
||||
"rhs": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "app",
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "int_to_str"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "app",
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "add_three"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 30
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"rhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "str",
|
||||
"value": "\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+214
-37
@@ -6,14 +6,31 @@
|
||||
{
|
||||
"kind": "type",
|
||||
"name": "List",
|
||||
"vars": ["a"],
|
||||
"vars": [
|
||||
"a"
|
||||
],
|
||||
"ctors": [
|
||||
{ "name": "Nil", "fields": [] },
|
||||
{
|
||||
"name": "Nil",
|
||||
"fields": []
|
||||
},
|
||||
{
|
||||
"name": "Cons",
|
||||
"fields": [
|
||||
{ "k": "var", "name": "a" },
|
||||
{ "k": "con", "name": "List", "args": [{ "k": "var", "name": "a" }] }
|
||||
{
|
||||
"k": "var",
|
||||
"name": "a"
|
||||
},
|
||||
{
|
||||
"k": "con",
|
||||
"name": "List",
|
||||
"args": [
|
||||
{
|
||||
"k": "var",
|
||||
"name": "a"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -23,43 +40,98 @@
|
||||
"name": "length",
|
||||
"type": {
|
||||
"k": "forall",
|
||||
"vars": ["a"],
|
||||
"vars": [
|
||||
"a"
|
||||
],
|
||||
"body": {
|
||||
"k": "fn",
|
||||
"params": [
|
||||
{ "k": "con", "name": "List", "args": [{ "k": "var", "name": "a" }] }
|
||||
{
|
||||
"k": "con",
|
||||
"name": "List",
|
||||
"args": [
|
||||
{
|
||||
"k": "var",
|
||||
"name": "a"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"param_modes": [
|
||||
"own"
|
||||
],
|
||||
"ret": {
|
||||
"k": "con",
|
||||
"name": "Int"
|
||||
},
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
}
|
||||
},
|
||||
"params": ["xs"],
|
||||
"params": [
|
||||
"xs"
|
||||
],
|
||||
"body": {
|
||||
"t": "match",
|
||||
"scrutinee": { "t": "var", "name": "xs" },
|
||||
"scrutinee": {
|
||||
"t": "var",
|
||||
"name": "xs"
|
||||
},
|
||||
"arms": [
|
||||
{
|
||||
"pat": { "p": "ctor", "ctor": "Nil", "fields": [] },
|
||||
"body": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
|
||||
"pat": {
|
||||
"p": "ctor",
|
||||
"ctor": "Nil",
|
||||
"fields": []
|
||||
},
|
||||
"body": {
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"pat": {
|
||||
"p": "ctor",
|
||||
"ctor": "Cons",
|
||||
"fields": [
|
||||
{ "p": "wild" },
|
||||
{ "p": "var", "name": "rest" }
|
||||
{
|
||||
"p": "wild"
|
||||
},
|
||||
{
|
||||
"p": "var",
|
||||
"name": "rest"
|
||||
}
|
||||
]
|
||||
},
|
||||
"body": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "+" },
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "+"
|
||||
},
|
||||
"args": [
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 1 } },
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "length" },
|
||||
"args": [{ "t": "var", "name": "rest" }]
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "length"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "var",
|
||||
"name": "rest"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -73,47 +145,152 @@
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"ret": { "k": "con", "name": "Unit" },
|
||||
"effects": ["IO"]
|
||||
"param_modes": [],
|
||||
"ret": {
|
||||
"k": "con",
|
||||
"name": "Unit"
|
||||
},
|
||||
"ret_mode": "own",
|
||||
"effects": [
|
||||
"IO"
|
||||
]
|
||||
},
|
||||
"params": [],
|
||||
"body": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_int",
|
||||
"args": [{
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "length" },
|
||||
"args": [{ "t": "ctor", "type": "List", "ctor": "Nil", "args": [] }]
|
||||
}]
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "int_to_str"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "app",
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "length"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "ctor",
|
||||
"type": "List",
|
||||
"ctor": "Nil",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"rhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_int",
|
||||
"args": [{
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "str",
|
||||
"value": "\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"rhs": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "length" },
|
||||
"args": [{
|
||||
"t": "ctor", "type": "List", "ctor": "Cons",
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "int_to_str"
|
||||
},
|
||||
"args": [
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 7 } },
|
||||
{
|
||||
"t": "ctor", "type": "List", "ctor": "Cons",
|
||||
"t": "app",
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "length"
|
||||
},
|
||||
"args": [
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 8 } },
|
||||
{
|
||||
"t": "ctor", "type": "List", "ctor": "Cons",
|
||||
"t": "ctor",
|
||||
"type": "List",
|
||||
"ctor": "Cons",
|
||||
"args": [
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 9 } },
|
||||
{ "t": "ctor", "type": "List", "ctor": "Nil", "args": [] }
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 7
|
||||
}
|
||||
},
|
||||
{
|
||||
"t": "ctor",
|
||||
"type": "List",
|
||||
"ctor": "Cons",
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 8
|
||||
}
|
||||
},
|
||||
{
|
||||
"t": "ctor",
|
||||
"type": "List",
|
||||
"ctor": "Cons",
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 9
|
||||
}
|
||||
},
|
||||
{
|
||||
"t": "ctor",
|
||||
"type": "List",
|
||||
"ctor": "Nil",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}]
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"rhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "str",
|
||||
"value": "\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+79
-6
@@ -9,21 +9,94 @@
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"ret": { "k": "con", "name": "Unit" },
|
||||
"effects": ["IO"]
|
||||
"param_modes": [],
|
||||
"ret": {
|
||||
"k": "con",
|
||||
"name": "Unit"
|
||||
},
|
||||
"ret_mode": "own",
|
||||
"effects": [
|
||||
"IO"
|
||||
]
|
||||
},
|
||||
"params": [],
|
||||
"body": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_int",
|
||||
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }]
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "app",
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "int_to_str"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 42
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"rhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_int",
|
||||
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 1337 } }]
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "str",
|
||||
"value": "\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"rhs": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "app",
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "int_to_str"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 1337
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"rhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "str",
|
||||
"value": "\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+258
-46
@@ -6,14 +6,31 @@
|
||||
{
|
||||
"kind": "type",
|
||||
"name": "List",
|
||||
"vars": ["a"],
|
||||
"vars": [
|
||||
"a"
|
||||
],
|
||||
"ctors": [
|
||||
{ "name": "Nil", "fields": [] },
|
||||
{
|
||||
"name": "Nil",
|
||||
"fields": []
|
||||
},
|
||||
{
|
||||
"name": "Cons",
|
||||
"fields": [
|
||||
{ "k": "var", "name": "a" },
|
||||
{ "k": "con", "name": "List", "args": [{ "k": "var", "name": "a" }] }
|
||||
{
|
||||
"k": "var",
|
||||
"name": "a"
|
||||
},
|
||||
{
|
||||
"k": "con",
|
||||
"name": "List",
|
||||
"args": [
|
||||
{
|
||||
"k": "var",
|
||||
"name": "a"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -24,55 +41,129 @@
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [
|
||||
{ "k": "con", "name": "List", "args": [{ "k": "con", "name": "Int" }] }
|
||||
{
|
||||
"k": "con",
|
||||
"name": "List",
|
||||
"args": [
|
||||
{
|
||||
"k": "con",
|
||||
"name": "Int"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"param_modes": [
|
||||
"own"
|
||||
],
|
||||
"ret": {
|
||||
"k": "con",
|
||||
"name": "Int"
|
||||
},
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["xs"],
|
||||
"params": [
|
||||
"xs"
|
||||
],
|
||||
"body": {
|
||||
"t": "match",
|
||||
"scrutinee": { "t": "var", "name": "xs" },
|
||||
"scrutinee": {
|
||||
"t": "var",
|
||||
"name": "xs"
|
||||
},
|
||||
"arms": [
|
||||
{
|
||||
"pat": { "p": "ctor", "ctor": "Nil", "fields": [] },
|
||||
"body": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
|
||||
"pat": {
|
||||
"p": "ctor",
|
||||
"ctor": "Nil",
|
||||
"fields": []
|
||||
},
|
||||
"body": {
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"pat": {
|
||||
"p": "ctor",
|
||||
"ctor": "Cons",
|
||||
"fields": [
|
||||
{ "p": "var", "name": "h" },
|
||||
{ "p": "var", "name": "rest" }
|
||||
{
|
||||
"p": "var",
|
||||
"name": "h"
|
||||
},
|
||||
{
|
||||
"p": "var",
|
||||
"name": "rest"
|
||||
}
|
||||
]
|
||||
},
|
||||
"body": {
|
||||
"t": "if",
|
||||
"cond": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "eq" },
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "eq"
|
||||
},
|
||||
"args": [
|
||||
{ "t": "var", "name": "h" },
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 0 } }
|
||||
{
|
||||
"t": "var",
|
||||
"name": "h"
|
||||
},
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "+" },
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "+"
|
||||
},
|
||||
"args": [
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 1 } },
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "count_zeros" },
|
||||
"args": [{ "t": "var", "name": "rest" }]
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "count_zeros"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "var",
|
||||
"name": "rest"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"else": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "count_zeros" },
|
||||
"args": [{ "t": "var", "name": "rest" }]
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "count_zeros"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "var",
|
||||
"name": "rest"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,48 +176,157 @@
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"ret": { "k": "con", "name": "Unit" },
|
||||
"effects": ["IO"]
|
||||
"param_modes": [],
|
||||
"ret": {
|
||||
"k": "con",
|
||||
"name": "Unit"
|
||||
},
|
||||
"ret_mode": "own",
|
||||
"effects": [
|
||||
"IO"
|
||||
]
|
||||
},
|
||||
"params": [],
|
||||
"body": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_int",
|
||||
"args": [{
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "count_zeros" },
|
||||
"args": [{ "t": "ctor", "type": "List", "ctor": "Nil", "args": [] }]
|
||||
}]
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "int_to_str"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "app",
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "count_zeros"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "ctor",
|
||||
"type": "List",
|
||||
"ctor": "Nil",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"rhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_int",
|
||||
"args": [{
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "str",
|
||||
"value": "\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"rhs": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "count_zeros" },
|
||||
"args": [{
|
||||
"t": "ctor", "type": "List", "ctor": "Cons",
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "int_to_str"
|
||||
},
|
||||
"args": [
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 0 } },
|
||||
{
|
||||
"t": "ctor", "type": "List", "ctor": "Cons",
|
||||
"t": "app",
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "count_zeros"
|
||||
},
|
||||
"args": [
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 5 } },
|
||||
{
|
||||
"t": "ctor", "type": "List", "ctor": "Cons",
|
||||
"t": "ctor",
|
||||
"type": "List",
|
||||
"ctor": "Cons",
|
||||
"args": [
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 0 } },
|
||||
{
|
||||
"t": "ctor", "type": "List", "ctor": "Cons",
|
||||
"args": [
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 3 } },
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"t": "ctor", "type": "List", "ctor": "Cons",
|
||||
"t": "ctor",
|
||||
"type": "List",
|
||||
"ctor": "Cons",
|
||||
"args": [
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 0 } },
|
||||
{ "t": "ctor", "type": "List", "ctor": "Nil", "args": [] }
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"t": "ctor",
|
||||
"type": "List",
|
||||
"ctor": "Cons",
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"t": "ctor",
|
||||
"type": "List",
|
||||
"ctor": "Cons",
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"t": "ctor",
|
||||
"type": "List",
|
||||
"ctor": "Cons",
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"t": "ctor",
|
||||
"type": "List",
|
||||
"ctor": "Nil",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -136,8 +336,20 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
}]
|
||||
}]
|
||||
},
|
||||
"rhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "str",
|
||||
"value": "\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ use std::collections::HashSet;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use ailang_core::ast::{
|
||||
Def, InstanceMethod, Literal, Module, ParamMode, Pattern, Term, Type,
|
||||
Def, InstanceMethod, Literal, Module, NewArg, ParamMode, Pattern, Term, Type,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
@@ -41,6 +41,9 @@ enum VariantTag {
|
||||
TermSeq,
|
||||
TermClone,
|
||||
TermReuseAs,
|
||||
TermLoop,
|
||||
TermRecur,
|
||||
TermNew,
|
||||
// Pattern
|
||||
PatternWild,
|
||||
PatternVar,
|
||||
@@ -58,7 +61,6 @@ enum VariantTag {
|
||||
TypeVar,
|
||||
TypeForall,
|
||||
// ParamMode
|
||||
ParamModeImplicit,
|
||||
ParamModeOwn,
|
||||
ParamModeBorrow,
|
||||
}
|
||||
@@ -86,6 +88,9 @@ const EXPECTED_VARIANTS: &[VariantTag] = &[
|
||||
VariantTag::TermSeq,
|
||||
VariantTag::TermClone,
|
||||
VariantTag::TermReuseAs,
|
||||
VariantTag::TermLoop,
|
||||
VariantTag::TermRecur,
|
||||
VariantTag::TermNew,
|
||||
VariantTag::PatternWild,
|
||||
VariantTag::PatternVar,
|
||||
VariantTag::PatternLit,
|
||||
@@ -99,7 +104,6 @@ const EXPECTED_VARIANTS: &[VariantTag] = &[
|
||||
VariantTag::TypeFn,
|
||||
VariantTag::TypeVar,
|
||||
VariantTag::TypeForall,
|
||||
VariantTag::ParamModeImplicit,
|
||||
VariantTag::ParamModeOwn,
|
||||
VariantTag::ParamModeBorrow,
|
||||
];
|
||||
@@ -222,6 +226,37 @@ fn visit_term(t: &Term, observed: &mut HashSet<VariantTag>) {
|
||||
visit_term(source, observed);
|
||||
visit_term(body, observed);
|
||||
}
|
||||
Term::Loop { binders, body } => {
|
||||
observed.insert(VariantTag::TermLoop);
|
||||
for b in binders {
|
||||
visit_type(&b.ty, observed);
|
||||
visit_term(&b.init, observed);
|
||||
}
|
||||
visit_term(body, observed);
|
||||
}
|
||||
Term::Recur { args } => {
|
||||
observed.insert(VariantTag::TermRecur);
|
||||
for a in args {
|
||||
visit_term(a, observed);
|
||||
}
|
||||
}
|
||||
Term::New { type_name: _, args } => {
|
||||
observed.insert(VariantTag::TermNew);
|
||||
for a in args {
|
||||
match a {
|
||||
NewArg::Type(t) => visit_type(t, observed),
|
||||
NewArg::Value(v) => visit_term(v, observed),
|
||||
}
|
||||
}
|
||||
}
|
||||
// `Intrinsic` is the compiler-supplied body marker — non-authorable
|
||||
// (absent from the parser's term dispatch; typecheck enforces
|
||||
// kernel-tier-only via IntrinsicOutsideKernelTier). A foreign-author
|
||||
// mini-spec must not show it and no master example can legally
|
||||
// contain it, so it is allowlisted OUT of completeness: no VariantTag,
|
||||
// no EXPECTED entry, a no-op arm here so the match compiles without
|
||||
// claiming coverage.
|
||||
Term::Intrinsic => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,9 +332,6 @@ fn visit_type(t: &Type, observed: &mut HashSet<VariantTag>) {
|
||||
|
||||
fn visit_param_mode(m: &ParamMode, observed: &mut HashSet<VariantTag>) {
|
||||
match m {
|
||||
ParamMode::Implicit => {
|
||||
observed.insert(VariantTag::ParamModeImplicit);
|
||||
}
|
||||
ParamMode::Own => {
|
||||
observed.insert(VariantTag::ParamModeOwn);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ through this pair is gated by an integration test.
|
||||
(module fn_returns_int
|
||||
(fn answer
|
||||
(doc "The simplest possible fn — no params, returns a fixed Int.")
|
||||
(type (fn-type (params) (ret (con Int))))
|
||||
(type (fn-type (params) (ret (own (con Int)))))
|
||||
(params)
|
||||
(body 42)))
|
||||
```
|
||||
@@ -99,68 +99,57 @@ BODY-TYPE)`.
|
||||
(module forall_polymorphic
|
||||
(fn id
|
||||
(doc "The polymorphic identity function. Exercises Type::Forall and Type::Var.")
|
||||
(type (forall (vars a) (fn-type (params a) (ret a))))
|
||||
(type (forall (vars a) (fn-type (params (own a)) (ret (own a)))))
|
||||
(params x)
|
||||
(body x)))
|
||||
```
|
||||
|
||||
## 4. Mode annotations
|
||||
|
||||
Every function parameter carries a mode. The mode says how the
|
||||
callee may treat the value: `implicit` is the legacy default
|
||||
(treated as `own`), `own` means the caller transfers ownership and
|
||||
the callee consumes the value, `borrow` means the caller retains
|
||||
ownership and the callee may inspect but not consume.
|
||||
Every function parameter carries a mode, and so does the return
|
||||
position. There are exactly two modes. `own` means the caller
|
||||
transfers ownership and the callee consumes the value; `borrow`
|
||||
means the caller retains ownership and the callee may inspect but
|
||||
not consume. `borrow` is legal only over a boxed type (an algebraic
|
||||
data type): unboxed value types (`Int`, `Bool`, `Float`, `Unit`)
|
||||
are always `own`, and borrowing one is a `borrow-over-value` error.
|
||||
|
||||
The mode also applies to the return value: `ret_mode` says whether
|
||||
the function transfers ownership to the caller (`own`) or returns a
|
||||
borrow (`borrow`). For most functions the return mode is `own` or
|
||||
implicit; `borrow` returns are rare and used only for accessor-style
|
||||
functions.
|
||||
The return position is always `own` — a function returns a fresh
|
||||
owned value; borrow-returns are not permitted.
|
||||
|
||||
Modes are mandatory on every parameter and on the return position.
|
||||
The schema rejects unannotated fn signatures only when annotations
|
||||
are explicitly requested; for compatibility the legacy form (no
|
||||
mode field at all) is treated as all-implicit.
|
||||
Modes are mandatory: every parameter and the return position carries
|
||||
exactly one mode. There is no default or omitted mode.
|
||||
|
||||
|
||||
Modes are surface wrappers around the type in parameter and return
|
||||
position. Inside a `(fn-type ...)`:
|
||||
|
||||
- `(params (own T1) (borrow T2))` — `T1` is owned, `T2` is borrowed.
|
||||
- `(ret (own T))` — the function returns an owned value.
|
||||
- A bare type with no mode wrapper is implicit (legacy default).
|
||||
- `(ret (own T))` — the return is always owned.
|
||||
|
||||
When all parameters and the return are implicit, the surface omits
|
||||
the mode wrappers entirely; this is the canonical form for fns that
|
||||
do not yet need explicit annotations. Adding modes is a forward
|
||||
change: an existing fn keeps the same canonical bytes as long as no
|
||||
annotation is added.
|
||||
|
||||
Writing `(borrow T)` on a parameter the typechecker wants `own`
|
||||
for surfaces as the `over-strict-mode` diagnostic — advisory, and
|
||||
suppressable via the fn def's `suppress` clause. The mode is part
|
||||
of the fn's signature and contributes to its content hash, so
|
||||
making the choice explicit at authoring time avoids surprise
|
||||
hash changes when the typechecker's defaults shift.
|
||||
Every parameter and the return carries a mode wrapper; there is no
|
||||
bare-type (mode-less) form. `borrow` is legal only over a boxed
|
||||
type: `(borrow (con Int))` is a `borrow-over-value` error — write
|
||||
`(own (con Int))`. The mode is part of the fn's signature and
|
||||
contributes to its content hash.
|
||||
|
||||
```ail
|
||||
(module param_modes_all
|
||||
(fn f_implicit
|
||||
(doc "Implicit mode is the legacy default — `param_modes` is omitted from canonical JSON when every entry is Implicit, which is the case here. The visitor still observes ParamMode::Implicit via the (defaulted) ret_mode field on Type::Fn.")
|
||||
(type (fn-type (params (con Int)) (ret (con Int))))
|
||||
(data List
|
||||
(ctor Nil)
|
||||
(ctor Cons (con Int) (con List)))
|
||||
(fn f_own_value
|
||||
(doc "(own Int) — unboxed value types (Int/Bool/Float/Unit) are always own; borrow over them is a borrow-over-value error.")
|
||||
(type (fn-type (params (own (con Int))) (ret (own (con Int)))))
|
||||
(params x)
|
||||
(body x))
|
||||
(fn f_own
|
||||
(doc "(own T) — caller transfers ownership; callee consumes.")
|
||||
(type (fn-type (params (own (con Int))) (ret (con Int))))
|
||||
(params x)
|
||||
(body x))
|
||||
(fn f_borrow
|
||||
(doc "(borrow T) — caller retains ownership; callee may not consume.")
|
||||
(type (fn-type (params (borrow (con Int))) (ret (con Int))))
|
||||
(params x)
|
||||
(body x)))
|
||||
(fn f_borrow_boxed
|
||||
(doc "(borrow List) — boxed types may be borrowed; the callee reads without consuming.")
|
||||
(type (fn-type (params (borrow (con List))) (ret (own (con Int)))))
|
||||
(params xs)
|
||||
(body (match xs
|
||||
(case (pat-ctor Nil) 0)
|
||||
(case (pat-ctor Cons h t) (app + 1 (app f_borrow_boxed t)))))))
|
||||
```
|
||||
|
||||
## 5. Functions
|
||||
@@ -211,7 +200,7 @@ number, a string is a double-quoted string, a bool is `true` or
|
||||
(module fn_calls_prelude
|
||||
(fn add
|
||||
(doc "Add two Ints via the polymorphic prelude `+`. Also exercises TermLet by binding the sum to a local name before returning it, and TermClone by re-using the let-bound value.")
|
||||
(type (fn-type (params (con Int) (con Int)) (ret (con Int))))
|
||||
(type (fn-type (params (own (con Int)) (own (con Int))) (ret (own (con Int)))))
|
||||
(params x y)
|
||||
(body (let s (app + x y) (clone s)))))
|
||||
```
|
||||
@@ -220,7 +209,7 @@ number, a string is a double-quoted string, a bool is `true` or
|
||||
(module fn_with_lambda
|
||||
(fn make_adder
|
||||
(doc "Curried adder: takes an Int and returns an Int -> Int closure. Exercises TermLam and Type::Fn appearing as a return type.")
|
||||
(type (fn-type (params (con Int)) (ret (fn-type (params (con Int)) (ret (con Int))))))
|
||||
(type (fn-type (params (own (con Int))) (ret (own (fn-type (params (own (con Int))) (ret (own (con Int))))))))
|
||||
(params x)
|
||||
(body (lam (params (typed y (con Int))) (ret (con Int)) (body (app + x y))))))
|
||||
```
|
||||
@@ -264,13 +253,12 @@ element list.
|
||||
```ail
|
||||
(module data_simple
|
||||
(data Box (vars a)
|
||||
(doc "A unary box around a polymorphic value.")
|
||||
(ctor MkBox a))
|
||||
(fn wrap_one
|
||||
(doc "Construct a Box Int via MkBox. The body uses (reuse-as src body) — a hint that the freshly-allocated Box should reuse the source's memory slot under --alloc=rc. Exercises TermCtor, ReuseAs, and Type::Var inside a ctor field position.")
|
||||
(type (fn-type (params (own (con Box (con Int)))) (ret (own (con Box (con Int))))))
|
||||
(params src)
|
||||
(body (reuse-as src (term-ctor Box MkBox 1)))))
|
||||
(body (match src
|
||||
(case (pat-ctor MkBox v) (reuse-as src (term-ctor Box MkBox 1)))))))
|
||||
```
|
||||
|
||||
## 7. Pattern matching
|
||||
@@ -319,16 +307,16 @@ arms or into code outside the `match`.
|
||||
(ctor Cons (con Int) (con List)))
|
||||
(fn head_or_zero
|
||||
(doc "Return the head of xs, or 0 if empty. Exercises TermMatch with two arms, PatternCtor (both nullary Nil and binary Cons), and PatternWild on the tail field.")
|
||||
(type (fn-type (params (borrow (con List))) (ret (con Int))))
|
||||
(type (fn-type (params (borrow (con List))) (ret (own (con Int)))))
|
||||
(params xs)
|
||||
(body (match xs
|
||||
(case (pat-ctor Nil) 0)
|
||||
(case (pat-ctor Cons h _) h))))
|
||||
(fn count_via_letrec
|
||||
(doc "Walk xs counting nodes using a local recursive let. Exercises TermLetRec and TermVar; the recursive `go` is bound locally.")
|
||||
(type (fn-type (params (borrow (con List))) (ret (con Int))))
|
||||
(type (fn-type (params (own (con List))) (ret (own (con Int)))))
|
||||
(params xs)
|
||||
(body (let-rec go (params ys) (type (fn-type (params (borrow (con List))) (ret (con Int)))) (body (match ys
|
||||
(body (let-rec go (params ys) (type (fn-type (params (own (con List))) (ret (own (con Int))))) (body (match ys
|
||||
(case (pat-ctor Nil) 0)
|
||||
(case (pat-ctor Cons _ t) (app + 1 (app go t))))) (in (app go xs))))))
|
||||
```
|
||||
@@ -337,16 +325,16 @@ arms or into code outside the `match`.
|
||||
(module match_literal_pattern
|
||||
(fn classify
|
||||
(doc "Classify an Int via literal patterns plus a wildcard fallback. Exercises PatternLit and PatternWild.")
|
||||
(type (fn-type (params (con Int)) (ret (con Int))))
|
||||
(type (fn-type (params (own (con Int))) (ret (own (con Int)))))
|
||||
(params n)
|
||||
(body (match n
|
||||
(case (pat-lit 0) 100)
|
||||
(case _ 200))))
|
||||
(fn sign_if
|
||||
(doc "Return -1 / 0 / 1 for the sign of n using nested TermIf. Exercises TermIf in both then/else positions plus TermApp on the polymorphic comparison.")
|
||||
(type (fn-type (params (con Int)) (ret (con Int))))
|
||||
(type (fn-type (params (own (con Int))) (ret (own (con Int)))))
|
||||
(params n)
|
||||
(body (if (app < n 0) -1 (if (app == n 0) 0 1)))))
|
||||
(body (if (app lt n 0) -1 (if (app eq n 0) 0 1)))))
|
||||
```
|
||||
|
||||
## 8. Effects
|
||||
@@ -390,9 +378,9 @@ value.
|
||||
(module fn_with_do_seq
|
||||
(fn main
|
||||
(doc "Print two Ints in sequence. Exercises TermDo, TermSeq, and the IO effect on a fn type. The trailing unit return is implicit in the last Do (op returns Unit).")
|
||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||
(type (fn-type (params) (ret (own (con Unit))) (effects IO)))
|
||||
(params)
|
||||
(body (seq (do io/print_int 1) (do io/print_int 2)))))
|
||||
(body (seq (seq (do io/print_str (app int_to_str 1)) (do io/print_str "\n")) (seq (do io/print_str (app int_to_str 2)) (do io/print_str "\n"))))))
|
||||
```
|
||||
|
||||
## 9. Literals
|
||||
@@ -447,17 +435,17 @@ authoring surface; for non-finite values use the prelude constants
|
||||
(module bool_str
|
||||
(fn is_true
|
||||
(doc "Trivial Bool literal. Exercises Literal::Bool.")
|
||||
(type (fn-type (params) (ret (con Bool))))
|
||||
(type (fn-type (params) (ret (own (con Bool)))))
|
||||
(params)
|
||||
(body true))
|
||||
(fn greeting
|
||||
(doc "Trivial Str literal. Exercises Literal::Str.")
|
||||
(type (fn-type (params) (ret (con Str))))
|
||||
(type (fn-type (params) (ret (own (con Str)))))
|
||||
(params)
|
||||
(body "hi"))
|
||||
(fn unit_value
|
||||
(doc "Trivial Unit literal — needed so Literal::Unit appears at least once in the corpus.")
|
||||
(type (fn-type (params) (ret (con Unit))))
|
||||
(type (fn-type (params) (ret (own (con Unit)))))
|
||||
(params)
|
||||
(body (lit-unit))))
|
||||
```
|
||||
@@ -508,7 +496,7 @@ also legal (typically a typecheck error unless an instance exists).
|
||||
(param a)
|
||||
(doc "A toy single-method class. The instance in instance_def.ail.json provides a body for `show` at type Int.")
|
||||
(method show
|
||||
(type (fn-type (params a) (ret (con Str)))))))
|
||||
(type (fn-type (params (own a)) (ret (own (con Str))))))))
|
||||
```
|
||||
|
||||
```ail
|
||||
@@ -517,7 +505,7 @@ also legal (typically a typecheck error unless an instance exists).
|
||||
(param a)
|
||||
(doc "Re-declared here so this fixture is self-contained; class_def.ail.json declares the same class verbatim.")
|
||||
(method show
|
||||
(type (fn-type (params a) (ret (con Str))))))
|
||||
(type (fn-type (params (own a)) (ret (own (con Str)))))))
|
||||
(instance
|
||||
(class MyShow)
|
||||
(type (con Int))
|
||||
|
||||
@@ -58,7 +58,9 @@ carries a `kind` discriminator.
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"param_modes": [],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": [],
|
||||
@@ -123,7 +125,9 @@ optional `constraints` array for class constraints (see section 10).
|
||||
"body": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "var", "name": "a" } ],
|
||||
"param_modes": ["own"],
|
||||
"ret": { "k": "var", "name": "a" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
}
|
||||
},
|
||||
@@ -136,89 +140,34 @@ optional `constraints` array for class constraints (see section 10).
|
||||
|
||||
## 4. Mode annotations
|
||||
|
||||
Every function parameter carries a mode. The mode says how the
|
||||
callee may treat the value: `implicit` is the legacy default
|
||||
(treated as `own`), `own` means the caller transfers ownership and
|
||||
the callee consumes the value, `borrow` means the caller retains
|
||||
ownership and the callee may inspect but not consume.
|
||||
Every function parameter carries a mode, and so does the return
|
||||
position. There are exactly two modes. `own` means the caller
|
||||
transfers ownership and the callee consumes the value; `borrow`
|
||||
means the caller retains ownership and the callee may inspect but
|
||||
not consume. `borrow` is legal only over a boxed type (an algebraic
|
||||
data type): unboxed value types (`Int`, `Bool`, `Float`, `Unit`)
|
||||
are always `own`, and borrowing one is a `borrow-over-value` error.
|
||||
|
||||
The mode also applies to the return value: `ret_mode` says whether
|
||||
the function transfers ownership to the caller (`own`) or returns a
|
||||
borrow (`borrow`). For most functions the return mode is `own` or
|
||||
implicit; `borrow` returns are rare and used only for accessor-style
|
||||
functions.
|
||||
The return position is always `own` — a function returns a fresh
|
||||
owned value; borrow-returns are not permitted.
|
||||
|
||||
Modes are mandatory on every parameter and on the return position.
|
||||
The schema rejects unannotated fn signatures only when annotations
|
||||
are explicitly requested; for compatibility the legacy form (no
|
||||
mode field at all) is treated as all-implicit.
|
||||
Modes are mandatory: every parameter and the return position carries
|
||||
exactly one mode. There is no default or omitted mode.
|
||||
|
||||
On `Type::Fn`, two optional fields carry modes:
|
||||
On `Type::Fn`, two required fields carry modes:
|
||||
|
||||
- `param_modes`: array of strings `"implicit"`, `"own"`, or
|
||||
`"borrow"`, one per parameter, in the same order as `params`. The
|
||||
array is omitted from the canonical bytes when every entry is
|
||||
`"implicit"`; this is purely a serialisation optimisation. Author
|
||||
the field explicitly when at least one parameter is `own` or
|
||||
`borrow`.
|
||||
- `ret_mode`: a single string of the same vocabulary. Omitted when
|
||||
it would be `"implicit"`.
|
||||
- `param_modes`: an array of strings, each `"own"` or `"borrow"`,
|
||||
one per parameter, in the same order as `params`.
|
||||
- `ret_mode`: a single string, always `"own"`.
|
||||
|
||||
Example: a fn that borrows two ints and returns an int:
|
||||
`"param_modes": ["borrow", "borrow"]`, `ret_mode` omitted (implicit).
|
||||
A fn that consumes a list and returns a new list:
|
||||
Both are present on every fn type. Example — a fn that borrows a
|
||||
boxed list and returns an int: `"param_modes": ["borrow"]`,
|
||||
`"ret_mode": "own"`. A fn that consumes an int and returns an int:
|
||||
`"param_modes": ["own"]`, `"ret_mode": "own"`.
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"schema": "ailang/v0",
|
||||
"name": "param_modes_all",
|
||||
"imports": [],
|
||||
"defs": [
|
||||
{
|
||||
"kind": "fn",
|
||||
"name": "f_implicit",
|
||||
"doc": "Implicit mode is the legacy default — `param_modes` is omitted from canonical JSON when every entry is Implicit, which is the case here. The visitor still observes ParamMode::Implicit via the (defaulted) ret_mode field on Type::Fn.",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "Int" } ],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"effects": []
|
||||
},
|
||||
"params": ["x"],
|
||||
"body": { "t": "var", "name": "x" }
|
||||
},
|
||||
{
|
||||
"kind": "fn",
|
||||
"name": "f_own",
|
||||
"doc": "(own T) — caller transfers ownership; callee consumes.",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "Int" } ],
|
||||
"param_modes": ["own"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"effects": []
|
||||
},
|
||||
"params": ["x"],
|
||||
"body": { "t": "var", "name": "x" }
|
||||
},
|
||||
{
|
||||
"kind": "fn",
|
||||
"name": "f_borrow",
|
||||
"doc": "(borrow T) — caller retains ownership; callee may not consume.",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "Int" } ],
|
||||
"param_modes": ["borrow"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"effects": []
|
||||
},
|
||||
"params": ["x"],
|
||||
"body": { "t": "var", "name": "x" }
|
||||
}
|
||||
]
|
||||
}
|
||||
{"defs":[{"ctors":[{"fields":[],"name":"Nil"},{"fields":[{"k":"con","name":"Int"},{"k":"con","name":"List"}],"name":"Cons"}],"kind":"type","name":"List"},{"body":{"name":"x","t":"var"},"doc":"(own Int) — unboxed value types (Int/Bool/Float/Unit) are always own; borrow over them is a borrow-over-value error.","kind":"fn","name":"f_own_value","params":["x"],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"},"ret_mode":"own"}},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":0},"t":"lit"},"pat":{"ctor":"Nil","fields":[],"p":"ctor"}},{"body":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"},{"args":[{"name":"t","t":"var"}],"fn":{"name":"f_borrow_boxed","t":"var"},"t":"app"}],"fn":{"name":"+","t":"var"},"t":"app"},"pat":{"ctor":"Cons","fields":[{"name":"h","p":"var"},{"name":"t","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"xs","t":"var"},"t":"match"},"doc":"(borrow List) — boxed types may be borrowed; the callee reads without consuming.","kind":"fn","name":"f_borrow_boxed","params":["xs"],"type":{"effects":[],"k":"fn","param_modes":["borrow"],"params":[{"k":"con","name":"List"}],"ret":{"k":"con","name":"Int"},"ret_mode":"own"}}],"imports":[],"name":"param_modes_all","schema":"ailang/v0"}
|
||||
```
|
||||
|
||||
## 5. Functions
|
||||
@@ -279,7 +228,9 @@ the difference.
|
||||
{ "k": "con", "name": "Int" },
|
||||
{ "k": "con", "name": "Int" }
|
||||
],
|
||||
"param_modes": ["own", "own"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["x", "y"],
|
||||
@@ -314,20 +265,24 @@ the difference.
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "Int" } ],
|
||||
"param_modes": ["own"],
|
||||
"ret": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "Int" } ],
|
||||
"param_modes": ["own"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["x"],
|
||||
"body": {
|
||||
"t": "lam",
|
||||
"params": ["y"],
|
||||
"paramTypes": [ { "k": "con", "name": "Int" } ],
|
||||
"retType": { "k": "con", "name": "Int" },
|
||||
"param-types": [ { "k": "con", "name": "Int" } ],
|
||||
"ret-type": { "k": "con", "name": "Int" },
|
||||
"effects": [],
|
||||
"body": {
|
||||
"t": "app",
|
||||
@@ -378,51 +333,7 @@ carry `"args": []`.
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"schema": "ailang/v0",
|
||||
"name": "data_simple",
|
||||
"imports": [],
|
||||
"defs": [
|
||||
{
|
||||
"kind": "type",
|
||||
"name": "Box",
|
||||
"vars": ["a"],
|
||||
"doc": "A unary box around a polymorphic value.",
|
||||
"ctors": [
|
||||
{
|
||||
"name": "MkBox",
|
||||
"fields": [ { "k": "var", "name": "a" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "fn",
|
||||
"name": "wrap_one",
|
||||
"doc": "Construct a Box Int via MkBox. The body uses (reuse-as src body) — a hint that the freshly-allocated Box should reuse the source's memory slot under --alloc=rc. Exercises TermCtor, ReuseAs, and Type::Var inside a ctor field position.",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [
|
||||
{ "k": "con", "name": "Box", "args": [ { "k": "con", "name": "Int" } ] }
|
||||
],
|
||||
"param_modes": ["own"],
|
||||
"ret": { "k": "con", "name": "Box", "args": [ { "k": "con", "name": "Int" } ] },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["src"],
|
||||
"body": {
|
||||
"t": "reuse-as",
|
||||
"source": { "t": "var", "name": "src" },
|
||||
"body": {
|
||||
"t": "ctor",
|
||||
"type": "Box",
|
||||
"ctor": "MkBox",
|
||||
"args": [ { "t": "lit", "lit": { "kind": "int", "value": 1 } } ]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
{"defs":[{"ctors":[{"fields":[{"k":"var","name":"a"}],"name":"MkBox"}],"kind":"type","name":"Box","vars":["a"]},{"body":{"arms":[{"body":{"body":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"ctor":"MkBox","t":"ctor","type":"Box"},"source":{"name":"src","t":"var"},"t":"reuse-as"},"pat":{"ctor":"MkBox","fields":[{"name":"v","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"src","t":"var"},"t":"match"},"kind":"fn","name":"wrap_one","params":["src"],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"args":[{"k":"con","name":"Int"}],"k":"con","name":"Box"}],"ret":{"args":[{"k":"con","name":"Int"}],"k":"con","name":"Box"},"ret_mode":"own"}}],"imports":[],"name":"data_simple","schema":"ailang/v0"}
|
||||
```
|
||||
|
||||
## 7. Pattern matching
|
||||
@@ -470,14 +381,23 @@ single pattern. Repeating a name is a typecheck error.
|
||||
{
|
||||
"kind": "type",
|
||||
"name": "List",
|
||||
"doc": "Monomorphic singly-linked Int list — boxed, recursive.",
|
||||
"doc": "Monomorphic singly-linked Int list \u2014 boxed, recursive.",
|
||||
"ctors": [
|
||||
{ "name": "Nil", "fields": [] },
|
||||
{
|
||||
"name": "Nil",
|
||||
"fields": []
|
||||
},
|
||||
{
|
||||
"name": "Cons",
|
||||
"fields": [
|
||||
{ "k": "con", "name": "Int" },
|
||||
{ "k": "con", "name": "List" }
|
||||
{
|
||||
"k": "con",
|
||||
"name": "Int"
|
||||
},
|
||||
{
|
||||
"k": "con",
|
||||
"name": "List"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -488,30 +408,64 @@ single pattern. Repeating a name is a typecheck error.
|
||||
"doc": "Return the head of xs, or 0 if empty. Exercises TermMatch with two arms, PatternCtor (both nullary Nil and binary Cons), and PatternWild on the tail field.",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "List" } ],
|
||||
"param_modes": ["borrow"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"params": [
|
||||
{
|
||||
"k": "con",
|
||||
"name": "List"
|
||||
}
|
||||
],
|
||||
"param_modes": [
|
||||
"borrow"
|
||||
],
|
||||
"ret": {
|
||||
"k": "con",
|
||||
"name": "Int"
|
||||
},
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["xs"],
|
||||
"params": [
|
||||
"xs"
|
||||
],
|
||||
"body": {
|
||||
"t": "match",
|
||||
"scrutinee": { "t": "var", "name": "xs" },
|
||||
"scrutinee": {
|
||||
"t": "var",
|
||||
"name": "xs"
|
||||
},
|
||||
"arms": [
|
||||
{
|
||||
"pat": { "p": "ctor", "ctor": "Nil", "fields": [] },
|
||||
"body": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
|
||||
"pat": {
|
||||
"p": "ctor",
|
||||
"ctor": "Nil",
|
||||
"fields": []
|
||||
},
|
||||
"body": {
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"pat": {
|
||||
"p": "ctor",
|
||||
"ctor": "Cons",
|
||||
"fields": [
|
||||
{ "p": "var", "name": "h" },
|
||||
{ "p": "wild" }
|
||||
{
|
||||
"p": "var",
|
||||
"name": "h"
|
||||
},
|
||||
{
|
||||
"p": "wild"
|
||||
}
|
||||
]
|
||||
},
|
||||
"body": { "t": "var", "name": "h" }
|
||||
"body": {
|
||||
"t": "var",
|
||||
"name": "h"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -522,49 +476,110 @@ single pattern. Repeating a name is a typecheck error.
|
||||
"doc": "Walk xs counting nodes using a local recursive let. Exercises TermLetRec and TermVar; the recursive `go` is bound locally.",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "List" } ],
|
||||
"param_modes": ["borrow"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"params": [
|
||||
{
|
||||
"k": "con",
|
||||
"name": "List"
|
||||
}
|
||||
],
|
||||
"param_modes": [
|
||||
"own"
|
||||
],
|
||||
"ret": {
|
||||
"k": "con",
|
||||
"name": "Int"
|
||||
},
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["xs"],
|
||||
"params": [
|
||||
"xs"
|
||||
],
|
||||
"body": {
|
||||
"t": "letrec",
|
||||
"name": "go",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "List" } ],
|
||||
"param_modes": ["borrow"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"params": [
|
||||
{
|
||||
"k": "con",
|
||||
"name": "List"
|
||||
}
|
||||
],
|
||||
"param_modes": [
|
||||
"own"
|
||||
],
|
||||
"ret": {
|
||||
"k": "con",
|
||||
"name": "Int"
|
||||
},
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["ys"],
|
||||
"params": [
|
||||
"ys"
|
||||
],
|
||||
"body": {
|
||||
"t": "match",
|
||||
"scrutinee": { "t": "var", "name": "ys" },
|
||||
"scrutinee": {
|
||||
"t": "var",
|
||||
"name": "ys"
|
||||
},
|
||||
"arms": [
|
||||
{
|
||||
"pat": { "p": "ctor", "ctor": "Nil", "fields": [] },
|
||||
"body": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
|
||||
"pat": {
|
||||
"p": "ctor",
|
||||
"ctor": "Nil",
|
||||
"fields": []
|
||||
},
|
||||
"body": {
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"pat": {
|
||||
"p": "ctor",
|
||||
"ctor": "Cons",
|
||||
"fields": [
|
||||
{ "p": "wild" },
|
||||
{ "p": "var", "name": "t" }
|
||||
{
|
||||
"p": "wild"
|
||||
},
|
||||
{
|
||||
"p": "var",
|
||||
"name": "t"
|
||||
}
|
||||
]
|
||||
},
|
||||
"body": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "+" },
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "+"
|
||||
},
|
||||
"args": [
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 1 } },
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "go" },
|
||||
"args": [ { "t": "var", "name": "t" } ]
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "go"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "var",
|
||||
"name": "t"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -573,8 +588,16 @@ single pattern. Repeating a name is a typecheck error.
|
||||
},
|
||||
"in": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "go" },
|
||||
"args": [ { "t": "var", "name": "xs" } ]
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "go"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "var",
|
||||
"name": "xs"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -595,7 +618,9 @@ single pattern. Repeating a name is a typecheck error.
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "Int" } ],
|
||||
"param_modes": ["own"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["n"],
|
||||
@@ -621,7 +646,9 @@ single pattern. Repeating a name is a typecheck error.
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "con", "name": "Int" } ],
|
||||
"param_modes": ["own"],
|
||||
"ret": { "k": "con", "name": "Int" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": ["n"],
|
||||
@@ -629,7 +656,7 @@ single pattern. Repeating a name is a typecheck error.
|
||||
"t": "if",
|
||||
"cond": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "<" },
|
||||
"fn": { "t": "var", "name": "lt" },
|
||||
"args": [
|
||||
{ "t": "var", "name": "n" },
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 0 } }
|
||||
@@ -640,7 +667,7 @@ single pattern. Repeating a name is a typecheck error.
|
||||
"t": "if",
|
||||
"cond": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "==" },
|
||||
"fn": { "t": "var", "name": "eq" },
|
||||
"args": [
|
||||
{ "t": "var", "name": "n" },
|
||||
{ "t": "lit", "lit": { "kind": "int", "value": 0 } }
|
||||
@@ -704,21 +731,94 @@ discarded but its effects count toward the enclosing fn's row.
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"ret": { "k": "con", "name": "Unit" },
|
||||
"effects": ["IO"]
|
||||
"param_modes": [],
|
||||
"ret": {
|
||||
"k": "con",
|
||||
"name": "Unit"
|
||||
},
|
||||
"ret_mode": "own",
|
||||
"effects": [
|
||||
"IO"
|
||||
]
|
||||
},
|
||||
"params": [],
|
||||
"body": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_int",
|
||||
"args": [ { "t": "lit", "lit": { "kind": "int", "value": 1 } } ]
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "app",
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "int_to_str"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"rhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_int",
|
||||
"args": [ { "t": "lit", "lit": { "kind": "int", "value": 2 } } ]
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "str",
|
||||
"value": "\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"rhs": {
|
||||
"t": "seq",
|
||||
"lhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "app",
|
||||
"fn": {
|
||||
"t": "var",
|
||||
"name": "int_to_str"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "int",
|
||||
"value": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"rhs": {
|
||||
"t": "do",
|
||||
"op": "io/print_str",
|
||||
"args": [
|
||||
{
|
||||
"t": "lit",
|
||||
"lit": {
|
||||
"kind": "str",
|
||||
"value": "\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -795,7 +895,9 @@ not by the author. When you write `3.14` in AIL, the parser emits
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"param_modes": [],
|
||||
"ret": { "k": "con", "name": "Bool" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": [],
|
||||
@@ -808,7 +910,9 @@ not by the author. When you write `3.14` in AIL, the parser emits
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"param_modes": [],
|
||||
"ret": { "k": "con", "name": "Str" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": [],
|
||||
@@ -821,7 +925,9 @@ not by the author. When you write `3.14` in AIL, the parser emits
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"param_modes": [],
|
||||
"ret": { "k": "con", "name": "Unit" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
},
|
||||
"params": [],
|
||||
@@ -889,7 +995,9 @@ constraints; omitted from canonical bytes when empty.
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "var", "name": "a" } ],
|
||||
"param_modes": ["own"],
|
||||
"ret": { "k": "con", "name": "Str" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
}
|
||||
}
|
||||
@@ -916,7 +1024,9 @@ constraints; omitted from canonical bytes when empty.
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [ { "k": "var", "name": "a" } ],
|
||||
"param_modes": ["own"],
|
||||
"ret": { "k": "con", "name": "Str" },
|
||||
"ret_mode": "own",
|
||||
"effects": []
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user