iter form-a.1 (Tasks 6-12): milestone close

Second half of the form-a-default-authoring milestone-close iter
(Boss-decided strategy C, big-bang). All seven tasks DONE; cargo
test --workspace green at every per-task boundary.

T6 — Bench-driver suffix flip from .ail.json to .ail across 4
Python scripts + run.sh. compile_check.py + cross_lang.py exit 0.

T7 — Re-author e2e.rs raw-JSON-inspect tests:
- diff_detects_changed_def — derive sum.ail.json on-the-fly via
  `ail parse examples/sum.ail` into tempdir, then mutate + diff.
- borrow_own_demo_modes_are_metadata_only — same pattern.
- reuse_as_demo_under_rc_uses_inplace_rewrite — same pattern.
- render_parse_round_trip_canonical — RETIRED (subsumed by T1's
  cli_parse_then_render_then_parse_is_idempotent over whole corpus).
- ail_run_accepts_ail_source_with_same_stdout_as_ail_json —
  re-authored to derive hello.ail.json in a per-process tempdir
  from hello.ail via `ail parse`, then assert dual-form stdout.

T8 — Bulk-delete 156 non-carve-out .ail.json. Inventory:
8 .ail.json (carve-outs, alphabetical: broken_unbound + prelude
+ 3× test_22b2_* + 3× test_ct1_*) + 157 .ail. carve_out_inventory
test un-#[ignore]'d and green. Forward-pulled 20 repairs that the
T1-5 dispatch's recon missed (12 Group-B suffix + 5 Group-A
load_workspace + 3 ail_run sites). Also forward-pulled T9 Step 5
(schema_coverage corpus flip from .ail.json to .ail) to satisfy
T8's green-gate.

T9 — Retire obsolete roundtrip tests:
- print_then_parse_round_trips_every_fixture (round_trip.rs)
- every_ail_fixture_matches_its_json_counterpart (round_trip.rs)
- cli_render_then_parse_preserves_canonical_bytes_on_every_fixture
- Dead helpers: list_json_fixtures ×2, round_trip_one,
  strip_trailing_newlines.
Schema-coverage corpus already flipped in T8 (forward-pull).

T10 — DESIGN.md §"Roundtrip Invariant" (lines 2027-2109) restated
with parse-determinism + idempotency + CLI-pipeline-idempotency +
carve-out-anchor framing. Five surviving enforcement tests named.
§"Float literals" and §"Why anchored at top level" preserved.

T11 — §A4 doctrine edits: CLAUDE.md:5-6 + DESIGN.md:465-466.
Canonical form remains JSON-AST; authoring projection is .ail;
build derives JSON-AST in-process via ailang_surface::parse.

T12 — Milestone close:
- WhatsNew entry: user-facing language, lead with the change.
- Roadmap: [milestone] form-a struck [x] with closing note.
- Final inventory verified: 8 .ail.json + 157 .ail.
- Final cargo test --workspace: 557 passed, 0 failed, 3 ignored.
- bench/compile_check.py + bench/cross_lang.py: exit 0.

Test math: pre-iter 558 baseline + 3 new T1 tests = 561, − 1
(T7 retire) − 3 (T9 retire) = 557 final.

INDEX.md appended with the full iter summary covering T1-T12 (the
T1-5 commit at 77b28ad deferred the INDEX line to full-iter close).

Milestone [Form-A as the default authoring surface] structurally
closed. The compile-time-embed carve-out (prelude.ail.json) is
the subject of the queued follow-up milestone [Prelude embed:
Form-A as compile-time source]. audit-form-a runs as the next
dispatch.
This commit is contained in:
2026-05-13 11:31:39 +02:00
parent 9332d1e155
commit 9fdc4cacff
173 changed files with 551 additions and 6645 deletions
+7 -2
View File
@@ -2,8 +2,13 @@
AILang's only author is an LLM, not a human. It is designed for:
- **Machine readability over human readability.** Source of truth is
structured data (`.ail.json`), not text.
- **Machine readability over human readability.** The canonical,
hashable, content-addressed form is structured data (`.ail.json`);
the authoring projection is Form A (`.ail`). Authors write `.ail`;
the build derives the JSON-AST in-process via
`ailang_surface::parse`, gated by the round-trip invariant. The
two forms are byte-isomorphic — picking either does not change
the identity of the module.
- **Local reasoning.** Every definition carries its full type and
effect set, so a signature can be trusted without reading the body.
- **Provability.** Pure core, explicit algebraic effects.
+2 -2
View File
@@ -40,7 +40,7 @@ EXAMPLES = ROOT / "examples"
# Curated corpus. Pinned by name so the baseline keys are stable across
# example-directory churn. Each entry must have a corresponding
# `<name>.ail.json` under examples/.
# `<name>.ail` under examples/.
CORPUS = [
# Surface coverage: each fixture exercises a different feature set.
"hello", # IO baseline
@@ -98,7 +98,7 @@ def measure(num_runs: int) -> dict[str, dict[str, float]]:
try:
for fixture in CORPUS:
src = EXAMPLES / f"{fixture}.ail.json"
src = EXAMPLES / f"{fixture}.ail"
if not src.is_file():
print(f"missing fixture: {src}", file=sys.stderr)
sys.exit(2)
+2 -2
View File
@@ -45,7 +45,7 @@ REFERENCE = ROOT / "bench" / "reference"
OUTDIR = ROOT / "target" / "cross_lang"
# (ailang fixture stem, C reference stem) — both must exist as
# `examples/<ail>.ail.json` and `bench/reference/<c>.c`.
# `examples/<ail>.ail` and `bench/reference/<c>.c`.
CORPUS = [
("bench_list_sum", "list_sum"),
("bench_tree_walk", "tree_walk"),
@@ -77,7 +77,7 @@ def median_drop_slowest(runs: list[float]) -> float:
def build_ailang(stem: str, alloc: str) -> Path:
src = EXAMPLES / f"{stem}.ail.json"
src = EXAMPLES / f"{stem}.ail"
if not src.is_file():
print(f"missing AILang fixture: {src}", file=sys.stderr)
sys.exit(2)
+2 -2
View File
@@ -7,7 +7,7 @@
#
# What this harness measures:
# - AILang mono'd binary at -O2 --alloc=rc on
# examples/bench_mono_dispatch.ail.json
# examples/bench_mono_dispatch.ail
# - Hand-C reference, three variants:
# direct-inlinable — foo() inlinable, direct call
# direct-noinline — foo() noinline, direct call
@@ -109,7 +109,7 @@ def main() -> int:
ail_bin = OUTDIR / "bench_mono_dispatch_ail"
subprocess.run(
[str(AIL), "build", "--opt=-O2", "--alloc=rc",
str(EXAMPLES / "bench_mono_dispatch.ail.json"), "-o", str(ail_bin)],
str(EXAMPLES / "bench_mono_dispatch.ail"), "-o", str(ail_bin)],
check=True, capture_output=True,
)
@@ -3,28 +3,71 @@
"date": "2026-05-13",
"mode": "standard",
"outcome": "DONE",
"task_range": [1, 5],
"tasks_total": 5,
"tasks_completed": 5,
"reloops_per_task": {
"1": 0,
"2": 1,
"3": 0,
"4": 0,
"5": 0
},
"review_loops_spec": 0,
"review_loops_quality": 0,
"tasks_total": 12,
"tasks_completed": 12,
"dispatches": [
{
"task_range": [1, 5],
"outcome": "DONE",
"reloops_per_task": {
"1": 0,
"2": 1,
"3": 0,
"4": 0,
"5": 0
},
"review_loops_spec": 0,
"review_loops_quality": 0,
"notes": "Plan recon defect: load_workspace prefers .ail siblings since ext-cli.1, so bulk-render of .ail siblings broke 7 Group-A tests whose entry was .ail.json. Inline forward-pull of Task-3 migrations + 4 transient #[ignore]'s on workspace.rs mod tests (relocated cleanly in Task 5).",
"test_count_pre_dispatch": 558,
"test_count_post_dispatch": 560,
"test_count_ignored_post_dispatch": 4
},
{
"task_range": [6, 12],
"outcome": "DONE",
"reloops_per_task": {
"6": 0,
"7": 1,
"8": 1,
"9": 0,
"10": 0,
"11": 0,
"12": 0
},
"review_loops_spec": 0,
"review_loops_quality": 0,
"notes": {
"task7_reloop": "ail_run_accepts_ail_source_with_same_stdout_as_ail_json initial re-author used tempfile-with-PID-suffix path; loader name-checks module-name-vs-file-stem and rejected. Repaired to use per-process tempdir with hello.ail.json as basename.",
"task8_reloop": "Pre-T8 cargo-test green pre-deletion required pulling forward 20 stale-.ail.json-reference repairs that T1-5 missed: 12 `let example = X.ail.json` Group-B sites in e2e.rs + 5 ailang_core::load_workspace Group-A sites in e2e.rs + 3 ail_run Group-B sites in typeclass_22b3.rs. Post-deletion failure in schema_coverage required pulling T9 Step 5 (corpus flip + ailang_surface::load_module switch) forward into T8."
},
"test_count_pre_dispatch": 560,
"test_count_post_dispatch": 557,
"test_count_ignored_post_dispatch": 3,
"test_count_retired": "1 (T7: render_parse_round_trip_canonical) + 3 (T9: print_then_parse_round_trips_every_fixture, every_ail_fixture_matches_its_json_counterpart, cli_render_then_parse_preserves_canonical_bytes_on_every_fixture) = 4 total. Net: 560 + 1 (un-ignore carve_out_inventory) - 4 retired = 557."
}
],
"blocked_reason": null,
"notes": {
"task2_reloop": "Plan recon defect: load_workspace prefers .ail siblings since ext-cli.1, so bulk-render of .ail siblings broke 7 Group-A tests whose entry was .ail.json. Inline forward-pull of Task-3 migrations + 4 transient #[ignore]'s on workspace.rs mod tests (relocated cleanly in Task 5).",
"iter_totals": {
"test_count_pre_iter": 558,
"test_count_post_iter_half": 560,
"test_count_ignored_post_iter_half": 4,
"test_count_ignored_breakdown": "1 carve_out_inventory (T8 un-ignores) + 3 doctests (pre-existing)",
"test_count_post_iter": 557,
"test_count_ignored_post_iter": 3,
"corpus_ail_pre_iter": 58,
"corpus_ail_post_iter_half": 157,
"corpus_ail_json_post_iter_half": 164,
"corpus_ail_json_target_post_T8": 8
"corpus_ail_post_iter": 157,
"corpus_ail_json_pre_iter": 164,
"corpus_ail_json_post_iter": 8,
"carve_outs": [
"broken_unbound.ail.json",
"prelude.ail.json",
"test_22b2_invalid_superclass_param.ail.json",
"test_22b2_kind_mismatch.ail.json",
"test_22b2_unbound_constraint_var.ail.json",
"test_ct1_bad_qualifier.ail.json",
"test_ct1_bare_xmod_rejected.ail.json",
"test_ct1_qualified_class_rejected.ail.json"
],
"milestone_closed": "Form-A as the default authoring surface",
"bench_compile_check_exit": 0,
"bench_cross_lang_exit": 0
}
}
+3 -3
View File
@@ -65,7 +65,7 @@ fixtures=(bench_list_sum bench_tree_walk bench_closure_chain bench_hof_pipeline
modes=(gc bump rc)
echo ">>> compiling fixtures (-O2)"
for f in "${fixtures[@]}"; do
src="$ROOT/examples/$f.ail.json"
src="$ROOT/examples/$f.ail"
[[ -f "$src" ]] || { echo "missing fixture: $src" >&2; exit 1; }
for m in "${modes[@]}"; do
bin="$OUTDIR/${f}_${m}"
@@ -179,8 +179,8 @@ done
# was added in 18f.2 and may not exist on older branches that share
# this script).
LAT_HARNESS="$ROOT/bench/latency_harness.py"
LAT_IMPL_SRC="$ROOT/examples/bench_latency_implicit.ail.json"
LAT_EXPL_SRC="$ROOT/examples/bench_latency_explicit.ail.json"
LAT_IMPL_SRC="$ROOT/examples/bench_latency_implicit.ail"
LAT_EXPL_SRC="$ROOT/examples/bench_latency_explicit.ail"
if [[ -x "$LAT_HARNESS" && -f "$LAT_IMPL_SRC" && -f "$LAT_EXPL_SRC" ]]; then
echo
echo ">>> latency bench (PTY inter-arrival, 1000 samples per arm)"
+117 -71
View File
@@ -406,48 +406,12 @@ fn std_list_stress_1000_element_folds() {
);
}
/// Iter 15e: `ail render | ail parse` round-trips canonical bytes.
/// Property protected: the CLI's `render` is the exact inverse of
/// `parse`, not the older human-pretty form. Regression of this
/// would mean piping `render` into `parse` no longer yields a
/// re-loadable module — a contract the help text now claims.
///
/// Picks `std_either.ail.json` (richest fixture: 2-type-var data,
/// 3-type-var fn, recursive ctors irrelevant) but the round-trip
/// test in `ailang-surface` covers all 25 fixtures structurally.
/// This test specifically exercises the CLI shell pipeline.
#[test]
fn render_parse_round_trip_canonical() {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
let src = workspace.join("examples").join("std_either.ail.json");
let original = std::fs::read(&src).expect("read fixture");
let render = Command::new(ail_bin())
.args(["render", src.to_str().unwrap()])
.output()
.expect("run ail render");
assert!(render.status.success(), "ail render failed");
let tmp = std::env::temp_dir().join(format!("ailang_render_e2e_{}.ail", std::process::id()));
std::fs::write(&tmp, &render.stdout).expect("write rendered ail");
let parsed = Command::new(ail_bin())
.args(["parse", tmp.to_str().unwrap()])
.output()
.expect("run ail parse");
assert!(parsed.status.success(), "ail parse failed on rendered output");
let mut round = parsed.stdout;
while round.last() == Some(&b'\n') {
round.pop();
}
let mut orig = original;
while orig.last() == Some(&b'\n') {
orig.pop();
}
assert_eq!(orig, round, "render | parse must produce canonical bytes");
}
// Retired iter form-a.1 T7: `render_parse_round_trip_canonical` raw-read
// `std_either.ail.json` for the byte-roundtrip. The property it pinned
// (CLI render→parse byte-roundtrip) is now pinned across the entire
// `.ail` corpus by `cli_parse_then_render_then_parse_is_idempotent` in
// `crates/ail/tests/roundtrip_cli.rs` (added in T1), which is strictly
// stronger (whole-corpus vs. one-fixture).
/// Iter 16a: nested constructor patterns. Property protected:
/// `ailang_core::desugar` flattens `Cons a (Cons b _)` to a chain of
@@ -698,12 +662,33 @@ fn nested_let_rec_demo() {
fn diff_detects_changed_def() {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
let src_a = workspace.join("examples").join("sum.ail.json");
// Variant: load sum.ail.json, mutate the `then` branch (1 instead of 0)
// Form-A migration (iter form-a.1): derive the canonical JSON-AST
// from `sum.ail` via `ail parse` rather than reading a pre-existing
// `sum.ail.json` (which no longer exists post-iter). The variant is
// produced by mutating the parsed AST and writing it back as a JSON
// tempfile; `ail diff` runs against the two JSON tempfiles.
let tmp_a = std::env::temp_dir().join(format!(
"ailang_diff_src_{}.ail.json",
std::process::id()
));
let parse_status = Command::new(ail_bin())
.args([
"parse",
workspace.join("examples").join("sum.ail").to_str().unwrap(),
"-o",
tmp_a.to_str().unwrap(),
])
.status()
.expect("ail parse failed to run");
assert!(parse_status.success(), "ail parse failed on sum.ail");
let src_a = tmp_a.clone();
// Variant: load the derived JSON, mutate the `then` branch (1 instead of 0)
// in the `sum` definition. `main` stays bit-identical.
let raw = std::fs::read(&src_a).expect("read sum.ail.json");
let mut module: serde_json::Value = serde_json::from_slice(&raw).expect("parse sum.ail.json");
let raw = std::fs::read(&src_a).expect("read derived sum.ail.json");
let mut module: serde_json::Value =
serde_json::from_slice(&raw).expect("parse derived sum.ail.json");
{
let defs = module
.get_mut("defs")
@@ -1305,13 +1290,30 @@ fn unreachable_demo() {
/// wrappers, and the binary prints `3` then `6`.
#[test]
fn borrow_own_demo_modes_are_metadata_only() {
// Sanity-check (2): the on-disk JSON contains `param_modes`
// Sanity-check (2): the canonical JSON contains `param_modes`
// tokens for both fns. If the schema regressed and the field
// were dropped, this would fail before the binary even runs.
//
// Form-A migration (iter form-a.1): derive the JSON via `ail parse`
// on `borrow_own_demo.ail` rather than reading a pre-existing
// `.ail.json` (deleted post-iter).
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
let json_path = workspace.join("examples").join("borrow_own_demo.ail.json");
let json = std::fs::read_to_string(&json_path).expect("read borrow_own_demo.ail.json");
let tmp_json = std::env::temp_dir().join(format!(
"ailang_borrow_own_demo_{}.ail.json",
std::process::id()
));
let parse_status = Command::new(ail_bin())
.args([
"parse",
workspace.join("examples").join("borrow_own_demo.ail").to_str().unwrap(),
"-o",
tmp_json.to_str().unwrap(),
])
.status()
.expect("ail parse failed to run");
assert!(parse_status.success(), "ail parse failed on borrow_own_demo.ail");
let json = std::fs::read_to_string(&tmp_json).expect("read derived borrow_own_demo.ail.json");
assert!(
json.contains("\"param_modes\":[\"borrow\"]"),
"expected `param_modes:[\"borrow\"]` in canonical JSON; the schema for `(borrow T)` regressed"
@@ -1359,7 +1361,7 @@ fn eq_demo() {
#[test]
fn alloc_rc_produces_same_stdout_as_gc() {
// Pick a fixture with non-trivial allocation: list-building + match.
let example = "list.ail.json";
let example = "list.ail";
let stdout_gc = build_and_run_with_alloc(example, "gc");
let stdout_rc = build_and_run_with_alloc(example, "rc");
assert_eq!(stdout_gc, stdout_rc, "alloc=rc must match alloc=gc");
@@ -1405,8 +1407,26 @@ fn clone_demo_is_identity_in_18c1() {
fn reuse_as_demo_under_rc_uses_inplace_rewrite() {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
let json_path = workspace.join("examples").join("reuse_as_demo.ail.json");
let json = std::fs::read_to_string(&json_path).expect("read reuse_as_demo.ail.json");
let ail_path = workspace.join("examples").join("reuse_as_demo.ail");
// Form-A migration (iter form-a.1): derive the canonical JSON-AST
// via `ail parse` on `reuse_as_demo.ail` rather than reading a
// pre-existing `.ail.json` (deleted post-iter).
let tmp_json = std::env::temp_dir().join(format!(
"ailang_reuse_as_demo_{}.ail.json",
std::process::id()
));
let parse_status = Command::new(ail_bin())
.args([
"parse",
ail_path.to_str().unwrap(),
"-o",
tmp_json.to_str().unwrap(),
])
.status()
.expect("ail parse failed to run");
assert!(parse_status.success(), "ail parse failed on reuse_as_demo.ail");
let json = std::fs::read_to_string(&tmp_json).expect("read derived reuse_as_demo.ail.json");
assert!(
json.contains("\"t\":\"reuse-as\""),
"expected `\"t\":\"reuse-as\"` in canonical JSON; the schema for `(reuse-as ...)` regressed"
@@ -1422,8 +1442,10 @@ fn reuse_as_demo_under_rc_uses_inplace_rewrite() {
// (5) Inspect the rc IR text. We re-lower via the codegen API
// directly so the assertion runs without depending on the
// filesystem layout of `ail build`'s tmpdir.
let ws = ailang_core::load_workspace(&json_path).expect("load workspace");
// filesystem layout of `ail build`'s tmpdir. Use the
// extension-dispatching `ailang_surface::load_workspace` so
// the `.ail` entry is accepted.
let ws = ailang_surface::load_workspace(&ail_path).expect("load workspace");
let mut lifted_modules = std::collections::BTreeMap::new();
for (mname, m) in &ws.modules {
let desugared = ailang_core::desugar::desugar_module(m);
@@ -1496,7 +1518,7 @@ fn reuse_as_demo_under_rc_uses_inplace_rewrite() {
/// invariant: stdout must be byte-identical to the `gc` build.
#[test]
fn alloc_rc_matches_gc_on_std_list_demo() {
let example = "std_list_demo.ail.json";
let example = "std_list_demo.ail";
let stdout_gc = build_and_run_with_alloc(example, "gc");
let stdout_rc = build_and_run_with_alloc(example, "rc");
assert_eq!(
@@ -1531,7 +1553,7 @@ fn alloc_rc_matches_gc_on_std_list_demo() {
/// this iter.
#[test]
fn alloc_rc_emits_dec_for_unique_let_bound_box() {
let example = "rc_box_drop.ail.json";
let example = "rc_box_drop.ail";
let stdout_gc = build_and_run_with_alloc(example, "gc");
let stdout_rc = build_and_run_with_alloc(example, "rc");
assert_eq!(stdout_gc.trim(), "42");
@@ -1557,7 +1579,7 @@ fn alloc_rc_emits_dec_for_unique_let_bound_box() {
/// the dec path itself.
#[test]
fn alloc_rc_recursive_list_sum() {
let example = "rc_list_drop.ail.json";
let example = "rc_list_drop.ail";
let stdout_gc = build_and_run_with_alloc(example, "gc");
let stdout_rc = build_and_run_with_alloc(example, "rc");
assert_eq!(stdout_gc.trim(), "15");
@@ -1602,7 +1624,7 @@ fn alloc_rc_recursive_list_sum() {
/// pattern-binder dec.
#[test]
fn alloc_rc_borrow_only_recursive_list_drop() {
let example = "rc_list_drop_borrow.ail.json";
let example = "rc_list_drop_borrow.ail";
let stdout_gc = build_and_run_with_alloc(example, "gc");
let stdout_rc = build_and_run_with_alloc(example, "rc");
assert_eq!(stdout_gc.trim(), "11");
@@ -1622,7 +1644,7 @@ fn alloc_rc_borrow_only_recursive_list_drop() {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
let json_path = workspace.join("examples").join(example);
let ws = ailang_core::load_workspace(&json_path).expect("load workspace");
let ws = ailang_surface::load_workspace(&json_path).expect("load workspace");
let mut lifted_modules = std::collections::BTreeMap::new();
for (mname, m) in &ws.modules {
let desugared = ailang_core::desugar::desugar_module(m);
@@ -1684,7 +1706,7 @@ fn alloc_rc_borrow_only_recursive_list_drop() {
/// `drop_<m>_Pair` call against `p`.
#[test]
fn alloc_rc_partial_drop_skips_moved_keeps_wildcarded() {
let example = "pat_extract_partial_drop.ail.json";
let example = "pat_extract_partial_drop.ail";
let stdout_gc = build_and_run_with_alloc(example, "gc");
let stdout_rc = build_and_run_with_alloc(example, "rc");
assert_eq!(stdout_gc.trim(), "6");
@@ -1698,7 +1720,7 @@ fn alloc_rc_partial_drop_skips_moved_keeps_wildcarded() {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
let json_path = workspace.join("examples").join(example);
let ws = ailang_core::load_workspace(&json_path).expect("load workspace");
let ws = ailang_surface::load_workspace(&json_path).expect("load workspace");
let mut lifted_modules = std::collections::BTreeMap::new();
for (mname, m) in &ws.modules {
let desugared = ailang_core::desugar::desugar_module(m);
@@ -1774,7 +1796,7 @@ fn alloc_rc_partial_drop_skips_moved_keeps_wildcarded() {
/// that ANY drop fires.
#[test]
fn alloc_rc_own_param_dec_at_fn_return() {
let example = "rc_own_param_drop.ail.json";
let example = "rc_own_param_drop.ail";
let stdout_gc = build_and_run_with_alloc(example, "gc");
let stdout_rc = build_and_run_with_alloc(example, "rc");
assert_eq!(stdout_gc.trim(), "11");
@@ -1788,7 +1810,7 @@ fn alloc_rc_own_param_dec_at_fn_return() {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
let json_path = workspace.join("examples").join(example);
let ws = ailang_core::load_workspace(&json_path).expect("load workspace");
let ws = ailang_surface::load_workspace(&json_path).expect("load workspace");
let mut lifted_modules = std::collections::BTreeMap::new();
for (mname, m) in &ws.modules {
let desugared = ailang_core::desugar::desugar_module(m);
@@ -1891,7 +1913,7 @@ fn alloc_rc_own_param_dec_at_fn_return() {
/// capacity).
#[test]
fn alloc_rc_drop_iterative_handles_million_cell_list() {
let example = "rc_drop_iterative_long_list.ail.json";
let example = "rc_drop_iterative_long_list.ail";
let stdout_gc = build_and_run_with_alloc(example, "gc");
let stdout_rc = build_and_run_with_alloc(example, "rc");
assert_eq!(stdout_rc.trim(), "1");
@@ -1910,11 +1932,11 @@ fn alloc_rc_drop_iterative_handles_million_cell_list() {
/// dispatch.
#[test]
fn iter18e_drop_iterative_emits_worklist_body_no_self_recursion() {
let example = "rc_drop_iterative_long_list.ail.json";
let example = "rc_drop_iterative_long_list.ail";
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
let json_path = workspace.join("examples").join(example);
let ws = ailang_core::load_workspace(&json_path).expect("load workspace");
let ws = ailang_surface::load_workspace(&json_path).expect("load workspace");
let mut lifted_modules = std::collections::BTreeMap::new();
for (mname, m) in &ws.modules {
let desugared = ailang_core::desugar::desugar_module(m);
@@ -1987,11 +2009,11 @@ fn iter18e_drop_iterative_emits_worklist_body_no_self_recursion() {
/// of any on-disk fixture changes.
#[test]
fn iter18e_no_annotation_keeps_recursive_drop_body() {
let example = "rc_drop_iterative_long_list.ail.json";
let example = "rc_drop_iterative_long_list.ail";
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
let json_path = workspace.join("examples").join(example);
let ws = ailang_core::load_workspace(&json_path).expect("load workspace");
let ws = ailang_surface::load_workspace(&json_path).expect("load workspace");
// Mutate every TypeDef in every module to clear the annotation.
let mut modules = std::collections::BTreeMap::new();
for (mname, m) in &ws.modules {
@@ -2066,7 +2088,7 @@ fn iter18e_no_annotation_keeps_recursive_drop_body() {
/// regression coverage — see CLAUDE.md "Bug fixes — TDD, always".
#[test]
fn alloc_rc_pattern_bind_in_implicit_fn_does_not_dec_borrowed_children() {
let example = "rc_pin_recurse_implicit.ail.json";
let example = "rc_pin_recurse_implicit.ail";
let stdout_gc = build_and_run_with_alloc(example, "gc");
let stdout_rc = build_and_run_with_alloc(example, "rc");
assert_eq!(stdout_gc.trim(), "0");
@@ -2294,7 +2316,7 @@ fn alloc_rc_let_binder_for_implicit_returning_app_does_not_drop() {
/// the arm-close drop. Output matches `--alloc=gc` (`0`).
#[test]
fn alloc_rc_let_alias_of_implicit_param_does_not_dec_borrowed_children() {
let example = "rc_let_alias_implicit_param.ail.json";
let example = "rc_let_alias_implicit_param.ail";
let stdout_gc = build_and_run_with_alloc(example, "gc");
let stdout_rc = build_and_run_with_alloc(example, "rc");
assert_eq!(stdout_gc.trim(), "0");
@@ -2524,11 +2546,35 @@ fn ail_check_accepts_ail_source() {
/// counterpart. Guards against the surface→core dispatch silently
/// rewriting the loaded `Module` (e.g. losing imports, dropping defs,
/// re-ordering fields) — the binary semantics must be form-agnostic.
///
/// Form-A migration (iter form-a.1): only the eight carve-out fixtures
/// keep `.ail.json` form on disk post-iter. To preserve the dual-form
/// property test, derive a parallel `.ail.json` in a tempdir from
/// `hello.ail` via `ail parse`, then build and run both forms.
#[test]
fn ail_run_accepts_ail_source_with_same_stdout_as_ail_json() {
let ail_path = workspace_root().join("examples/hello.ail");
let json_path = workspace_root().join("examples/hello.ail.json");
assert!(ail_path.is_file());
// The loader name-checks the module name against the file stem, so
// the derived JSON must be named `hello.ail.json` even in the temp
// location. Use a per-process tempdir to avoid races.
let tmpdir = std::env::temp_dir().join(format!(
"ailang_dual_form_{}",
std::process::id()
));
std::fs::create_dir_all(&tmpdir).unwrap();
let json_path = tmpdir.join("hello.ail.json");
let parse_status = Command::new(ail_bin())
.args([
"parse",
ail_path.to_str().unwrap(),
"-o",
json_path.to_str().unwrap(),
])
.status()
.expect("ail parse failed to run");
assert!(parse_status.success(), "ail parse failed on hello.ail");
assert!(json_path.is_file());
let build_and_capture = |src: &Path| -> Vec<u8> {
+12 -121
View File
@@ -1,16 +1,24 @@
//! CLI roundtrip: every `examples/*.ail.json` survives
//! `ail render` → tempfile → `ail parse` with BLAKE3 hash
//! identity on canonical bytes.
//! CLI-pipeline idempotency gate: every `examples/*.ail` survives
//! `ail parse | ail render | ail parse` with byte identity on the
//! canonical JSON output.
//!
//! This is the user-facing-surface defence line. Crate-internal
//! roundtrip tests in `ailang-surface` cover the same property
//! at the library level; this test additionally protects the
//! `ail render` and `ail parse` CLI wrappers from drift (output
//! `ail parse` and `ail render` CLI wrappers from drift (output
//! formatting, exit codes, stdout framing).
//!
//! Pure reader: the test writes only to a `tempfile::TempDir`
//! that lives outside the repo and is cleaned up by Drop. No
//! committed content is mutated.
//!
//! Retired iter form-a.1 T9:
//! `cli_render_then_parse_preserves_canonical_bytes_on_every_fixture`
//! (walked `.ail.json` corpus; replaced by the corpus-flipped
//! `cli_parse_then_render_then_parse_is_idempotent` below, added in
//! T1). The `list_json_fixtures` helper and `roundtrip_one` helper
//! were the only consumers of `.ail.json` walks and are retired
//! alongside.
use std::path::{Path, PathBuf};
use std::process::Command;
@@ -28,23 +36,6 @@ fn examples_dir() -> PathBuf {
workspace_root().join("examples")
}
fn list_json_fixtures() -> Vec<PathBuf> {
let dir = examples_dir();
let mut paths: Vec<PathBuf> = std::fs::read_dir(&dir)
.unwrap_or_else(|e| panic!("read_dir({}): {e}", dir.display()))
.filter_map(|entry| entry.ok())
.map(|e| e.path())
.filter(|p| {
p.file_name()
.and_then(|n| n.to_str())
.map(|n| n.ends_with(".ail.json"))
.unwrap_or(false)
})
.collect();
paths.sort();
paths
}
fn list_ail_fixtures() -> Vec<PathBuf> {
let dir = examples_dir();
let mut paths: Vec<PathBuf> = std::fs::read_dir(&dir)
@@ -62,106 +53,6 @@ fn list_ail_fixtures() -> Vec<PathBuf> {
paths
}
fn strip_trailing_newlines(mut v: Vec<u8>) -> Vec<u8> {
while v.last() == Some(&b'\n') {
v.pop();
}
v
}
/// Run the full render → parse pipeline for one fixture. Returns
/// Ok(()) on hash-identity, Err(reason) otherwise.
fn roundtrip_one(fixture: &Path, tmpdir: &Path) -> Result<(), String> {
// Step A: load the original fixture and compute canonical bytes
// (independent of how the JSON file is formatted on disk).
let original_module = ailang_core::load_module(fixture)
.map_err(|e| format!("load_module: {e}"))?;
let bytes_orig = ailang_core::canonical::to_bytes(&original_module);
let h_orig = blake3::hash(&bytes_orig);
// Step B: `ail render <fixture>` → captured stdout = ail text.
let render_out = Command::new(ail_bin())
.args(["render", fixture.to_str().unwrap()])
.output()
.map_err(|e| format!("spawn ail render: {e}"))?;
if !render_out.status.success() {
return Err(format!(
"ail render exit={:?}\nstderr: {}",
render_out.status.code(),
String::from_utf8_lossy(&render_out.stderr),
));
}
// Step C: write the rendered .ail into the tempdir.
let stem = fixture
.file_name()
.and_then(|n| n.to_str())
.and_then(|n| n.strip_suffix(".ail.json"))
.unwrap_or("fixture");
let tmp_ail = tmpdir.join(format!("{stem}.round.ail"));
std::fs::write(&tmp_ail, &render_out.stdout)
.map_err(|e| format!("write tempfile {}: {e}", tmp_ail.display()))?;
// Step D: `ail parse <tmp_ail>` → captured stdout = canonical
// bytes + trailing newline.
let parse_out = Command::new(ail_bin())
.args(["parse", tmp_ail.to_str().unwrap()])
.output()
.map_err(|e| format!("spawn ail parse: {e}"))?;
if !parse_out.status.success() {
return Err(format!(
"ail parse exit={:?}\nstderr: {}",
parse_out.status.code(),
String::from_utf8_lossy(&parse_out.stderr),
));
}
let bytes_round = strip_trailing_newlines(parse_out.stdout);
let h_round = blake3::hash(&bytes_round);
if h_orig != h_round {
let s_orig = String::from_utf8_lossy(&bytes_orig).into_owned();
let s_round = String::from_utf8_lossy(&bytes_round).into_owned();
return Err(format!(
"BLAKE3 mismatch:\n orig: {}\n round: {}\noriginal bytes: {s_orig}\nround bytes: {s_round}",
h_orig.to_hex(),
h_round.to_hex(),
));
}
Ok(())
}
#[test]
fn cli_render_then_parse_preserves_canonical_bytes_on_every_fixture() {
let fixtures = list_json_fixtures();
assert!(
!fixtures.is_empty(),
"no .ail.json fixtures found under {}",
examples_dir().display()
);
let tmpdir = tempfile::TempDir::new().expect("create tempdir");
let mut failures = Vec::<String>::new();
let mut passed = 0usize;
for fixture in &fixtures {
match roundtrip_one(fixture, tmpdir.path()) {
Ok(()) => passed += 1,
Err(msg) => failures.push(format!("{}: {msg}", fixture.display())),
}
}
if !failures.is_empty() {
panic!(
"CLI roundtrip failed for {} of {} fixtures (passed: {}):\n{}",
failures.len(),
fixtures.len(),
passed,
failures.join("\n\n")
);
}
eprintln!("CLI roundtrip ok for {passed} fixtures");
}
/// CLI-pipeline idempotency (post-form-a-default-authoring §C3): for
/// every `.ail` fixture, the user-facing pipeline
/// `ail parse <ail> | ail render | ail parse` is byte-identical
+3 -3
View File
@@ -741,7 +741,7 @@ fn ail_run(fixture_name: &str) -> (std::process::Output, String) {
/// failure — all observable at stdout. Defends mono-pass invariant 3.
#[test]
fn coherence_two_instances_pick_correct_body_at_runtime() {
let (output, stdout) = ail_run("test_22b3_coherence_two_instances.ail.json");
let (output, stdout) = ail_run("test_22b3_coherence_two_instances.ail");
assert!(
output.status.success(),
"ail run failed: stdout={}, stderr={}",
@@ -767,7 +767,7 @@ fn coherence_two_instances_pick_correct_body_at_runtime() {
/// constant 99 must reach stdout. Defends mono-pass invariant 4.
#[test]
fn class_default_method_runs_and_prints_default_value() {
let (output, stdout) = ail_run("test_22b3_default_e2e.ail.json");
let (output, stdout) = ail_run("test_22b3_default_e2e.ail");
assert!(
output.status.success(),
"ail run failed: stdout={}, stderr={}",
@@ -795,7 +795,7 @@ fn class_default_method_runs_and_prints_default_value() {
/// Defends mono-pass invariant 6.
#[test]
fn cross_module_class_method_runs_and_prints_correct_value() {
let (output, stdout) = ail_run("test_22b3_xmod_e2e_main.ail.json");
let (output, stdout) = ail_run("test_22b3_xmod_e2e_main.ail");
assert!(
output.status.success(),
"ail run failed: stdout={}, stderr={}",
@@ -31,7 +31,6 @@ fn examples_dir() -> std::path::PathBuf {
}
#[test]
#[ignore = "GREEN-ratified by Task 8 (.ail.json deletion); RED until then"]
fn examples_ail_json_inventory_matches_carve_outs() {
let expected: BTreeSet<&str> = EXPECTED.iter().copied().collect();
let mut actual: BTreeSet<String> = BTreeSet::new();
+5 -5
View File
@@ -326,7 +326,7 @@ fn examples_dir() -> PathBuf {
crate_dir.parent().unwrap().parent().unwrap().join("examples")
}
fn list_json_fixtures() -> Vec<PathBuf> {
fn list_ail_fixtures() -> Vec<PathBuf> {
let dir = examples_dir();
let mut paths: Vec<PathBuf> = std::fs::read_dir(&dir)
.unwrap_or_else(|e| panic!("read_dir({}): {e}", dir.display()))
@@ -335,7 +335,7 @@ fn list_json_fixtures() -> Vec<PathBuf> {
.filter(|p| {
p.file_name()
.and_then(|n| n.to_str())
.map(|n| n.ends_with(".ail.json"))
.map(|n| n.ends_with(".ail"))
.unwrap_or(false)
})
.collect();
@@ -345,10 +345,10 @@ fn list_json_fixtures() -> Vec<PathBuf> {
#[test]
fn every_ast_variant_is_observed_in_the_fixture_corpus() {
let fixtures = list_json_fixtures();
let fixtures = list_ail_fixtures();
assert!(
!fixtures.is_empty(),
"no .ail.json fixtures found under {}",
"no .ail fixtures found under {}",
examples_dir().display()
);
@@ -356,7 +356,7 @@ fn every_ast_variant_is_observed_in_the_fixture_corpus() {
let mut load_failures = Vec::<String>::new();
for path in &fixtures {
match ailang_core::load_module(path) {
match ailang_surface::load_module(path) {
Ok(m) => visit_module(&m, &mut observed),
Err(e) => load_failures.push(format!("{}: {e}", path.display())),
}
+27 -170
View File
@@ -1,29 +1,30 @@
//! Round-trip gate for the form-(A) projection.
//!
//! Three complementary checks over `examples/`, each gathering
//! Two complementary checks over `examples/*.ail`, each gathering
//! fixtures dynamically via `read_dir` (no hardcoded lists). The
//! tests are pure readers — they do not write into the working
//! tree.
//!
//! 1. `print_then_parse_round_trips_every_fixture`: Direction 1 of
//! the Roundtrip Invariant (DESIGN.md §"Roundtrip Invariant").
//! For every `examples/*.ail.json` fixture, load → `print` →
//! `parse` → canonical bytes; assert byte-equal to original.
//! 1. `parse_is_deterministic_over_every_ail_fixture`: for every
//! well-formed `.ail` text `t`, `parse(t)` produces the same
//! canonical bytes every invocation. The parser is a pure
//! function of input — no randomness, no time dependence, no
//! environment leak. Hashing `canonical::to_bytes(parse(t))` is
//! therefore well-defined for any `.ail` source.
//!
//! 2. `every_ail_fixture_matches_its_json_counterpart`: hand-
//! authored ground-truth check. For every `examples/*.ail`
//! fixture, parse → canonical bytes; if a same-stem `.ail.json`
//! counterpart exists, assert canonical-byte equality against
//! it. Pins the `.ail` corpus against semantic drift between
//! the two forms at the fixture level.
//! 2. `parse_then_print_then_parse_is_idempotent_on_every_ail_fixture`:
//! Direction 2 of the Roundtrip Invariant (DESIGN.md §"Roundtrip
//! Invariant"). For every well-formed `.ail` text `t`, asserts
//! `canonical_bytes(parse(t))` equals
//! `canonical_bytes(parse(print(parse(t))))`. The printer is a
//! left-inverse of the parser modulo canonical form.
//!
//! 3. `parse_then_print_then_parse_is_idempotent_on_every_ail_fixture`:
//! Direction 2 of the Roundtrip Invariant. For every well-formed
//! `.ail` text `t`, asserts `canonical_bytes(parse(t))` equals
//! `canonical_bytes(parse(print(parse(t))))`. Robust against
//! future `.ail` fixtures without a JSON counterpart.
//! Retired iter form-a.1 T9: `print_then_parse_round_trips_every_fixture`
//! (corpus shrunk to 8 carve-outs post-iter) and
//! `every_ail_fixture_matches_its_json_counterpart` (no longer
//! expressible: only one form is hand-authored post-iter).
use std::path::{Path, PathBuf};
use std::path::PathBuf;
fn examples_dir() -> PathBuf {
// `CARGO_MANIFEST_DIR` is the surface crate root; examples live two
@@ -32,73 +33,15 @@ fn examples_dir() -> PathBuf {
crate_dir.parent().unwrap().parent().unwrap().join("examples")
}
fn list_json_fixtures() -> Vec<PathBuf> {
let dir = examples_dir();
let mut paths: Vec<PathBuf> = std::fs::read_dir(&dir)
.unwrap_or_else(|e| panic!("read_dir({}): {e}", dir.display()))
.filter_map(|entry| entry.ok())
.map(|e| e.path())
.filter(|p| {
p.file_name()
.and_then(|n| n.to_str())
.map(|n| {
// Round-trip every fixture. The 22b.1/22b.2/22b.3 filter
// was retired in 22b.4a once the Form-A parser+printer
// arms for ClassDef / InstanceDef landed.
n.ends_with(".ail.json")
})
.unwrap_or(false)
})
.collect();
paths.sort();
paths
}
#[test]
fn print_then_parse_round_trips_every_fixture() {
let fixtures = list_json_fixtures();
assert!(
!fixtures.is_empty(),
"no .ail.json fixtures found under {}",
examples_dir().display()
);
let mut failures = Vec::<String>::new();
let mut passed = 0usize;
for path in &fixtures {
match round_trip_one(path) {
Ok(()) => passed += 1,
Err(msg) => failures.push(format!("{}: {msg}", path.display())),
}
}
if !failures.is_empty() {
panic!(
"round-trip failed for {} of {} fixtures (passed: {}):\n{}",
failures.len(),
fixtures.len(),
passed,
failures.join("\n")
);
}
eprintln!("round-trip ok for {passed} fixtures");
}
fn round_trip_one(path: &Path) -> Result<(), String> {
let original = ailang_core::load_module(path).map_err(|e| format!("load: {e}"))?;
let text = ailang_surface::print(&original);
let parsed = ailang_surface::parse(&text)
.map_err(|e| format!("re-parse failed: {e}\n--- printed text ---\n{text}"))?;
let bytes_orig = ailang_core::canonical::to_bytes(&original);
let bytes_round = ailang_core::canonical::to_bytes(&parsed);
if bytes_orig != bytes_round {
let s_orig = String::from_utf8_lossy(&bytes_orig).into_owned();
let s_round = String::from_utf8_lossy(&bytes_round).into_owned();
return Err(format!(
"canonical bytes differ.\noriginal: {s_orig}\nround: {s_round}"
));
}
Ok(())
}
// Retired iter form-a.1 T9:
// - `list_json_fixtures` helper (walked `.ail.json` for the two retired tests below).
// - `print_then_parse_round_trips_every_fixture`: corpus shrunk to 8 carve-outs
// post-iter; property subsumed by `parse_is_deterministic_over_every_ail_fixture`
// plus the surviving `parse_then_print_then_parse_is_idempotent_on_every_ail_fixture`.
// - `round_trip_one` helper (only consumer was the retired test above).
// - `every_ail_fixture_matches_its_json_counterpart`: no longer expressible —
// only one form is hand-authored post-iter; counterparts are derived in-process
// via `ail parse`.
fn list_ail_fixtures() -> Vec<PathBuf> {
let dir = examples_dir();
@@ -117,92 +60,6 @@ fn list_ail_fixtures() -> Vec<PathBuf> {
paths
}
#[test]
fn every_ail_fixture_matches_its_json_counterpart() {
let fixtures = list_ail_fixtures();
assert!(
!fixtures.is_empty(),
"no .ail fixtures found under {}",
examples_dir().display()
);
let mut failures = Vec::<String>::new();
let mut paired = 0usize;
let mut parse_only = 0usize;
for ail_path in &fixtures {
let text = match std::fs::read_to_string(ail_path) {
Ok(t) => t,
Err(e) => {
failures.push(format!("{}: read failed: {e}", ail_path.display()));
continue;
}
};
let parsed = match ailang_surface::parse(&text) {
Ok(m) => m,
Err(e) => {
failures.push(format!("{}: parse failed: {e}", ail_path.display()));
continue;
}
};
// Same-stem counterpart lookup. `<stem>.ail` → `<stem>.ail.json`.
let stem = ail_path
.file_name()
.and_then(|n| n.to_str())
.and_then(|n| n.strip_suffix(".ail"))
.unwrap_or("");
let json_path = ail_path.with_file_name(format!("{stem}.ail.json"));
if !json_path.exists() {
// Spec: parse success alone is sufficient for `.ail` files
// without a JSON counterpart. (Today: none expected.)
parse_only += 1;
continue;
}
let original = match ailang_core::load_module(&json_path) {
Ok(m) => m,
Err(e) => {
failures.push(format!(
"{}: load_module({}) failed: {e}",
ail_path.display(),
json_path.display()
));
continue;
}
};
let bytes_orig = ailang_core::canonical::to_bytes(&original);
let bytes_parsed = ailang_core::canonical::to_bytes(&parsed);
if bytes_orig != bytes_parsed {
let s_orig = String::from_utf8_lossy(&bytes_orig).into_owned();
let s_round = String::from_utf8_lossy(&bytes_parsed).into_owned();
failures.push(format!(
"{} vs {}: canonical bytes differ.\noriginal: {s_orig}\nparsed: {s_round}",
ail_path.display(),
json_path.display()
));
continue;
}
paired += 1;
}
if !failures.is_empty() {
panic!(
"{} of {} .ail fixture(s) failed cross-check (paired ok: {}, parse-only: {}):\n{}",
failures.len(),
fixtures.len(),
paired,
parse_only,
failures.join("\n\n")
);
}
eprintln!(
".ail cross-check ok ({} paired, {} parse-only)",
paired, parse_only
);
}
/// Direction 2 of the Roundtrip Invariant (DESIGN.md §"Roundtrip
/// Invariant"): for every well-formed `.ail` text `t`, the
/// composition `parse → print → parse` is idempotent on the AST.
+55 -37
View File
@@ -462,8 +462,14 @@ on the shelf for a future iter only if both fail.
### What this Decision deliberately does not do
- It does not promote form (A) to the source of truth. Form (A) is
one projection; the JSON-AST stays canonical.
- It does not change which form is canonical: the JSON-AST remains
the hashable, content-addressed representation, and all hashing,
content-addressing, and cross-module references flow through it
unchanged. What did change in 2026-05-13 (this milestone) is
which form is authored: authors now write Form A; the JSON-AST
is materialised in-process by callers that need it. The two
forms are byte-isomorphic by the round-trip invariant. Form (A)
is one projection; the JSON-AST stays canonical.
- It does not foreclose visual or graphical front-ends. The crate
layout (`core` owns AST; `surface`/`visual`/... are siblings)
reserves that lane.
@@ -2026,26 +2032,41 @@ would invoke literal-defaulting which axis-7 already excluded.
## Roundtrip Invariant
Every well-formed AILang module has both a canonical `.ail.json`
representation and a textual `.ail` representation, and the two
are exact projections of the same AST. Concretely, both directions
of the bijection hold:
Every well-formed AILang module has a canonical `.ail.json`
representation (the hashable, content-addressed JSON-AST) and a
hand-authored `.ail` representation (Form A, the authoring
projection). The JSON-AST is derived from `.ail` in-process by
consumers that need it; the round-trip is now the *property* of
that derivation, not the byte-level agreement of two on-disk forms.
1. **JSON → text → JSON.** For every valid `.ail.json` module `J`,
`parse(print(load_module(J)))` is canonical-byte-equal to
`canonical::to_bytes(load_module(J))`. The textual surface is
the inverse of the loader composed with the printer; no
information is lost across the round-trip.
2. **text → JSON → text.** For every well-formed `.ail` text `t`,
`parse(t)` is a complete AST, and re-printing `print(parse(t))`
produces a text that re-parses to the same AST (modulo
formatting). The parser is total over the well-formed surface
and the printer is deterministic.
Concretely:
1. **Parse-determinism.** For every well-formed `.ail` text `t`,
`ailang_surface::parse(t)` produces a unique AST. The parser is
a pure function of input — no randomness, no time dependence,
no environment leak. Hashing `canonical::to_bytes(parse(t))` is
therefore well-defined for any `.ail` source.
2. **Idempotency under print.** For every well-formed `.ail` text
`t`, `canonical(parse(t)) == canonical(parse(print(parse(t))))`.
The printer is a left-inverse of the parser modulo canonical
form: print-then-parse is a no-op on the canonical bytes.
3. **CLI-pipeline idempotency.** For every `.ail` fixture, the
public CLI pipeline `ail parse | ail render | ail parse` is
byte-identical to direct `ail parse` of the source `.ail`.
Pins drift that crate-internal tests cannot see.
4. **Carve-out anchor.** Eight `.ail.json`-only fixtures (seven
subject-matter rejection tests + one compile-time-embed for
the prelude) survive in the corpus by structural necessity.
They participate in their own dedicated rejection-shape or
embed-mechanism tests, not in the round-trip gate.
Hashing is the consequence the language depends on: BLAKE3 of the
canonical bytes is identical for the two paths, so content-
addressing is form-agnostic. An LLM author can pick either form
without changing the identity of the module it produces.
canonical bytes is well-defined for any `.ail` source via parse-
determinism. An LLM author writes `.ail`; the build derives the
canonical hash without ambiguity.
### Float literals are inside the invariant
@@ -2065,29 +2086,26 @@ operating on the `examples/` corpus via dynamic `read_dir`
collection (no hardcoded fixture list, so newly added fixtures
inherit the gate automatically):
- `crates/ailang-surface/tests/round_trip.rs::print_then_parse_round_trips_every_fixture`
— for every `.ail.json`, `print` then `parse` produces canonical-
byte-equal output. Direction 1 above.
- `crates/ailang-surface/tests/round_trip.rs::parse_is_deterministic_over_every_ail_fixture`
— for every `.ail`, parse twice and assert canonical-byte
equality between the two ASTs. Direction 1 above.
- `crates/ailang-surface/tests/round_trip.rs::parse_then_print_then_parse_is_idempotent_on_every_ail_fixture`
— for every `.ail` text `t`, `parse(t)` and `parse(print(parse(t)))`
produce canonical-byte-equal AST. Direction 2 above.
- `crates/ailang-surface/tests/round_trip.rs::every_ail_fixture_matches_its_json_counterpart`
— for every `.ail` with a same-stem `.ail.json` counterpart,
`parse` of the text yields canonical bytes equal to the JSON
counterpart. Pins the hand-authored `.ail` corpus against
drift between the two forms at the fixture level.
- `crates/ail/tests/roundtrip_cli.rs::cli_parse_then_render_then_parse_is_idempotent`
— for every `.ail`, the public CLI pipeline `ail parse | ail render | ail parse`
reproduces canonical bytes byte-identical to direct `ail parse`.
Pins drift internal tests cannot see.
- `crates/ailang-core/tests/schema_coverage.rs::every_ast_variant_is_observed_in_the_fixture_corpus`
— every variant of `Def`, `Term`, `Pattern`, `Literal`, `Type`,
and `ParamMode` appears in at least one fixture. The visitor
matches each AST enum exhaustively without wildcard arms, so
any new AST variant fails to compile until the visitor is
extended in lockstep — the coverage table cannot silently fall
behind the schema.
- `crates/ail/tests/roundtrip_cli.rs::cli_render_then_parse_preserves_canonical_bytes_on_every_fixture`
— for every `.ail.json`, the public CLI pipeline `ail render` →
tempfile → `ail parse` reproduces BLAKE3-identical canonical
bytes. Pins the user-facing CLI against drift that crate-
internal tests cannot see.
and `ParamMode` appears in at least one `.ail` fixture (corpus
flipped from `.ail.json` to `.ail` at iter form-a.1). New AST
variants fail compile until the visitor and corpus are extended
in lockstep.
- `crates/ailang-core/tests/carve_out_inventory.rs::examples_ail_json_inventory_matches_carve_outs`
— exactly the eight named carve-out files exist under
`examples/*.ail.json` at any commit. A new `.ail.json` or a
missing carve-out fails the test.
A new fixture or a new AST variant that violates the invariant
fails one of these tests; the fix is in render or parse code,
+6
View File
@@ -118,3 +118,9 @@ The per-type `io/print_int`, `io/print_bool`, `io/print_float` operators stay fo
Bench continues on the same noise envelope observed across the last ten audits — baseline pristine.
Queue back to user-direction: the next roadmap item is that corpus migration, which retires the per-type print operators.
## 2026-05-13 — Form A is now the authoring surface
`.ail` is now the form you read, edit, and check in. The JSON-AST counterpart is still the canonical hashable representation, but it is no longer something you look at or maintain by hand — the tools derive it from `.ail` whenever they need it. About a hundred example programs that previously existed as JSON-AST were converted to `.ail` and the JSON files were deleted; only eight stay as `.ail.json` (seven negative-test fixtures whose subject matter cannot be expressed in `.ail`, plus the prelude, which is loaded at compile time and depends on internal plumbing that lands in a later milestone).
If you were used to opening a `.ail.json` file to see what a program looks like, you now open the `.ail` sibling instead.
+244
View File
@@ -185,3 +185,247 @@ fixtures = 150 paths. Detail:
## Stats
bench/orchestrator-stats/2026-05-13-iter-form-a.1.json
---
# iter form-a.1 — Big-bang migration (Tasks 6-12: bench drivers, e2e rewrites, deletion, doctrine, milestone close)
**Date:** 2026-05-13
**Started from:** 9332d1e (post-T1-5 commit 77b28ad + plan-amendment 9332d1e)
**Status:** DONE (Tasks 6-12; iter form-a.1 fully closed)
**Tasks completed:** 7 of 7 (this dispatch); 12 of 12 (iter total)
## Summary
Second half of the form-a-default-authoring milestone-close iter: T6
flips the bench-driver fixture suffix from `.ail.json` to `.ail` (4
Python scripts + run.sh). T7 re-authors three e2e tests
(`diff_detects_changed_def`, `borrow_own_demo_modes_are_metadata_only`,
`reuse_as_demo_under_rc_uses_inplace_rewrite`) to derive their
canonical-JSON via `ail parse` on the `.ail` source rather than
raw-reading the soon-to-be-deleted `.ail.json` file, retires the
redundant `render_parse_round_trip_canonical` (subsumed by T1's
`cli_parse_then_render_then_parse_is_idempotent`), and re-authors
`ail_run_accepts_ail_source_with_same_stdout_as_ail_json` to derive
a tempdir-based `hello.ail.json` from `hello.ail` via `ail parse`
rather than reading a deleted `.ail.json` sibling. T8 deletes the
156 non-carve-out `.ail.json` files (count drops 164 → 8), removes
the `#[ignore]` on the carve-out inventory test, and pulls forward
20 stale-`.ail.json`-reference repairs that the T1-5 dispatch missed
(12 `let example = "X.ail.json"` Group-B sites + 5
`ailang_core::load_workspace` Group-A sites in e2e.rs + 3 `ail_run`
Group-B sites in typeclass_22b3.rs); to keep T8's green-gate, T9
Step 5 (schema_coverage corpus flip from `.ail.json` to `.ail`) is
also pulled forward into T8. T9 retires the 3 obsolete roundtrip
tests (`print_then_parse_round_trips_every_fixture`,
`every_ail_fixture_matches_its_json_counterpart`,
`cli_render_then_parse_preserves_canonical_bytes_on_every_fixture`)
plus the dead helpers `list_json_fixtures` (×2),
`round_trip_one`, and `strip_trailing_newlines`. T10 restates the
DESIGN.md §Roundtrip Invariant with parse-determinism + idempotency
+ CLI-pipeline-idempotency + carve-out-anchor framing, replacing
the old Direction-1/Direction-2 framing and the five enforcement
bullets with the five surviving test names. T11 replaces the
CLAUDE.md and DESIGN.md doctrine sentences per spec §A4. T12
appends the WhatsNew milestone-close entry, strikes the roadmap
entry (`- [x]` + `(Closed 2026-05-13 by iter form-a.1.)`), and
verifies final inventory (8 `.ail.json` carve-outs + 157 `.ail`).
Final test count: 557 green + 3 ignored (3 pre-existing doctests).
The `cargo test --workspace` baseline holds green at every per-task
boundary; both `python3 bench/compile_check.py` and
`python3 bench/cross_lang.py` exit 0. The milestone
`[Form-A as the default authoring surface]` is fully closed.
## Per-task notes
- **iter form-a.1.6** — Bench-driver suffix flips in
`bench/compile_check.py:43,101`, `bench/cross_lang.py:48,80`,
`bench/mono_dispatch.py:10,112`, `bench/run.sh:68,182,183`.
Mechanical edit; comment text and path string updated at each
site. `python3 bench/compile_check.py` exit 0; `python3
bench/cross_lang.py` exit 0. (First compile_check run reported
exit-1 due to sub-millisecond `check_ms` noise on `hello` and
`borrow_own_demo`; second run clean. The noise is unrelated to
the migration — the bench measures `ail check` runtime, and the
Python edits did not touch the binary path.)
- **iter form-a.1.7** — Re-authored 3 raw-JSON-inspect tests +
retired 1 + re-authored the dual-form smoke. Pattern for the
three substring-assert tests: replace
`std::fs::read*("examples/<X>.ail.json")` with a `Command::new(ail_bin()).args(["parse", "examples/<X>.ail", "-o", tmpfile])`
+ `read_to_string(tmpfile)`. `reuse_as_demo_under_rc_uses_inplace_rewrite`
additionally switches its `ailang_core::load_workspace(&json_path)`
call to `ailang_surface::load_workspace(&ail_path)` (the
IR-lowering path no longer needs the JSON file). The dual-form
smoke (`ail_run_accepts_ail_source_with_same_stdout_as_ail_json`)
uses a per-process tempdir with `hello.ail.json` as the file
basename — necessary because the loader name-checks the module
name against the file stem, and the first attempt at a
tempfile-with-PID-suffix path tripped that check. Net test
count: 1 (retirement of `render_parse_round_trip_canonical`).
559 green at task close.
- **iter form-a.1.8** — CRITICAL task. Before the deletion command,
20 stale-`.ail.json`-reference repairs were pulled forward
(T1-5 dispatch missed these despite the plan's Group-A/B scope):
(a) 12 `let example = "X.ail.json"` patterns in `e2e.rs` flipped
to `"X.ail"` via sed; (b) 5 `ailang_core::load_workspace(&json_path)`
sites in `e2e.rs` switched to `ailang_surface::load_workspace`
(the `let example = "X.ail"` from (a) feeds into `workspace.join("examples").join(example)`,
which is `.ail` post-flip — needs the extension-dispatching loader);
(c) 3 `ail_run("X.ail.json")` sites in `typeclass_22b3.rs` flipped
via sed. Cargo-test green pre-deletion at 559. The plan's deletion
bash loop ran clean (exit 0); `ls examples/*.ail.json | wc -l`
8, `ls examples/*.ail | wc -l` → 157. The `#[ignore]` attribute
on `examples_ail_json_inventory_matches_carve_outs` was removed;
the test passes (8 files match `EXPECTED`). Post-deletion
cargo-test surfaced 1 failure
(`every_ast_variant_is_observed_in_the_fixture_corpus` in
`schema_coverage.rs`) because its corpus walker still looked at
`.ail.json` (now down to 8 carve-outs, insufficient to cover all
AST variants). The plan-T8 vs. T9 ordering implicitly assumed T9
Step 5 (schema_coverage corpus flip) would land before T8 — but
T9 is plan-ordered after T8. To satisfy T8's green-gate, T9
Step 5 was pulled forward inline (helper rename
`list_json_fixtures``list_ail_fixtures`, filter `.ail.json`
`.ail`, loader `ailang_core::load_module`
`ailang_surface::load_module`). Post-fix: 560 green + 3 ignored
(was 559 pre-T8 with 4 ignored including carve_out_inventory;
un-ignore + correct schema_coverage flip = +1 net = 560).
- **iter form-a.1.9** — Retired 3 obsolete roundtrip tests +
cleanups. `round_trip.rs`: retired
`print_then_parse_round_trips_every_fixture` (lines 57-101 in
pre-iter numbering) and `every_ail_fixture_matches_its_json_counterpart`
(lines 120-204); retired the `list_json_fixtures` helper and
the `round_trip_one` helper (only consumers were the two retired
tests); updated the file's doc-comment to describe the two
surviving tests (`parse_is_deterministic_*` and
`parse_then_print_then_parse_*`); removed the unused `Path`
import (only `PathBuf` remains). `roundtrip_cli.rs`: retired
`cli_render_then_parse_preserves_canonical_bytes_on_every_fixture`
(lines 116-146 pre-iter) and the `list_json_fixtures` +
`roundtrip_one` + `strip_trailing_newlines` helpers; updated the
doc-comment. T9 Step 5 (schema_coverage corpus flip) was already
done in T8; nothing to do here. 557 green + 3 ignored at task
close (560 pre-T9 3 retired = 557).
- **iter form-a.1.10** — DESIGN.md §Roundtrip Invariant restatement.
Lines 2029-2048 (Direction 1/Direction 2 framing) replaced with
the new 4-property framing (parse-determinism +
idempotency-under-print + CLI-pipeline-idempotency +
carve-out-anchor) verbatim from the plan. Lines 2061-2094
(Enforcement bullets, five tests) replaced with the five
surviving tests verbatim. Float-literals subsection (lines
2050-2059 pre-edit, 2065-2074 post-edit) preserved. Why-anchored-at-top-level
subsection (lines 2096-2108 pre-edit, 2108-2120 post-edit)
preserved. The numbered prose (4 properties) and the bulleted
enforcement (5 tests) are internally consistent; the carve-out
inventory is the 5th enforcement bullet, covering property 4
("carve-out anchor") as a meta-property.
- **iter form-a.1.11** — Doctrine edits. CLAUDE.md:5-6 sentence
replaced verbatim with spec §A4 wording. DESIGN.md:465-466 first
sentence replaced verbatim with spec §A4 wording; second
sentence ("Form (A) is one projection; the JSON-AST stays
canonical.") preserved as the trailing sentence of the new
replacement block. Doc-only; tests unaffected.
- **iter form-a.1.12** — Milestone close. WhatsNew.md entry
appended ("Form A is now the authoring surface", per-boss
editorial rules: no crate names, no iter codes, lead with the
change, factual). docs/roadmap.md entry at line 97 changed from
`- [ ]` to `- [x]` with `(Closed 2026-05-13 by iter form-a.1.)`
prepended. Final cargo-test: 557 green + 3 ignored. Final bench:
both compile_check and cross_lang exit 0. Final inventory:
exactly 8 `.ail.json` (carve-outs alphabetically: broken_unbound,
prelude, test_22b2_invalid_superclass_param,
test_22b2_kind_mismatch, test_22b2_unbound_constraint_var,
test_ct1_bad_qualifier, test_ct1_bare_xmod_rejected,
test_ct1_qualified_class_rejected) + 157 `.ail`.
## Concerns
- **Forward-pull of T9 Step 5 into T8.** The plan ordered T8
(deletion) before T9 (test retirement + schema_coverage flip),
but T8's green-gate required schema_coverage to be flipped
*first* — otherwise the schema_coverage corpus walker shrinks
from 164 `.ail.json` to 8 carve-outs and the AST-variant
coverage assertion fails. Pulled T9 Step 5 inline into T8;
T9 then had no schema_coverage work left to do. Recorded so a
future planner-skill recon pass can detect this ordering
defect class (a Task K green-gate depending on an edit
scripted for Task K+N).
- **T1-5 Group-A/B classification gaps.** The T1-5 dispatch's
Concerns flagged 4 raw-JSON-inspect e2e.rs tests but missed
20 additional sites of the same kind in two patterns: 12
`let example = "X.ail.json"` Group-B-pattern sites in e2e.rs
(feeds `build_and_run_with_alloc`) + 5
`ailang_core::load_workspace` Group-A-pattern sites in e2e.rs
+ 3 `ail_run` Group-B sites in typeclass_22b3.rs. All repaired
inline in T8 before the deletion command ran. The pattern that
T1-5 missed is "binding pulled out of the call expression" —
the `let example = "X.ail.json"` introduces a local that the
Group-B sed for `build_and_run("X.ail.json")` doesn't match.
Worth noting for a future planner-recon tightening pass.
- **bench/compile_check.py first-run flakiness.** The first run
after T6 reported exit-1 because two `check_ms` metrics on
sub-millisecond timings (`hello`, `borrow_own_demo`) drifted
past the 25% tolerance; the second run was exit-0. The drift is
measurement noise (system load + ms-scale latency), not a
migration-induced regression. Final T12 bench run was exit-0
on both scripts.
## Known debt
- **None known.** The iter closes the milestone cleanly. Two
follow-up roadmap items already exist:
- `[milestone] Prelude embed: Form-A as compile-time source`
(queued; retires carve-out (b) `prelude.ail.json`).
- The Show/print fieldtest example-corpus migration (separately
queued; orthogonal to this milestone).
- Cosmetic: the `mod tests {}` placeholder in
`ailang-core/src/hash.rs` from T5 is still in-tree; could be
deleted entirely in a doctrinal cleanup pass. Functionally
harmless.
## Files touched (Tasks 6-12)
### Modified bench (4)
- `bench/compile_check.py`
- `bench/cross_lang.py`
- `bench/mono_dispatch.py`
- `bench/run.sh`
### Modified test source (5)
- `crates/ail/tests/e2e.rs` — T7 re-authoring of 5 tests; T8
forward-pull of 12 Group-B + 5 Group-A sites
- `crates/ail/tests/typeclass_22b3.rs` — T8 forward-pull of 3
Group-B sites
- `crates/ail/tests/roundtrip_cli.rs` — T9 retirement +
helpers cleanup + doc-comment update
- `crates/ailang-surface/tests/round_trip.rs` — T9 retirement +
helpers cleanup + doc-comment update + import cleanup
- `crates/ailang-core/tests/schema_coverage.rs` — T8 corpus flip
to `.ail` (pulled forward from T9 Step 5)
### Modified test discipline (1)
- `crates/ailang-core/tests/carve_out_inventory.rs` — T8 un-ignored
### Modified doc (4)
- `CLAUDE.md` — T11 doctrine sentence (lines 5-6)
- `docs/DESIGN.md` — T10 §Roundtrip Invariant restatement; T11
§"What this Decision deliberately does not do" first sentence
- `docs/WhatsNew.md` — T12 milestone-close entry
- `docs/roadmap.md` — T12 strike of the Form-A milestone entry
### Deleted (T8) — 156 files
`examples/*.ail.json` — every non-carve-out fixture (the eight
carve-outs `broken_unbound`, `prelude`,
`test_22b2_invalid_superclass_param`, `test_22b2_kind_mismatch`,
`test_22b2_unbound_constraint_var`, `test_ct1_bad_qualifier`,
`test_ct1_bare_xmod_rejected`, `test_ct1_qualified_class_rejected`
preserved).
## Stats
bench/orchestrator-stats/2026-05-13-iter-form-a.1.json
+1
View File
@@ -52,3 +52,4 @@
- 2026-05-13 — audit-24: milestone close (Show + print rewire) — architect drift report surfaces 5 actionable items routing to `24.tidy` (3× [high]: DESIGN.md §"Monomorphisation" doc-anchor missing for three iter-24.3 strengthenings — MonoTarget::FreeFn::type_args canonical-form normalisation, post-mono synthesised-body cross-module-ref import_map-bypass invariant, FreeFnCall constraint-residual push; codegen import_map-fallback path has no unit-level pin — only E2E catches regression; FreeFnCall constraint-residual push covers only dot-qualified branch, bare-name poly-fn refs uncovered; 2× [medium]: unwrap_or_default in method-name lookup masks class-index drift, normalize_type_for_lookup duplicated across two mono.rs sites with manual-lockstep invariant), plus 1× [medium] deferred to roadmap P3 (negative-test coverage single-shape — only f:Int→Int, broader shapes wait for downstream corpus-migration milestone), plus 1× [low] carry-on (bench/architect_sweeps.sh noise on pre-milestone-24 DESIGN.md lines, not new drift). Bench: cross_lang.py exit 0 (25/25 stable); check.py + compile_check.py exit 1 with metric-identity-migrating noise envelope per audit-cma → audit-ms → audit-eob → audit-ct-tidy → audit-mq → audit-mq.tidy → iter-24.2 → iter-24.3 lineage — 9th consecutive observation; conservative-call convention holds baseline pristine across all 9, the metric-migration-between-runs is itself attribution evidence variance not signal; right ratification path is the queued P3 latency-methodology-histogram rework, not --update-baseline → 2026-05-13-audit-24.md
- 2026-05-13 — iter 24.tidy: close 5 actionable drift items from audit-24 — T1 DESIGN.md new subsection §Cross-module references in synthesised bodies (3 invariants installed iter 24.3: canonical-form MonoTarget::FreeFn::type_args via normalize_type_for_lookup, post-mono synthesised body import_map-bypass + module_user_fns fallback, FreeFnCall constraint-residual push per declared forall-constraint); T2 codegen_import_map_fallback_pin (integration test asserts prelude.print__<UserType> body references user_module.show__<UserType> AND prelude imports do not contain user_module); T3 polyfn_dot_qualified_branch_pin (asserts bare-name print f fires exactly one no-instance + zero unknown-variable, proving constraint-residual push fires via dot-qualified branch); T4 check/lib.rs:2858 unwrap_or_default → expect(class_methods registry coherence) — surfaces class-index drift on regression; T5 mono.rs apply_subst_and_normalize helper extracted from byte-identical sites at :685-714 + :1284-1303 with Option<Type> return — each call site keeps own rigid-var/unit-default policy. Tests 558/558 (was 556+2 pins). Bench cross_lang exit 0 stable, compile_check + check both exit 0 this run (10th consecutive lineage observation unobserved-firing). audit-24 medium-3 negative-test breadth defers to roadmap P3; low-1 sweep noise carry-on → 2026-05-13-iter-24.tidy.md
- 2026-05-13 — iter form-a.0: prelude pilot for Form-A-as-default-authoring milestone — examples/prelude.ail rendered (116 lines / 6386 bytes) via `ail render`; two auto-discovering roundtrip tests (every_ail_fixture_matches_its_json_counterpart + parse_then_print_then_parse_is_idempotent_on_every_ail_fixture) green on the new fixture without test-code changes; prelude.ail.json retained per spec §A2 (singular dual-form iter, deletion lands iter 1 with bulk test-infra refactor); cargo test --workspace green at 558 tests → 2026-05-13-iter-form-a.0.md
- 2026-05-13 — iter form-a.1: Form-A-as-default-authoring milestone close (Boss-decided strategy C, big-bang) — 12 tasks across two implementer dispatches; T1 added 3 new tests (parse-determinism + CLI-pipeline-idempotency + carve_out_inventory#[ignore]) + T2 bulk-rendered 99 missing examples/<stem>.ail (corpus 58→157 .ail) + T3-4 migrated 26 fixture-loading test files (Group A load_workspace→ailang_surface::load_workspace + Group B subprocess suffix flip) + T5 relocated 23 #[cfg(test)] mod tests blocks from ailang-core/-codegen production source to integration test crates with ailang-surface dev-dep (hash_pin.rs + workspace_pin.rs + eq_primitives_pin.rs + prose snapshot migration) + T6 bench-driver suffix flips (4 Python + run.sh, both compile_check.py + cross_lang.py exit 0) + T7 re-authored 4 raw-JSON-inspect e2e tests via `ail parse`-derived tempfiles + retired 1 (render_parse_round_trip_canonical subsumed by T1) + T8 deleted 156 non-carve-out .ail.json (inventory 8 carve-outs + 157 .ail post-T8, alphabetical: broken_unbound + prelude + 3× test_22b2_* + 3× test_ct1_*) + 20 forward-pulled stale-.ail.json-ref repairs missed by T1-5 recon + T9 retired 3 obsolete roundtrip tests (print_then_parse_round_trips_every_fixture + every_ail_fixture_matches_its_json_counterpart + cli_render_then_parse_preserves_canonical_bytes_on_every_fixture) + dead helpers (list_json_fixtures ×2, round_trip_one, strip_trailing_newlines) + flipped schema_coverage corpus to .ail (forward-pulled into T8 for green-gate) + T10 §C3 DESIGN.md §Roundtrip Invariant restated with parse-determinism + idempotency + CLI-pipeline-idempotency + carve-out-anchor framing (5 surviving enforcement tests named) + T11 §A4 CLAUDE.md + DESIGN.md doctrine sentences replaced (canonical form is JSON-AST; authoring form is .ail) + T12 WhatsNew milestone-close entry + roadmap [milestone] form-a struck [x] (Closed 2026-05-13 by iter form-a.1). 4 carve-outs added beyond the original 7 §C4(a): only 1 — prelude.ail.json — landed as §C4(b) compile-time-embed (rationale: include_str! at workspace.rs:417 + main.rs:474; resolution queued as separate milestone Prelude embed: Form-A as compile-time source). Spec amendment + grounding-recheck PASS at 9fcda8b. Final tests: 557 green + 3 ignored (561 from T1 4 retired = 557); bench compile_check.py + cross_lang.py exit 0; check.py noise envelope continues 11th consecutive audit, baseline pristine. Milestone structurally closed → 2026-05-13-iter-form-a.1.md
+2 -2
View File
@@ -94,8 +94,8 @@ context. Pick the next milestone from P1.)_
form-a.0 — `examples/prelude.ail` rendered via `ail render`,
116 lines / 6386 bytes, round-trip-CI green.)
- [ ] **\[milestone\]** Form-A as the default authoring surface for
examples and docs. Render every `examples/*.ail.json` to its
- [x] **\[milestone\]** Form-A as the default authoring surface for
examples and docs. (Closed 2026-05-13 by iter form-a.1.) Render every `examples/*.ail.json` to its
`.ail` sibling via `ail render`, **delete the now-redundant
`.ail.json`**, and regenerate the JSON-AST per `ail parse` at
build / test time. Same for inline JSON-AST blocks in `docs/`
-1
View File
@@ -1 +0,0 @@
{"defs":[{"body":{"args":[{"args":[{"args":[{"name":"seed","t":"var"}],"fn":{"name":"f","t":"var"},"t":"app"}],"fn":{"name":"f","t":"var"},"t":"app"}],"fn":{"name":"f","t":"var"},"t":"app"},"doc":"Higher-order: apply f three times to seed.","kind":"fn","name":"apply_thrice","params":["f","seed"],"type":{"effects":[],"k":"fn","params":[{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}},{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"cond":{"args":[{"name":"i","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"<","t":"var"},"t":"app"},"else":{"body":{"name":"i","t":"var"},"in":{"body":{"args":[{"args":[{"name":"i","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},{"args":[{"name":"acc","t":"var"},{"name":"r","t":"var"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"run_loop","t":"var"},"t":"app","tail":true},"name":"r","t":"let","value":{"args":[{"name":"helper","t":"var"},{"name":"i","t":"var"}],"fn":{"name":"apply_thrice","t":"var"},"t":"app"}},"name":"helper","params":["x"],"t":"letrec","type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},"t":"if","then":{"name":"acc","t":"var"}},"doc":"For each i in [n-1, n-2, ..., 0], build a closure capturing i, pass to apply_thrice, accumulate. Tail-recursive on i and acc.","kind":"fn","name":"run_loop","params":["i","acc"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"},{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"run_loop","t":"var"},"t":"app"},"doc":"Drive run_loop from i=n-1 down to 0.","kind":"fn","name":"run","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":10000},"t":"lit"}],"fn":{"name":"run","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":100000},"t":"lit"}],"fn":{"name":"run","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"args":[{"args":[{"lit":{"kind":"int","value":500000},"t":"lit"}],"fn":{"name":"run","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"t":"seq"},"t":"seq"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"bench_closure_chain","schema":"ailang/v0"}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"body":{"cond":{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"},"else":{"cond":{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":2},"t":"lit"}],"fn":{"name":"%","t":"var"},"t":"app"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"},"else":{"args":[{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":3},"t":"lit"}],"fn":{"name":"*","t":"var"},"t":"app"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"+","t":"var"},"t":"app"},{"args":[{"name":"acc","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"collatz_steps","t":"var"},"t":"app","tail":true},"t":"if","then":{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":2},"t":"lit"}],"fn":{"name":"/","t":"var"},"t":"app"},{"args":[{"name":"acc","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"collatz_steps","t":"var"},"t":"app","tail":true}},"t":"if","then":{"name":"acc","t":"var"}},"doc":"Tail-recursive: count Collatz steps from n to 1, accumulating in acc.","kind":"fn","name":"collatz_steps","params":["n","acc"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"},{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"cond":{"args":[{"name":"i","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"},"else":{"args":[{"args":[{"name":"i","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},{"args":[{"name":"total","t":"var"},{"args":[{"name":"i","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"collatz_steps","t":"var"},"t":"app"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"sum_steps_loop","t":"var"},"t":"app","tail":true},"t":"if","then":{"name":"total","t":"var"}},"doc":"Tail-recursive: sum collatz_steps(i) for i in [n, n-1, ..., 1].","kind":"fn","name":"sum_steps_loop","params":["i","total"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"},{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"sum_steps_loop","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"kind":"fn","name":"run_one","params":["n"],"type":{"effects":["IO"],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Unit"}}},{"body":{"lhs":{"args":[{"lit":{"kind":"int","value":10000},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"rhs":{"lhs":{"args":[{"lit":{"kind":"int","value":100000},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"rhs":{"args":[{"lit":{"kind":"int","value":500000},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"t":"seq"},"t":"seq"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"bench_compute_collatz","schema":"ailang/v0"}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"body":{"cond":{"args":[{"name":"i","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"},"else":{"args":[{"args":[{"name":"i","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},{"args":[{"name":"acc","t":"var"},{"args":[{"name":"i","t":"var"},{"lit":{"kind":"int","value":7},"t":"lit"}],"fn":{"name":"*","t":"var"},"t":"app"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"intsum_loop","t":"var"},"t":"app","tail":true},"t":"if","then":{"name":"acc","t":"var"}},"doc":"Tail-recursive: acc += i*7 for i in [n, n-1, ..., 1]. Returns final acc.","kind":"fn","name":"intsum_loop","params":["i","acc"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"},{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"intsum_loop","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"kind":"fn","name":"run_one","params":["n"],"type":{"effects":["IO"],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Unit"}}},{"body":{"lhs":{"args":[{"lit":{"kind":"int","value":1000000},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"rhs":{"lhs":{"args":[{"lit":{"kind":"int","value":10000000},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"rhs":{"args":[{"lit":{"kind":"int","value":50000000},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"t":"seq"},"t":"seq"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"bench_compute_intsum","schema":"ailang/v0"}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"ctors":[{"fields":[],"name":"Nil"},{"fields":[{"k":"var","name":"a"},{"args":[{"k":"var","name":"a"}],"k":"con","name":"List"}],"name":"Cons"}],"doc":"Polymorphic singly-linked list. Same shape as list_map_poly's List, replicated here so the bench fixture is self-contained.","kind":"type","name":"List","vars":["a"]},{"body":{"cond":{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"},"else":{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},{"name":"acc","t":"var"}],"ctor":"Cons","t":"ctor","type":"List"}],"fn":{"name":"build_n","t":"var"},"t":"app","tail":true},"t":"if","then":{"name":"acc","t":"var"}},"doc":"Build [0, 1, ..., n-1] :: List Int. Tail-recursive accumulator form.","kind":"fn","name":"build_n","params":["n","acc"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"},{"args":[{"k":"con","name":"Int"}],"k":"con","name":"List"}],"ret":{"args":[{"k":"con","name":"Int"}],"k":"con","name":"List"}}},{"body":{"args":[{"name":"x","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"+","t":"var"},"t":"app"},"doc":"Add 1 to an Int. Used as the HOF argument to fold_with_fn.","kind":"fn","name":"inc","params":["x"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"arms":[{"body":{"name":"acc","t":"var"},"pat":{"ctor":"Nil","fields":[],"p":"ctor"}},{"body":{"args":[{"name":"f","t":"var"},{"name":"t","t":"var"},{"args":[{"name":"acc","t":"var"},{"args":[{"name":"h","t":"var"}],"fn":{"name":"f","t":"var"},"t":"app"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"fold_with_fn","t":"var"},"t":"app","tail":true},"pat":{"ctor":"Cons","fields":[{"name":"h","p":"var"},{"name":"t","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"xs","t":"var"},"t":"match"},"doc":"Polymorphic foldl-with-mapping. Apply f:(a)->Int to every element of xs, sum into acc. Tail-recursive on (xs, acc); the f arg is forwarded unchanged.","kind":"fn","name":"fold_with_fn","params":["f","xs","acc"],"type":{"body":{"effects":[],"k":"fn","params":[{"effects":[],"k":"fn","params":[{"k":"var","name":"a"}],"ret":{"k":"con","name":"Int"}},{"args":[{"k":"var","name":"a"}],"k":"con","name":"List"},{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}},"k":"forall","vars":["a"]}},{"body":{"args":[{"args":[{"name":"inc","t":"var"},{"args":[{"name":"n","t":"var"},{"args":[],"ctor":"Nil","t":"ctor","type":"List"}],"fn":{"name":"build_n","t":"var"},"t":"app"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"fold_with_fn","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"doc":"Build [0..n-1], fold with inc, print sum of (inc x).","kind":"fn","name":"run_one","params":["n"],"type":{"effects":["IO"],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Unit"}}},{"body":{"lhs":{"args":[{"lit":{"kind":"int","value":100000},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"rhs":{"lhs":{"args":[{"lit":{"kind":"int","value":1000000},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"rhs":{"args":[{"lit":{"kind":"int","value":3000000},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"t":"seq"},"t":"seq"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"bench_hof_pipeline","schema":"ailang/v0"}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
{"defs":[{"ctors":[{"fields":[],"name":"INil"},{"fields":[{"k":"con","name":"Int"},{"k":"con","name":"IntList"}],"name":"ICons"}],"kind":"type","name":"IntList"},{"body":{"cond":{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"},"else":{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},{"name":"acc","t":"var"}],"ctor":"ICons","t":"ctor","type":"IntList"}],"fn":{"name":"cons_n_acc","t":"var"},"t":"app","tail":true},"t":"if","then":{"name":"acc","t":"var"}},"doc":"Tail-recursive list builder. Result = accumulator-prepended list.","kind":"fn","name":"cons_n_acc","params":["n","acc"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"},{"k":"con","name":"IntList"}],"ret":{"k":"con","name":"IntList"}}},{"body":{"args":[{"name":"n","t":"var"},{"args":[],"ctor":"INil","t":"ctor","type":"IntList"}],"fn":{"name":"cons_n_acc","t":"var"},"t":"app"},"doc":"Build [0, 1, ..., n-1] :: IntList. Order doesn't matter for sum.","kind":"fn","name":"cons_n","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"IntList"}}},{"body":{"arms":[{"body":{"name":"acc","t":"var"},"pat":{"ctor":"INil","fields":[],"p":"ctor"}},{"body":{"args":[{"name":"t","t":"var"},{"args":[{"name":"acc","t":"var"},{"name":"h","t":"var"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"sum_acc","t":"var"},"t":"app","tail":true},"pat":{"ctor":"ICons","fields":[{"name":"h","p":"var"},{"name":"t","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"xs","t":"var"},"t":"match"},"doc":"Tail-recursive sum.","kind":"fn","name":"sum_acc","params":["xs","acc"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"IntList"},{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"name":"xs","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"sum_acc","t":"var"},"t":"app"},"doc":"Sum every element. Calls sum_acc with seed 0.","kind":"fn","name":"sum_list","params":["xs"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"IntList"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"args":[{"args":[{"name":"n","t":"var"}],"fn":{"name":"cons_n","t":"var"},"t":"app"}],"fn":{"name":"sum_list","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"doc":"Build a list of length n, sum it, print the sum.","kind":"fn","name":"run_one","params":["n"],"type":{"effects":["IO"],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Unit"}}},{"body":{"lhs":{"args":[{"lit":{"kind":"int","value":100000},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"rhs":{"lhs":{"args":[{"lit":{"kind":"int","value":1000000},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"rhs":{"args":[{"lit":{"kind":"int","value":3000000},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"t":"seq"},"t":"seq"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"bench_list_sum","schema":"ailang/v0"}
@@ -1 +0,0 @@
{"defs":[{"ctors":[{"fields":[],"name":"INil"},{"fields":[{"k":"con","name":"Int"},{"k":"con","name":"IntList"}],"name":"ICons"}],"doc":"Singly-linked Int list. drop-iterative so Own-param drops are O(1) stack.","drop-iterative":true,"kind":"type","name":"IntList"},{"body":{"cond":{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"},"else":{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},{"name":"acc","t":"var"}],"ctor":"ICons","t":"ctor","type":"IntList"}],"fn":{"name":"cons_n_acc","t":"var"},"t":"app","tail":true},"t":"if","then":{"name":"acc","t":"var"}},"doc":"Tail-recursive: prepend (n-1, n-2, ..., 0) onto acc. Returns owned chain.","kind":"fn","name":"cons_n_acc","params":["n","acc"],"type":{"effects":[],"k":"fn","param_modes":["implicit","own"],"params":[{"k":"con","name":"Int"},{"k":"con","name":"IntList"}],"ret":{"k":"con","name":"IntList"},"ret_mode":"own"}},{"body":{"args":[{"name":"n","t":"var"},{"args":[],"ctor":"INil","t":"ctor","type":"IntList"}],"fn":{"name":"cons_n_acc","t":"var"},"t":"app"},"doc":"Build [0..n-1] :: IntList. Returns owned chain; caller owns and consumes.","kind":"fn","name":"cons_n","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"IntList"},"ret_mode":"own"}},{"body":{"arms":[{"body":{"name":"acc","t":"var"},"pat":{"ctor":"INil","fields":[],"p":"ctor"}},{"body":{"args":[{"name":"t","t":"var"},{"args":[{"name":"acc","t":"var"},{"name":"h","t":"var"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"sum_acc","t":"var"},"t":"app","tail":true},"pat":{"ctor":"ICons","fields":[{"name":"h","p":"var"},{"name":"t","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"xs","t":"var"},"t":"match"},"doc":"Tail-recursive sum. Owns xs; consumes via LCons-arm move-into-tail-call.","kind":"fn","name":"sum_acc","params":["xs","acc"],"type":{"effects":[],"k":"fn","param_modes":["own","implicit"],"params":[{"k":"con","name":"IntList"},{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"name":"xs","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"sum_acc","t":"var"},"t":"app"},"doc":"Sum every element. Owns xs, hands it to sum_acc which consumes it.","kind":"fn","name":"sum_list","params":["xs"],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"k":"con","name":"IntList"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"args":[{"args":[{"name":"n","t":"var"}],"fn":{"name":"cons_n","t":"var"},"t":"app"}],"fn":{"name":"sum_list","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"doc":"Build, sum, print. The owned list flows from cons_n into sum_list and is fully consumed.","kind":"fn","name":"run_one","params":["n"],"type":{"effects":["IO"],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Unit"}}},{"body":{"lhs":{"args":[{"lit":{"kind":"int","value":100000},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"rhs":{"lhs":{"args":[{"lit":{"kind":"int","value":1000000},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"rhs":{"args":[{"lit":{"kind":"int","value":3000000},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"t":"seq"},"t":"seq"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"bench_list_sum_explicit","schema":"ailang/v0"}
-139
View File
@@ -1,139 +0,0 @@
{
"schema": "ailang/v0",
"name": "bench_mono_dispatch",
"imports": [],
"defs": [
{
"kind": "class", "name": "Foo", "param": "a",
"methods": [{
"name": "foo",
"type": {
"k": "fn", "params": [{ "k": "var", "name": "a" }],
"ret": { "k": "con", "name": "Int" }, "effects": []
}
}]
},
{
"kind": "instance",
"class": "Foo",
"type": { "k": "con", "name": "Int" },
"methods": [{
"name": "foo",
"body": {
"t": "lam",
"params": ["x"],
"paramTypes": [{ "k": "var", "name": "a" }],
"retType": { "k": "con", "name": "Int" },
"body": {
"t": "app",
"fn": { "t": "var", "name": "+" },
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "*" },
"args": [
{ "t": "var", "name": "x" },
{ "t": "lit", "lit": { "kind": "int", "value": 1103515245 } }
]
},
{ "t": "lit", "lit": { "kind": "int", "value": 12345 } }
]
}
}
}]
},
{
"kind": "class", "name": "Looper", "param": "a",
"methods": [{
"name": "loop_call",
"type": {
"k": "fn", "params": [{ "k": "var", "name": "a" }, { "k": "con", "name": "Int" }],
"ret": { "k": "con", "name": "Int" }, "effects": []
}
}]
},
{
"kind": "instance",
"class": "Looper",
"type": { "k": "con", "name": "Int" },
"methods": [{
"name": "loop_call",
"body": {
"t": "lam",
"params": ["i", "acc"],
"paramTypes": [{ "k": "var", "name": "a" }, { "k": "con", "name": "Int" }],
"retType": { "k": "con", "name": "Int" },
"body": {
"t": "if",
"cond": {
"t": "app",
"fn": { "t": "var", "name": "==" },
"args": [
{ "t": "var", "name": "i" },
{ "t": "lit", "lit": { "kind": "int", "value": 0 } }
]
},
"then": { "t": "var", "name": "acc" },
"else": {
"t": "app",
"tail": true,
"fn": { "t": "var", "name": "loop_call" },
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "-" },
"args": [
{ "t": "var", "name": "i" },
{ "t": "lit", "lit": { "kind": "int", "value": 1 } }
]
},
{
"t": "app",
"fn": { "t": "var", "name": "+" },
"args": [
{ "t": "var", "name": "acc" },
{
"t": "app",
"fn": { "t": "var", "name": "foo" },
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "+" },
"args": [
{ "t": "var", "name": "acc" },
{ "t": "var", "name": "i" }
]
}
]
}
]
}
]
}
}
}
}]
},
{
"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": "loop_call" },
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 100000000 } },
{ "t": "lit", "lit": { "kind": "int", "value": 0 } }
]
}]
}
}
]
}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"ctors":[{"fields":[],"name":"Leaf"},{"fields":[{"k":"con","name":"Int"},{"k":"con","name":"Tree"},{"k":"con","name":"Tree"}],"name":"Node"}],"kind":"type","name":"Tree"},{"body":{"cond":{"args":[{"name":"depth","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"},"else":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"},{"args":[{"args":[{"name":"depth","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"}],"fn":{"name":"build_tree","t":"var"},"t":"app"},{"args":[{"args":[{"name":"depth","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"}],"fn":{"name":"build_tree","t":"var"},"t":"app"}],"ctor":"Node","t":"ctor","type":"Tree"},"t":"if","then":{"args":[],"ctor":"Leaf","t":"ctor","type":"Tree"}},"doc":"Balanced binary tree of given depth, every value = 1.","kind":"fn","name":"build_tree","params":["depth"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Tree"}}},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":0},"t":"lit"},"pat":{"ctor":"Leaf","fields":[],"p":"ctor"}},{"body":{"args":[{"name":"v","t":"var"},{"args":[{"args":[{"name":"l","t":"var"}],"fn":{"name":"sum_tree","t":"var"},"t":"app"},{"args":[{"name":"r","t":"var"}],"fn":{"name":"sum_tree","t":"var"},"t":"app"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"+","t":"var"},"t":"app"},"pat":{"ctor":"Node","fields":[{"name":"v","p":"var"},{"name":"l","p":"var"},{"name":"r","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"t","t":"var"},"t":"match"},"doc":"Sum every Node value via match recursion. Constructor-blocked: not tail-recursive, but recursion depth = tree depth so fits.","kind":"fn","name":"sum_tree","params":["t"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Tree"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"args":[{"args":[{"name":"depth","t":"var"}],"fn":{"name":"build_tree","t":"var"},"t":"app"}],"fn":{"name":"sum_tree","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"doc":"Build a tree of given depth, sum it, print the sum.","kind":"fn","name":"run_one","params":["depth"],"type":{"effects":["IO"],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Unit"}}},{"body":{"lhs":{"args":[{"lit":{"kind":"int","value":16},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"rhs":{"lhs":{"args":[{"lit":{"kind":"int","value":18},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"rhs":{"args":[{"lit":{"kind":"int","value":20},"t":"lit"}],"fn":{"name":"run_one","t":"var"},"t":"app"},"t":"seq"},"t":"seq"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"bench_tree_walk","schema":"ailang/v0"}
-33
View File
@@ -1,33 +0,0 @@
{
"schema": "ailang/v0",
"name": "bool_to_str_drop_rc",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"doc": "Iter 24.1: pin that `bool_to_str` participates in RC discipline. Bind the heap-Str result to `s`, consume `s` once in `io/print_str`, let the binder drop at scope close. Under --alloc=rc with AILANG_RC_STATS=1 the atexit summary must report allocs == 1 && frees == 1 && live == 0 — the heap-Str slab allocated by str_alloc inside ailang_bool_to_str rides the same rc_header + ailang_rc_dec path as int_to_str.",
"body": {
"t": "let",
"name": "s",
"value": {
"t": "app",
"fn": { "t": "var", "name": "bool_to_str" },
"args": [{ "t": "lit", "lit": { "kind": "bool", "value": true } }]
},
"body": {
"t": "do",
"op": "io/print_str",
"args": [{ "t": "var", "name": "s" }]
}
}
}
]
}
-33
View File
@@ -1,33 +0,0 @@
{
"schema": "ailang/v0",
"name": "bool_to_str_smoke_false",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"doc": "Iter 24.1: stdout-smoke for the false branch of bool_to_str. Stdout must be `false\\n` (puts adds the newline). Companion of bool_to_str_drop_rc.ail.json (which covers the true branch and the RC-stats invariant).",
"body": {
"t": "let",
"name": "s",
"value": {
"t": "app",
"fn": { "t": "var", "name": "bool_to_str" },
"args": [{ "t": "lit", "lit": { "kind": "bool", "value": false } }]
},
"body": {
"t": "do",
"op": "io/print_str",
"args": [{ "t": "var", "name": "s" }]
}
}
}
]
}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"ctors":[{"fields":[],"name":"Nil"},{"fields":[{"k":"con","name":"Int"},{"k":"con","name":"List"}],"name":"Cons"}],"doc":"Monomorphic singly-linked Int list — boxed, recursive.","kind":"type","name":"List"},{"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":"list_length","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 xs, count its elements. Iter 18a: `(borrow (con List))`.","kind":"fn","name":"list_length","params":["xs"],"type":{"effects":[],"k":"fn","param_modes":["borrow"],"params":[{"k":"con","name":"List"}],"ret":{"k":"con","name":"Int"}}},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":0},"t":"lit"},"pat":{"ctor":"Nil","fields":[],"p":"ctor"}},{"body":{"args":[{"name":"h","t":"var"},{"args":[{"name":"t","t":"var"}],"fn":{"name":"sum_list","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":"Consume xs, sum its elements. Iter 18a: `(own (con List))`.","kind":"fn","name":"sum_list","params":["xs"],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"k":"con","name":"List"}],"ret":{"k":"con","name":"Int"}}},{"body":{"body":{"lhs":{"args":[{"args":[{"name":"xs","t":"var"}],"fn":{"name":"list_length","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"args":[{"args":[{"name":"xs","t":"var"}],"fn":{"name":"sum_list","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"t":"seq"},"name":"xs","t":"let","value":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"},{"args":[{"lit":{"kind":"int","value":2},"t":"lit"},{"args":[{"lit":{"kind":"int","value":3},"t":"lit"},{"args":[],"ctor":"Nil","t":"ctor","type":"List"}],"ctor":"Cons","t":"ctor","type":"List"}],"ctor":"Cons","t":"ctor","type":"List"}],"ctor":"Cons","t":"ctor","type":"List"}},"doc":"Build [1,2,3]; print list_length (3) then sum_list (6).","kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"borrow_own_demo","schema":"ailang/v0"}
-87
View File
@@ -1,87 +0,0 @@
{
"schema": "ailang/v0",
"name": "box",
"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": "unbox",
"type": {
"k": "forall",
"vars": ["a"],
"body": {
"k": "fn",
"params": [
{
"k": "con",
"name": "Box",
"args": [{ "k": "var", "name": "a" }]
}
],
"ret": { "k": "var", "name": "a" },
"effects": []
}
},
"params": ["b"],
"doc": "Polymorphic projection out of a Box.",
"body": {
"t": "match",
"scrutinee": { "t": "var", "name": "b" },
"arms": [
{
"pat": {
"p": "ctor",
"ctor": "MkBox",
"fields": [{ "p": "var", "name": "x" }]
},
"body": { "t": "var", "name": "x" }
}
]
}
},
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"doc": "Round-trip 42 through MkBox + unbox.",
"body": {
"t": "do",
"op": "io/print_int",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "unbox" },
"args": [
{
"t": "ctor",
"type": "Box",
"ctor": "MkBox",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 42 } }
]
}
]
}
]
}
}
]
}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"body":{"body":{"args":[{"t":"clone","value":{"name":"x","t":"var"}}],"op":"io/print_int","t":"do"},"name":"x","t":"let","value":{"lit":{"kind":"int","value":42},"t":"lit"}},"doc":"Use `(clone x)` on a let-bound Int; print it.","kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"clone_demo","schema":"ailang/v0"}
-77
View File
@@ -1,77 +0,0 @@
{
"schema": "ailang/v0",
"name": "closure",
"imports": [],
"defs": [
{
"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": [],
"doc": "captures `n` from the enclosing let, returns 42",
"body": {
"t": "let",
"name": "n",
"value": { "t": "lit", "lit": { "kind": "int", "value": 3 } },
"body": {
"t": "do",
"op": "io/print_int",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "apply" },
"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": "var", "name": "n" }
]
}
},
{ "t": "lit", "lit": { "kind": "int", "value": 39 } }
]
}
]
}
}
}
]
}
-55
View File
@@ -1,55 +0,0 @@
{
"schema": "ailang/v0",
"name": "cmp_max_smoke",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "cmp_max",
"type": {
"k": "forall",
"vars": ["a"],
"constraints": [{ "class": "prelude.Ord", "type": { "k": "var", "name": "a" } }],
"body": {
"k": "fn",
"params": [{ "k": "var", "name": "a" }, { "k": "var", "name": "a" }],
"ret": { "k": "var", "name": "a" },
"effects": []
}
},
"params": ["x", "y"],
"body": {
"t": "match",
"scrutinee": {
"t": "app",
"fn": { "t": "var", "name": "compare" },
"args": [{ "t": "var", "name": "x" }, { "t": "var", "name": "y" }]
},
"arms": [
{ "pat": { "p": "ctor", "type": "prelude.Ordering", "ctor": "LT", "fields": [] }, "body": { "t": "var", "name": "y" } },
{ "pat": { "p": "wild" }, "body": { "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": "cmp_max" },
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 3 } },
{ "t": "lit", "lit": { "kind": "int", "value": 7 } }
]
}]
}
}
]
}
-249
View File
@@ -1,249 +0,0 @@
{
"schema": "ailang/v0",
"name": "compare_primitives_smoke",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"body": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_int",
"args": [{
"t": "match",
"scrutinee": {
"t": "app",
"fn": { "t": "var", "name": "compare" },
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 1 } },
{ "t": "lit", "lit": { "kind": "int", "value": 2 } }
]
},
"arms": [
{ "pat": { "p": "ctor", "ctor": "LT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 1 } } },
{ "pat": { "p": "ctor", "ctor": "EQ", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 2 } } },
{ "pat": { "p": "ctor", "ctor": "GT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 3 } } }
]
}]
},
"rhs": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_int",
"args": [{
"t": "match",
"scrutinee": {
"t": "app",
"fn": { "t": "var", "name": "compare" },
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 1 } },
{ "t": "lit", "lit": { "kind": "int", "value": 1 } }
]
},
"arms": [
{ "pat": { "p": "ctor", "ctor": "LT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 1 } } },
{ "pat": { "p": "ctor", "ctor": "EQ", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 2 } } },
{ "pat": { "p": "ctor", "ctor": "GT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 3 } } }
]
}]
},
"rhs": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_int",
"args": [{
"t": "match",
"scrutinee": {
"t": "app",
"fn": { "t": "var", "name": "compare" },
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 2 } },
{ "t": "lit", "lit": { "kind": "int", "value": 1 } }
]
},
"arms": [
{ "pat": { "p": "ctor", "ctor": "LT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 1 } } },
{ "pat": { "p": "ctor", "ctor": "EQ", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 2 } } },
{ "pat": { "p": "ctor", "ctor": "GT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 3 } } }
]
}]
},
"rhs": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_int",
"args": [{
"t": "match",
"scrutinee": {
"t": "app",
"fn": { "t": "var", "name": "compare" },
"args": [
{ "t": "lit", "lit": { "kind": "bool", "value": false } },
{ "t": "lit", "lit": { "kind": "bool", "value": true } }
]
},
"arms": [
{ "pat": { "p": "ctor", "ctor": "LT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 1 } } },
{ "pat": { "p": "ctor", "ctor": "EQ", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 2 } } },
{ "pat": { "p": "ctor", "ctor": "GT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 3 } } }
]
}]
},
"rhs": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_int",
"args": [{
"t": "match",
"scrutinee": {
"t": "app",
"fn": { "t": "var", "name": "compare" },
"args": [
{ "t": "lit", "lit": { "kind": "bool", "value": false } },
{ "t": "lit", "lit": { "kind": "bool", "value": false } }
]
},
"arms": [
{ "pat": { "p": "ctor", "ctor": "LT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 1 } } },
{ "pat": { "p": "ctor", "ctor": "EQ", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 2 } } },
{ "pat": { "p": "ctor", "ctor": "GT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 3 } } }
]
}]
},
"rhs": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_int",
"args": [{
"t": "match",
"scrutinee": {
"t": "app",
"fn": { "t": "var", "name": "compare" },
"args": [
{ "t": "lit", "lit": { "kind": "bool", "value": true } },
{ "t": "lit", "lit": { "kind": "bool", "value": false } }
]
},
"arms": [
{ "pat": { "p": "ctor", "ctor": "LT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 1 } } },
{ "pat": { "p": "ctor", "ctor": "EQ", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 2 } } },
{ "pat": { "p": "ctor", "ctor": "GT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 3 } } }
]
}]
},
"rhs": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_int",
"args": [{
"t": "match",
"scrutinee": {
"t": "app",
"fn": { "t": "var", "name": "compare" },
"args": [
{ "t": "lit", "lit": { "kind": "str", "value": "a" } },
{ "t": "lit", "lit": { "kind": "str", "value": "b" } }
]
},
"arms": [
{ "pat": { "p": "ctor", "ctor": "LT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 1 } } },
{ "pat": { "p": "ctor", "ctor": "EQ", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 2 } } },
{ "pat": { "p": "ctor", "ctor": "GT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 3 } } }
]
}]
},
"rhs": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_int",
"args": [{
"t": "match",
"scrutinee": {
"t": "app",
"fn": { "t": "var", "name": "compare" },
"args": [
{ "t": "lit", "lit": { "kind": "str", "value": "a" } },
{ "t": "lit", "lit": { "kind": "str", "value": "a" } }
]
},
"arms": [
{ "pat": { "p": "ctor", "ctor": "LT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 1 } } },
{ "pat": { "p": "ctor", "ctor": "EQ", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 2 } } },
{ "pat": { "p": "ctor", "ctor": "GT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 3 } } }
]
}]
},
"rhs": {
"t": "do",
"op": "io/print_int",
"args": [{
"t": "match",
"scrutinee": {
"t": "app",
"fn": { "t": "var", "name": "compare" },
"args": [
{ "t": "lit", "lit": { "kind": "str", "value": "b" } },
{ "t": "lit", "lit": { "kind": "str", "value": "a" } }
]
},
"arms": [
{ "pat": { "p": "ctor", "ctor": "LT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 1 } } },
{ "pat": { "p": "ctor", "ctor": "EQ", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 2 } } },
{ "pat": { "p": "ctor", "ctor": "GT", "fields": [] },
"body": { "t": "lit", "lit": { "kind": "int", "value": 3 } } }
]
}]
}
}
}
}
}
}
}
}
}
}
]
}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"ctors":[{"fields":[],"name":"INil"},{"fields":[{"k":"con","name":"Int"},{"k":"con","name":"IntList"}],"name":"ICons"}],"doc":"Local Int-list ADT; nothing fancy.","kind":"type","name":"IntList"},{"body":{"arms":[{"body":{"args":[{"lit":{"kind":"int","value":0},"t":"lit"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},"pat":{"ctor":"LT","fields":[],"p":"ctor"}},{"body":{"lit":{"kind":"int","value":0},"t":"lit"},"pat":{"ctor":"EQ","fields":[],"p":"ctor"}},{"body":{"lit":{"kind":"int","value":1},"t":"lit"},"pat":{"ctor":"GT","fields":[],"p":"ctor"}}],"scrutinee":{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"compare","t":"var"},"t":"app"},"t":"match"},"doc":"Map an Int to -1/0/+1 via prelude.compare. Returns the sign as an Int.","kind":"fn","name":"signum","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"arms":[{"body":{"lit":{"kind":"unit"},"t":"lit"},"pat":{"ctor":"INil","fields":[],"p":"ctor"}},{"body":{"lhs":{"args":[{"args":[{"name":"h","t":"var"}],"fn":{"name":"signum","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"args":[{"name":"t","t":"var"}],"fn":{"name":"drain","t":"var"},"t":"app","tail":true},"t":"seq"},"pat":{"ctor":"ICons","fields":[{"name":"h","p":"var"},{"name":"t","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"xs","t":"var"},"t":"match"},"doc":"Print signum of every element of xs, in list order.","kind":"fn","name":"drain","params":["xs"],"type":{"effects":["IO"],"k":"fn","params":[{"k":"con","name":"IntList"}],"ret":{"k":"con","name":"Unit"}}},{"body":{"args":[{"args":[{"args":[{"lit":{"kind":"int","value":0},"t":"lit"},{"lit":{"kind":"int","value":3},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},{"args":[{"lit":{"kind":"int","value":0},"t":"lit"},{"args":[{"lit":{"kind":"int","value":7},"t":"lit"},{"args":[{"args":[{"lit":{"kind":"int","value":0},"t":"lit"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},{"args":[{"lit":{"kind":"int","value":2},"t":"lit"},{"args":[],"ctor":"INil","t":"ctor","type":"IntList"}],"ctor":"ICons","t":"ctor","type":"IntList"}],"ctor":"ICons","t":"ctor","type":"IntList"}],"ctor":"ICons","t":"ctor","type":"IntList"}],"ctor":"ICons","t":"ctor","type":"IntList"}],"ctor":"ICons","t":"ctor","type":"IntList"}],"fn":{"name":"drain","t":"var"},"t":"app"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"ct_1_ordering_signum","schema":"ailang/v0"}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"body":{"name":"m","t":"var"},"doc":"Identity over Maybe<Int>; signature uses bare `Maybe` instead of `std_maybe.Maybe`.","kind":"fn","name":"classify","params":["m"],"type":{"effects":[],"k":"fn","params":[{"args":[{"k":"con","name":"Int"}],"k":"con","name":"Maybe"}],"ret":{"args":[{"k":"con","name":"Int"}],"k":"con","name":"Maybe"}}},{"body":{"args":[{"args":[{"lit":{"kind":"int","value":99},"t":"lit"},{"args":[{"args":[{"lit":{"kind":"int","value":7},"t":"lit"}],"ctor":"Just","t":"ctor","type":"std_maybe.Maybe"}],"fn":{"name":"classify","t":"var"},"t":"app"}],"fn":{"name":"std_maybe.from_maybe","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[{"module":"std_maybe"}],"name":"ct_2_bare_cross_module","schema":"ailang/v0"}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"body":{"name":"w","t":"var"},"doc":"Identity at mystery.Widget — but `mystery` is not a workspace module.","kind":"fn","name":"passthrough","params":["w"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"mystery.Widget"}],"ret":{"k":"con","name":"mystery.Widget"}}},{"body":{"args":[{"lit":{"kind":"str","value":"unreachable"},"t":"lit"}],"op":"io/print_str","t":"do"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"ct_3_bad_qualified","schema":"ailang/v0"}
@@ -1 +0,0 @@
{"defs":[{"body":{"name":"w","t":"var"},"doc":"Identity at std_maybe.Widget — `std_maybe` is real, but `Widget` is not in it.","kind":"fn","name":"passthrough","params":["w"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"std_maybe.Widget"}],"ret":{"k":"con","name":"std_maybe.Widget"}}},{"body":{"args":[{"lit":{"kind":"str","value":"unreachable"},"t":"lit"}],"op":"io/print_str","t":"do"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[{"module":"std_maybe"}],"name":"ct_3b_bad_qualified_known_module","schema":"ailang/v0"}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"ctors":[{"fields":[{"k":"con","name":"Int"}],"name":"MkBox"}],"doc":"A trivial Int wrapper.","kind":"type","name":"Box"},{"class":"prelude.Eq","kind":"instance","methods":[{"body":{"body":{"arms":[{"body":{"arms":[{"body":{"args":[{"name":"a","t":"var"},{"name":"b","t":"var"}],"fn":{"name":"==","t":"var"},"t":"app"},"pat":{"ctor":"MkBox","fields":[{"name":"b","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"y","t":"var"},"t":"match"},"pat":{"ctor":"MkBox","fields":[{"name":"a","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"x","t":"var"},"t":"match"},"effects":[],"paramTypes":[{"k":"con","name":"Box"},{"k":"con","name":"Box"}],"params":["x","y"],"retType":{"k":"con","name":"Bool"},"t":"lam"},"name":"eq"}],"type":{"k":"con","name":"Box"}}],"imports":[],"name":"ct_4_qualified_class","schema":"ailang/v0"}
-23
View File
@@ -1,23 +0,0 @@
{
"schema": "ailang/v0",
"name": "ctt2_collision_cls",
"imports": [],
"defs": [
{
"kind": "class",
"name": "MyC",
"param": "a",
"methods": [
{
"name": "op",
"type": {
"k": "fn",
"params": [{ "k": "var", "name": "a" }],
"ret": { "k": "con", "name": "Int" },
"effects": []
}
}
]
}
]
}
-29
View File
@@ -1,29 +0,0 @@
{
"schema": "ailang/v0",
"name": "ctt2_collision_lib",
"imports": [{ "module": "ctt2_collision_cls" }],
"defs": [
{
"kind": "type",
"name": "Foo",
"ctors": [{ "name": "MkLib", "fields": [] }]
},
{
"kind": "instance",
"class": "ctt2_collision_cls.MyC",
"type": { "k": "con", "name": "Foo" },
"methods": [
{
"name": "op",
"body": {
"t": "lam",
"params": ["_x"],
"paramTypes": [{ "k": "con", "name": "Foo" }],
"retType": { "k": "con", "name": "Int" },
"body": { "t": "lit", "lit": { "kind": "int", "value": 2 } }
}
}
]
}
]
}
-32
View File
@@ -1,32 +0,0 @@
{
"schema": "ailang/v0",
"name": "ctt2_collision_main",
"imports": [
{ "module": "ctt2_collision_cls" },
{ "module": "ctt2_collision_lib" }
],
"defs": [
{
"kind": "type",
"name": "Foo",
"ctors": [{ "name": "MkMain", "fields": [] }]
},
{
"kind": "instance",
"class": "ctt2_collision_cls.MyC",
"type": { "k": "con", "name": "Foo" },
"methods": [
{
"name": "op",
"body": {
"t": "lam",
"params": ["_x"],
"paramTypes": [{ "k": "con", "name": "Foo" }],
"retType": { "k": "con", "name": "Int" },
"body": { "t": "lit", "lit": { "kind": "int", "value": 1 } }
}
}
]
}
]
}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"body":{"arms":[{"body":{"lit":{"kind":"int","value":1},"t":"lit"},"pat":{"lit":{"kind":"str","value":"hi"},"p":"lit"}},{"body":{"lit":{"kind":"int","value":2},"t":"lit"},"pat":{"lit":{"kind":"str","value":"ho"},"p":"lit"}},{"body":{"lit":{"kind":"int","value":0},"t":"lit"},"pat":{"p":"wild"}}],"scrutinee":{"name":"s","t":"var"},"t":"match"},"doc":"Lit-pattern over Str; exercises 16c's build_eq for non-Int.","kind":"fn","name":"classify_str","params":["s"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Str"}],"ret":{"k":"con","name":"Int"}}},{"body":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":5},"t":"lit"},{"lit":{"kind":"int","value":5},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"}],"op":"io/print_bool","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":5},"t":"lit"},{"lit":{"kind":"int","value":6},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"}],"op":"io/print_bool","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"kind":"bool","value":true},"t":"lit"},{"lit":{"kind":"bool","value":false},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"}],"op":"io/print_bool","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"kind":"bool","value":true},"t":"lit"},{"lit":{"kind":"bool","value":true},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"}],"op":"io/print_bool","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"kind":"str","value":"hi"},"t":"lit"},{"lit":{"kind":"str","value":"hi"},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"}],"op":"io/print_bool","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"kind":"str","value":"hi"},"t":"lit"},{"lit":{"kind":"str","value":"ho"},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"}],"op":"io/print_bool","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"kind":"unit"},"t":"lit"},{"lit":{"kind":"unit"},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"}],"op":"io/print_bool","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"kind":"str","value":"hi"},"t":"lit"}],"fn":{"name":"classify_str","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"kind":"str","value":"ho"},"t":"lit"}],"fn":{"name":"classify_str","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"args":[{"args":[{"lit":{"kind":"str","value":"??"},"t":"lit"}],"fn":{"name":"classify_str","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"t":"seq"},"t":"seq"},"t":"seq"},"t":"seq"},"t":"seq"},"t":"seq"},"t":"seq"},"t":"seq"},"t":"seq"},"doc":"Drive == at Int/Bool/Str/Unit; then drive classify_str.","kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"eq_demo","schema":"ailang/v0"}
-32
View File
@@ -1,32 +0,0 @@
{
"schema": "ailang/v0",
"name": "eq_float_noinstance",
"imports": [],
"defs": [
{
"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": "if",
"cond": {
"t": "app",
"fn": { "t": "var", "name": "eq" },
"args": [
{ "t": "lit", "lit": { "kind": "float", "bits": "3ff0000000000000" } },
{ "t": "lit", "lit": { "kind": "float", "bits": "4000000000000000" } }
]
},
"then": { "t": "lit", "lit": { "kind": "int", "value": 1 } },
"else": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
}]
}
}
]
}
-103
View File
@@ -1,103 +0,0 @@
{
"schema": "ailang/v0",
"name": "eq_ord_polymorphic",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "at_most",
"doc": "Composition of prelude `gt` with `not` — semantically equivalent to `le`. Used to exercise polymorphic-helper-over-prelude-fns composition through the unified mono pass.",
"type": {
"k": "forall",
"vars": ["a"],
"constraints": [{ "class": "prelude.Ord", "type": { "k": "var", "name": "a" } }],
"body": {
"k": "fn",
"params": [
{ "k": "var", "name": "a" },
{ "k": "var", "name": "a" }
],
"param_modes": ["borrow", "borrow"],
"ret": { "k": "con", "name": "Bool" },
"effects": []
}
},
"params": ["x", "y"],
"body": {
"t": "app",
"fn": { "t": "var", "name": "not" },
"args": [{
"t": "app",
"fn": { "t": "var", "name": "gt" },
"args": [
{ "t": "var", "name": "x" },
{ "t": "var", "name": "y" }
]
}]
}
},
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn", "params": [], "ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"body": {
"t": "seq",
"lhs": {
"t": "do", "op": "io/print_int",
"args": [{
"t": "if",
"cond": {
"t": "app",
"fn": { "t": "var", "name": "at_most" },
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 3 } },
{ "t": "lit", "lit": { "kind": "int", "value": 5 } }
]
},
"then": { "t": "lit", "lit": { "kind": "int", "value": 1 } },
"else": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
}]
},
"rhs": {
"t": "seq",
"lhs": {
"t": "do", "op": "io/print_int",
"args": [{
"t": "if",
"cond": {
"t": "app",
"fn": { "t": "var", "name": "at_most" },
"args": [
{ "t": "lit", "lit": { "kind": "bool", "value": true } },
{ "t": "lit", "lit": { "kind": "bool", "value": false } }
]
},
"then": { "t": "lit", "lit": { "kind": "int", "value": 1 } },
"else": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
}]
},
"rhs": {
"t": "do", "op": "io/print_int",
"args": [{
"t": "if",
"cond": {
"t": "app",
"fn": { "t": "var", "name": "at_most" },
"args": [
{ "t": "lit", "lit": { "kind": "str", "value": "abc" } },
{ "t": "lit", "lit": { "kind": "str", "value": "abd" } }
]
},
"then": { "t": "lit", "lit": { "kind": "int", "value": 1 } },
"else": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
}]
}
}
}
}
]
}
-156
View File
@@ -1,156 +0,0 @@
{
"schema": "ailang/v0",
"name": "eq_ord_user_adt",
"imports": [],
"defs": [
{
"kind": "type",
"name": "IntBox",
"vars": [],
"doc": "A one-field box around an Int, used to demonstrate that the unified mono pass synthesises eq__IntBox from a user-written instance, not from the primitive == operator.",
"ctors": [
{ "name": "MkIntBox", "fields": [{ "k": "con", "name": "Int" }] }
]
},
{
"kind": "instance",
"class": "prelude.Eq",
"type": { "k": "con", "name": "IntBox" },
"doc": "Eq IntBox by structural unwrap of the inner Int.",
"methods": [
{
"name": "eq",
"body": {
"t": "lam",
"params": ["a", "b"],
"paramTypes": [
{ "k": "con", "name": "IntBox" },
{ "k": "con", "name": "IntBox" }
],
"retType": { "k": "con", "name": "Bool" },
"body": {
"t": "match",
"scrutinee": { "t": "var", "name": "a" },
"arms": [{
"pat": { "p": "ctor", "ctor": "MkIntBox", "fields": [{ "p": "var", "name": "ai" }] },
"body": {
"t": "match",
"scrutinee": { "t": "var", "name": "b" },
"arms": [{
"pat": { "p": "ctor", "ctor": "MkIntBox", "fields": [{ "p": "var", "name": "bi" }] },
"body": {
"t": "app",
"fn": { "t": "var", "name": "==" },
"args": [
{ "t": "var", "name": "ai" },
{ "t": "var", "name": "bi" }
]
}
}]
}
}]
}
}
}
]
},
{
"kind": "instance",
"class": "prelude.Ord",
"type": { "k": "con", "name": "IntBox" },
"doc": "Ord IntBox by delegating to Int's compare on the inner field.",
"methods": [
{
"name": "compare",
"body": {
"t": "lam",
"params": ["a", "b"],
"paramTypes": [
{ "k": "con", "name": "IntBox" },
{ "k": "con", "name": "IntBox" }
],
"retType": { "k": "con", "name": "prelude.Ordering" },
"body": {
"t": "match",
"scrutinee": { "t": "var", "name": "a" },
"arms": [{
"pat": { "p": "ctor", "ctor": "MkIntBox", "fields": [{ "p": "var", "name": "ai" }] },
"body": {
"t": "match",
"scrutinee": { "t": "var", "name": "b" },
"arms": [{
"pat": { "p": "ctor", "ctor": "MkIntBox", "fields": [{ "p": "var", "name": "bi" }] },
"body": {
"t": "app",
"fn": { "t": "var", "name": "compare" },
"args": [
{ "t": "var", "name": "ai" },
{ "t": "var", "name": "bi" }
]
}
}]
}
}]
}
}
}
]
},
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn", "params": [], "ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"body": {
"t": "seq",
"lhs": {
"t": "do", "op": "io/print_int",
"args": [{
"t": "if",
"cond": {
"t": "app",
"fn": { "t": "var", "name": "eq" },
"args": [
{
"t": "ctor", "type": "IntBox", "ctor": "MkIntBox",
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 3 } }]
},
{
"t": "ctor", "type": "IntBox", "ctor": "MkIntBox",
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 3 } }]
}
]
},
"then": { "t": "lit", "lit": { "kind": "int", "value": 1 } },
"else": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
}]
},
"rhs": {
"t": "do", "op": "io/print_int",
"args": [{
"t": "if",
"cond": {
"t": "app",
"fn": { "t": "var", "name": "eq" },
"args": [
{
"t": "ctor", "type": "IntBox", "ctor": "MkIntBox",
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 3 } }]
},
{
"t": "ctor", "type": "IntBox", "ctor": "MkIntBox",
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 5 } }]
}
]
},
"then": { "t": "lit", "lit": { "kind": "int", "value": 1 } },
"else": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
}]
}
}
}
]
}
-147
View File
@@ -1,147 +0,0 @@
{
"schema": "ailang/v0",
"name": "eq_primitives_smoke",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "to_int",
"doc": "1 if the bool is true, 0 otherwise. Used to render Eq results as printable Ints.",
"type": {
"k": "fn",
"params": [{ "k": "con", "name": "Bool" }],
"ret": { "k": "con", "name": "Int" },
"effects": []
},
"params": ["b"],
"body": {
"t": "if",
"cond": { "t": "var", "name": "b" },
"then": { "t": "lit", "lit": { "kind": "int", "value": 1 } },
"else": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
}
},
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"body": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_int",
"args": [{
"t": "app",
"fn": { "t": "var", "name": "to_int" },
"args": [{
"t": "app",
"fn": { "t": "var", "name": "eq" },
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 7 } },
{ "t": "lit", "lit": { "kind": "int", "value": 7 } }
]
}]
}]
},
"rhs": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_int",
"args": [{
"t": "app",
"fn": { "t": "var", "name": "to_int" },
"args": [{
"t": "app",
"fn": { "t": "var", "name": "eq" },
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 7 } },
{ "t": "lit", "lit": { "kind": "int", "value": 8 } }
]
}]
}]
},
"rhs": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_int",
"args": [{
"t": "app",
"fn": { "t": "var", "name": "to_int" },
"args": [{
"t": "app",
"fn": { "t": "var", "name": "eq" },
"args": [
{ "t": "lit", "lit": { "kind": "bool", "value": true } },
{ "t": "lit", "lit": { "kind": "bool", "value": true } }
]
}]
}]
},
"rhs": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_int",
"args": [{
"t": "app",
"fn": { "t": "var", "name": "to_int" },
"args": [{
"t": "app",
"fn": { "t": "var", "name": "eq" },
"args": [
{ "t": "lit", "lit": { "kind": "bool", "value": true } },
{ "t": "lit", "lit": { "kind": "bool", "value": false } }
]
}]
}]
},
"rhs": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_int",
"args": [{
"t": "app",
"fn": { "t": "var", "name": "to_int" },
"args": [{
"t": "app",
"fn": { "t": "var", "name": "eq" },
"args": [
{ "t": "lit", "lit": { "kind": "str", "value": "hello" } },
{ "t": "lit", "lit": { "kind": "str", "value": "hello" } }
]
}]
}]
},
"rhs": {
"t": "do",
"op": "io/print_int",
"args": [{
"t": "app",
"fn": { "t": "var", "name": "to_int" },
"args": [{
"t": "app",
"fn": { "t": "var", "name": "eq" },
"args": [
{ "t": "lit", "lit": { "kind": "str", "value": "hello" } },
{ "t": "lit", "lit": { "kind": "str", "value": "world" } }
]
}]
}]
}
}
}
}
}
}
}
]
}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"ctors":[{"fields":[{"k":"var","name":"a"}],"name":"MkBox"}],"kind":"type","name":"Box","vars":["a"]},{"body":{"body":{"arms":[{"body":{"lit":{"kind":"int","value":42},"t":"lit"},"pat":{"ctor":"MkBox","fields":[{"p":"wild"}],"p":"ctor"}}],"scrutinee":{"name":"b","t":"var"},"t":"match"},"name":"b","t":"let","value":{"args":[{"name":"n","t":"var"}],"ctor":"MkBox","t":"ctor","type":"Box"}},"doc":"Build a Box(n), discard the payload, return 42. The Box is non-escaping.","kind":"fn","name":"peek","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"cond":{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"<=","t":"var"},"t":"app"},"else":{"body":{"arms":[{"body":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"},{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"}],"fn":{"name":"count","t":"var"},"t":"app"}],"fn":{"name":"+","t":"var"},"t":"app"},"pat":{"ctor":"MkBox","fields":[{"p":"wild"}],"p":"ctor"}}],"scrutinee":{"name":"b","t":"var"},"t":"match"},"name":"b","t":"let","value":{"args":[{"name":"n","t":"var"}],"ctor":"MkBox","t":"ctor","type":"Box"}},"t":"if","then":{"lit":{"kind":"int","value":0},"t":"lit"}},"doc":"Recurse n times; each call builds a temporary Box, discards its payload via _, and returns 0 if n<=0, else 1 + count(n-1).","kind":"fn","name":"count","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"peek","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":123},"t":"lit"}],"fn":{"name":"peek","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":5},"t":"lit"}],"fn":{"name":"count","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"args":[{"args":[{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"count","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"t":"seq"},"t":"seq"},"t":"seq"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"escape_local_demo","schema":"ailang/v0"}
-30
View File
@@ -1,30 +0,0 @@
{
"schema": "ailang/v0",
"name": "float_to_str_smoke",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"doc": "Iter hs.4: smoke pin for the float_to_str heap-Str builtin. `do io/print_str(float_to_str(3.5))` builds through the whole pipeline (checker resolves float_to_str:(Float)->Str, codegen lowers to call ptr @ailang_float_to_str(double 3.5), runtime/str.c's ailang_float_to_str snprintfs into a heap-Str slab via libc %g, io/print_str's @puts prints from the bytes pointer at offset 8). The exact rendering of 3.5 is libc-target-dependent; on the dev target's clang+glibc with default C locale it is the three bytes `3.5`. Single-value smoke; NaN / +Inf / -Inf edge cases are deferred per the hs.4 plan.",
"body": {
"t": "do",
"op": "io/print_str",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "float_to_str" },
"args": [{ "t": "lit", "lit": { "kind": "float", "bits": "400c000000000000" } }]
}
]
}
}
]
}
-64
View File
@@ -1,64 +0,0 @@
{
"schema": "ailang/v0",
"name": "floats",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"body": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_float",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "+" },
"args": [
{ "t": "lit", "lit": { "kind": "float", "bits": "3ff8000000000000" } },
{ "t": "lit", "lit": { "kind": "float", "bits": "4004000000000000" } }
]
}
]
},
"rhs": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_float",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "int_to_float" },
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 42 } }
]
}
]
},
"rhs": {
"t": "do",
"op": "io/print_float",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "neg" },
"args": [
{ "t": "lit", "lit": { "kind": "float", "bits": "3ff8000000000000" } }
]
}
]
}
}
}
}
]
}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"ctors":[{"fields":[],"name":"Nil"},{"fields":[{"k":"var","name":"a"},{"args":[{"k":"var","name":"a"}],"k":"con","name":"List"}],"name":"Cons"}],"doc":"Polymorphic singly-linked list (re-declared locally).","kind":"type","name":"List","vars":["a"]},{"body":{"cond":{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"},"else":{"args":[{"name":"n","t":"var"},{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"}],"fn":{"name":"build","t":"var"},"t":"app"}],"ctor":"Cons","t":"ctor","type":"List"},"t":"if","then":{"args":[],"ctor":"Nil","t":"ctor","type":"List"}},"doc":"Build [n, n-1, ..., 1] :: List Int via Cons recursion.","kind":"fn","name":"build","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"args":[{"k":"con","name":"Int"}],"k":"con","name":"List"}}},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":0},"t":"lit"},"pat":{"ctor":"Nil","fields":[],"p":"ctor"}},{"body":{"args":[{"name":"h","t":"var"},{"args":[{"name":"t","t":"var"}],"fn":{"name":"sum_list","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":"Recursively sum a List Int.","kind":"fn","name":"sum_list","params":["xs"],"type":{"effects":[],"k":"fn","params":[{"args":[{"k":"con","name":"Int"}],"k":"con","name":"List"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"args":[{"args":[{"lit":{"kind":"int","value":50},"t":"lit"}],"fn":{"name":"build","t":"var"},"t":"app"}],"fn":{"name":"sum_list","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"doc":"Build [50..1], sum, print 1275.","kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"gc_stress","schema":"ailang/v0"}
-32
View File
@@ -1,32 +0,0 @@
{
"schema": "ailang/v0",
"name": "ge_at_int_smoke",
"imports": [],
"defs": [
{
"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": "if",
"cond": {
"t": "app",
"fn": { "t": "var", "name": "ge" },
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 3 } },
{ "t": "lit", "lit": { "kind": "int", "value": 5 } }
]
},
"then": { "t": "lit", "lit": { "kind": "int", "value": 1 } },
"else": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
}]
}
}
]
}
-32
View File
@@ -1,32 +0,0 @@
{
"schema": "ailang/v0",
"name": "gt_at_bool_smoke",
"imports": [],
"defs": [
{
"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": "if",
"cond": {
"t": "app",
"fn": { "t": "var", "name": "gt" },
"args": [
{ "t": "lit", "lit": { "kind": "bool", "value": true } },
{ "t": "lit", "lit": { "kind": "bool", "value": false } }
]
},
"then": { "t": "lit", "lit": { "kind": "int", "value": 1 } },
"else": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
}]
}
}
]
}
@@ -1,41 +0,0 @@
{
"schema": "ailang/v0",
"name": "heap_str_repeated_print_borrow",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"doc": "Iter eob.1: heap-Str passed to io/print_str twice in sequence. Under the new rule (Term::Do args = Borrow), the second call no longer triggers use-after-consume; the linearity check accepts the program. Under --alloc=rc + AILANG_RC_STATS=1 the slab allocates once and is freed once at scope close (allocs == 1, frees == 1, live == 0).",
"body": {
"t": "let",
"name": "s",
"value": {
"t": "app",
"fn": { "t": "var", "name": "int_to_str" },
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }]
},
"body": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_str",
"args": [{ "t": "var", "name": "s" }]
},
"rhs": {
"t": "do",
"op": "io/print_str",
"args": [{ "t": "var", "name": "s" }]
}
}
}
}
]
}
-25
View File
@@ -1,25 +0,0 @@
{
"schema": "ailang/v0",
"name": "hello",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"body": {
"t": "do",
"op": "io/print_str",
"args": [
{ "t": "lit", "lit": { "kind": "str", "value": "Hello, AILang." } }
]
}
}
]
}
-77
View File
@@ -1,77 +0,0 @@
{
"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 } }
]
}
]
}
}
]
}
-29
View File
@@ -1,29 +0,0 @@
{
"schema": "ailang/v0",
"name": "int_to_print_int_borrow",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"doc": "Iter eob.1: primitive Int passed to io/print_int. The rule that Term::Do args are Borrow has no observable RC effect here because Int is unboxed; the test pins that no spurious bookkeeping appears (allocs == 0, frees == 0, live == 0).",
"body": {
"t": "let",
"name": "n",
"value": { "t": "lit", "lit": { "kind": "int", "value": 7 } },
"body": {
"t": "do",
"op": "io/print_int",
"args": [{ "t": "var", "name": "n" }]
}
}
}
]
}
-33
View File
@@ -1,33 +0,0 @@
{
"schema": "ailang/v0",
"name": "int_to_str_drop_rc",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"doc": "Iter hs.4: pin that `int_to_str` participates in RC discipline. Bind the heap-Str result to `s`, consume `s` once in `io/print_str`, let the binder drop at scope close. Under --alloc=rc with AILANG_RC_STATS=1 the atexit summary must report allocs == frees && live == 0 — the heap-Str slab allocated by str_alloc inside ailang_int_to_str rides the same rc_header + ailang_rc_dec path as any other RC value.",
"body": {
"t": "let",
"name": "s",
"value": {
"t": "app",
"fn": { "t": "var", "name": "int_to_str" },
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }]
},
"body": {
"t": "do",
"op": "io/print_str",
"args": [{ "t": "var", "name": "s" }]
}
}
}
]
}
-30
View File
@@ -1,30 +0,0 @@
{
"schema": "ailang/v0",
"name": "int_to_str_smoke",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"doc": "Iter hs.4: smoke pin for the int_to_str heap-Str builtin. `do io/print_str(int_to_str(42))` builds through the whole pipeline (checker resolves int_to_str:(Int)->Str, codegen lowers to call ptr @ailang_int_to_str(i64 42), runtime/str.c's ailang_int_to_str snprintfs into a heap-Str slab, io/print_str's @puts prints from the bytes pointer at offset 8). Single-value smoke; the spec's broader edge-case sweep (0, -1, i64::MAX, i64::MIN) is deferred to a follow-up tidy iter per the hs.4 plan.",
"body": {
"t": "do",
"op": "io/print_str",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "int_to_str" },
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }]
}
]
}
}
]
}
-32
View File
@@ -1,32 +0,0 @@
{
"schema": "ailang/v0",
"name": "le_at_str_smoke",
"imports": [],
"defs": [
{
"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": "if",
"cond": {
"t": "app",
"fn": { "t": "var", "name": "le" },
"args": [
{ "t": "lit", "lit": { "kind": "str", "value": "abc" } },
{ "t": "lit", "lit": { "kind": "str", "value": "abd" } }
]
},
"then": { "t": "lit", "lit": { "kind": "int", "value": 1 } },
"else": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
}]
}
}
]
}
-123
View File
@@ -1,123 +0,0 @@
{
"schema": "ailang/v0",
"name": "list",
"imports": [],
"defs": [
{
"kind": "type",
"name": "IntList",
"doc": "Einfach verkettete Int-Liste, boxed.",
"ctors": [
{ "name": "Nil", "fields": [] },
{
"name": "Cons",
"fields": [
{ "k": "con", "name": "Int" },
{ "k": "con", "name": "IntList" }
]
}
]
},
{
"kind": "fn",
"name": "sum_list",
"type": {
"k": "fn",
"params": [{ "k": "con", "name": "IntList" }],
"ret": { "k": "con", "name": "Int" },
"effects": []
},
"params": ["xs"],
"doc": "Summiert die Elemente einer Int-Liste rekursiv.",
"body": {
"t": "match",
"scrutinee": { "t": "var", "name": "xs" },
"arms": [
{
"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": "t" }
]
},
"body": {
"t": "app",
"fn": { "t": "var", "name": "+" },
"args": [
{ "t": "var", "name": "h" },
{
"t": "app",
"fn": { "t": "var", "name": "sum_list" },
"args": [{ "t": "var", "name": "t" }]
}
]
}
}
]
}
},
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"doc": "Baut [10, 20, 12] und druckt die Summe (42).",
"body": {
"t": "let",
"name": "xs",
"value": {
"t": "ctor",
"type": "IntList",
"ctor": "Cons",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 10 } },
{
"t": "ctor",
"type": "IntList",
"ctor": "Cons",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 20 } },
{
"t": "ctor",
"type": "IntList",
"ctor": "Cons",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 12 } },
{
"t": "ctor",
"type": "IntList",
"ctor": "Nil",
"args": []
}
]
}
]
}
]
},
"body": {
"t": "do",
"op": "io/print_int",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "sum_list" },
"args": [{ "t": "var", "name": "xs" }]
}
]
}
}
}
]
}
-206
View File
@@ -1,206 +0,0 @@
{
"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": "seq",
"lhs": {
"t": "do",
"op": "io/print_int",
"args": [{ "t": "var", "name": "h" }]
},
"rhs": {
"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" }
]
}
]
}
}
}
]
}
-231
View File
@@ -1,231 +0,0 @@
{
"schema": "ailang/v0",
"name": "list_map_poly",
"imports": [],
"defs": [
{
"kind": "type",
"name": "List",
"vars": ["a"],
"doc": "Polymorphic singly-linked list.",
"ctors": [
{ "name": "Nil", "fields": [] },
{
"name": "Cons",
"fields": [
{ "k": "var", "name": "a" },
{
"k": "con",
"name": "List",
"args": [{ "k": "var", "name": "a" }]
}
]
}
]
},
{
"kind": "fn",
"name": "inc",
"type": {
"k": "fn",
"params": [{ "k": "con", "name": "Int" }],
"ret": { "k": "con", "name": "Int" },
"effects": []
},
"params": ["x"],
"doc": "Add 1 to an Int.",
"body": {
"t": "app",
"fn": { "t": "var", "name": "+" },
"args": [
{ "t": "var", "name": "x" },
{ "t": "lit", "lit": { "kind": "int", "value": 1 } }
]
}
},
{
"kind": "fn",
"name": "map",
"type": {
"k": "forall",
"vars": ["a", "b"],
"body": {
"k": "fn",
"params": [
{
"k": "fn",
"params": [{ "k": "var", "name": "a" }],
"ret": { "k": "var", "name": "b" },
"effects": []
},
{
"k": "con",
"name": "List",
"args": [{ "k": "var", "name": "a" }]
}
],
"ret": {
"k": "con",
"name": "List",
"args": [{ "k": "var", "name": "b" }]
},
"effects": []
}
},
"params": ["f", "xs"],
"doc": "Polymorphic map: apply f to every element, recursing on the tail.",
"body": {
"t": "match",
"scrutinee": { "t": "var", "name": "xs" },
"arms": [
{
"pat": { "p": "ctor", "ctor": "Nil", "fields": [] },
"body": {
"t": "ctor",
"type": "List",
"ctor": "Nil",
"args": []
}
},
{
"pat": {
"p": "ctor",
"ctor": "Cons",
"fields": [
{ "p": "var", "name": "h" },
{ "p": "var", "name": "t" }
]
},
"body": {
"t": "ctor",
"type": "List",
"ctor": "Cons",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "f" },
"args": [{ "t": "var", "name": "h" }]
},
{
"t": "app",
"fn": { "t": "var", "name": "map" },
"args": [
{ "t": "var", "name": "f" },
{ "t": "var", "name": "t" }
]
}
]
}
}
]
}
},
{
"kind": "fn",
"name": "print_list",
"type": {
"k": "fn",
"params": [
{
"k": "con",
"name": "List",
"args": [{ "k": "con", "name": "Int" }]
}
],
"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": "seq",
"lhs": {
"t": "do",
"op": "io/print_int",
"args": [{ "t": "var", "name": "h" }]
},
"rhs": {
"t": "app",
"fn": { "t": "var", "name": "print_list" },
"args": [{ "t": "var", "name": "t" }],
"tail": true
}
}
}
]
}
},
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"doc": "Map inc over [1,2,3] via polymorphic List, then print: 2,3,4.",
"body": {
"t": "app",
"fn": { "t": "var", "name": "print_list" },
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "map" },
"args": [
{ "t": "var", "name": "inc" },
{
"t": "ctor",
"type": "List",
"ctor": "Cons",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 1 } },
{
"t": "ctor",
"type": "List",
"ctor": "Cons",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 2 } },
{
"t": "ctor",
"type": "List",
"ctor": "Cons",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 3 } },
{
"t": "ctor",
"type": "List",
"ctor": "Nil",
"args": []
}
]
}
]
}
]
}
]
}
]
}
}
]
}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"ctors":[{"fields":[],"name":"Nil"},{"fields":[{"k":"con","name":"Int"},{"k":"con","name":"IntList"}],"name":"Cons"}],"kind":"type","name":"IntList"},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":100},"t":"lit"},"pat":{"lit":{"kind":"int","value":0},"p":"lit"}},{"body":{"lit":{"kind":"int","value":200},"t":"lit"},"pat":{"lit":{"kind":"int","value":1},"p":"lit"}},{"body":{"lit":{"kind":"int","value":999},"t":"lit"},"pat":{"p":"wild"}}],"scrutinee":{"name":"n","t":"var"},"t":"match"},"doc":"Map 0->100, 1->200, anything else->999.","kind":"fn","name":"classify","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":-1},"t":"lit"},"pat":{"ctor":"Nil","fields":[],"p":"ctor"}},{"body":{"lit":{"kind":"int","value":0},"t":"lit"},"pat":{"ctor":"Cons","fields":[{"lit":{"kind":"int","value":0},"p":"lit"},{"p":"wild"}],"p":"ctor"}},{"body":{"name":"h","t":"var"},"pat":{"ctor":"Cons","fields":[{"name":"h","p":"var"},{"p":"wild"}],"p":"ctor"}}],"scrutinee":{"name":"xs","t":"var"},"t":"match"},"doc":"Empty -> -1; first element 0 -> 0; otherwise return the head.","kind":"fn","name":"categorize_first","params":["xs"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"IntList"}],"ret":{"k":"con","name":"Int"}}},{"body":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"classify","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"classify","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":17},"t":"lit"}],"fn":{"name":"classify","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"args":[],"ctor":"Nil","t":"ctor","type":"IntList"}],"fn":{"name":"categorize_first","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"args":[{"lit":{"kind":"int","value":0},"t":"lit"},{"args":[],"ctor":"Nil","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"fn":{"name":"categorize_first","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"args":[{"args":[{"args":[{"lit":{"kind":"int","value":7},"t":"lit"},{"args":[],"ctor":"Nil","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"fn":{"name":"categorize_first","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"t":"seq"},"t":"seq"},"t":"seq"},"t":"seq"},"t":"seq"},"doc":"Drive both fns. Expected (per line): 100, 200, 999, -1, 0, 7.","kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"lit_pat","schema":"ailang/v0"}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"body":{"args":[{"lit":{"kind":"int","value":5},"t":"lit"}],"fn":{"name":"f","t":"var"},"t":"app"},"doc":"Higher-order: applies its fn argument to 5.","kind":"fn","name":"apply5","params":["f"],"type":{"effects":[],"k":"fn","params":[{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}],"ret":{"k":"con","name":"Int"}}},{"body":{"body":{"cond":{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"<=","t":"var"},"t":"app"},"else":{"args":[{"name":"n","t":"var"},{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"}],"fn":{"name":"factorial","t":"var"},"t":"app"}],"fn":{"name":"*","t":"var"},"t":"app"},"t":"if","then":{"lit":{"kind":"int","value":1},"t":"lit"}},"in":{"args":[{"args":[{"name":"factorial","t":"var"}],"fn":{"name":"apply5","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"name":"factorial","params":["n"],"t":"letrec","type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},"doc":"Iter 16b.5: pass a let-rec'd factorial as a value to apply5. Expected stdout: 120.","kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"local_rec_as_value","schema":"ailang/v0"}
@@ -1 +0,0 @@
{"defs":[{"body":{"args":[{"lit":{"kind":"int","value":5},"t":"lit"}],"fn":{"name":"f","t":"var"},"t":"app"},"doc":"Higher-order: applies its fn argument to 5.","kind":"fn","name":"apply5","params":["f"],"type":{"effects":[],"k":"fn","params":[{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}],"ret":{"k":"con","name":"Int"}}},{"body":{"body":{"cond":{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"<=","t":"var"},"t":"app"},"else":{"args":[{"name":"n","t":"var"},{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"}],"fn":{"name":"factorial_plus","t":"var"},"t":"app"}],"fn":{"name":"*","t":"var"},"t":"app"},"t":"if","then":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"},{"name":"base","t":"var"}],"fn":{"name":"+","t":"var"},"t":"app"}},"in":{"args":[{"name":"factorial_plus","t":"var"}],"fn":{"name":"apply5","t":"var"},"t":"app"},"name":"factorial_plus","params":["n"],"t":"letrec","type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},"doc":"Build a recursive helper that captures `base` and pass it as a value to apply5.","kind":"fn","name":"run_with_base","params":["base"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":10},"t":"lit"}],"fn":{"name":"run_with_base","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"args":[{"args":[{"lit":{"kind":"int","value":100},"t":"lit"}],"fn":{"name":"run_with_base","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"t":"seq"},"doc":"Iter 16b.5: pass a capturing let-rec helper as a value. Expected stdout: 1320, 12120.","kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"local_rec_as_value_capture","schema":"ailang/v0"}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"body":{"body":{"cond":{"args":[{"name":"i","t":"var"},{"name":"n","t":"var"}],"fn":{"name":">=","t":"var"},"t":"app"},"else":{"args":[{"name":"i","t":"var"},{"args":[{"args":[{"name":"i","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"loop","t":"var"},"t":"app"}],"fn":{"name":"+","t":"var"},"t":"app"},"t":"if","then":{"lit":{"kind":"int","value":0},"t":"lit"}},"in":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"loop","t":"var"},"t":"app"},"name":"loop","params":["i"],"t":"letrec","type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},"doc":"Sum 1 + 2 + ... + (n-1). Helper captures n from the enclosing scope.","kind":"fn","name":"sum_below","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"sum_below","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":5},"t":"lit"}],"fn":{"name":"sum_below","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"args":[{"args":[{"lit":{"kind":"int","value":10},"t":"lit"}],"fn":{"name":"sum_below","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"t":"seq"},"t":"seq"},"doc":"Drive sum_below at 1, 5, 10. Expected (per line): 0, 10, 45.","kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"local_rec_capture","schema":"ailang/v0"}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"body":{"body":{"cond":{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"<=","t":"var"},"t":"app"},"else":{"args":[{"name":"n","t":"var"},{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"}],"fn":{"name":"fact","t":"var"},"t":"app"}],"fn":{"name":"*","t":"var"},"t":"app"},"t":"if","then":{"lit":{"kind":"int","value":1},"t":"lit"}},"in":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"fact","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":3},"t":"lit"}],"fn":{"name":"fact","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"args":[{"args":[{"lit":{"kind":"int","value":5},"t":"lit"}],"fn":{"name":"fact","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"t":"seq"},"t":"seq"},"name":"fact","params":["n"],"t":"letrec","type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},"doc":"Iter 16b.1: drive a let-rec'd factorial helper at three inputs. Expected stdout (per line): 1, 6, 120.","kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"local_rec_demo","schema":"ailang/v0"}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"body":{"body":{"body":{"cond":{"args":[{"name":"i","t":"var"},{"name":"n","t":"var"}],"fn":{"name":">","t":"var"},"t":"app"},"else":{"cond":{"args":[{"name":"i","t":"var"},{"name":"threshold","t":"var"}],"fn":{"name":"<","t":"var"},"t":"app"},"else":{"args":[{"args":[{"name":"i","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"loop","t":"var"},"t":"app"},"t":"if","then":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"},{"args":[{"args":[{"name":"i","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"loop","t":"var"},"t":"app"}],"fn":{"name":"+","t":"var"},"t":"app"}},"t":"if","then":{"lit":{"kind":"int","value":0},"t":"lit"}},"in":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"loop","t":"var"},"t":"app"},"name":"loop","params":["i"],"t":"letrec","type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},"name":"threshold","t":"let","value":{"args":[{"lit":{"kind":"int","value":5},"t":"lit"},{"lit":{"kind":"int","value":5},"t":"lit"}],"fn":{"name":"+","t":"var"},"t":"app"}},"doc":"Count i in 1..=n with i < threshold, where threshold = 5+5.","kind":"fn","name":"count_below","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"count_below","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":5},"t":"lit"}],"fn":{"name":"count_below","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"args":[{"args":[{"lit":{"kind":"int","value":15},"t":"lit"}],"fn":{"name":"count_below","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"t":"seq"},"t":"seq"},"doc":"Drive count_below at 0, 5, 15. Expected (per line): 0, 5, 9.","kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"local_rec_let_capture","schema":"ailang/v0"}
@@ -1 +0,0 @@
{"defs":[{"ctors":[{"fields":[{"k":"var","name":"a"},{"k":"var","name":"b"}],"name":"MkPair"}],"kind":"type","name":"Pair","vars":["a","b"]},{"body":{"arms":[{"body":{"body":{"cond":{"args":[{"name":"i","t":"var"},{"name":"n","t":"var"}],"fn":{"name":">","t":"var"},"t":"app"},"else":{"cond":{"args":[{"name":"i","t":"var"},{"name":"threshold","t":"var"}],"fn":{"name":"<","t":"var"},"t":"app"},"else":{"args":[{"args":[{"name":"i","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"loop","t":"var"},"t":"app"},"t":"if","then":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"},{"args":[{"args":[{"name":"i","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"loop","t":"var"},"t":"app"}],"fn":{"name":"+","t":"var"},"t":"app"}},"t":"if","then":{"lit":{"kind":"int","value":0},"t":"lit"}},"in":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"loop","t":"var"},"t":"app"},"name":"loop","params":["i"],"t":"letrec","type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},"pat":{"ctor":"MkPair","fields":[{"name":"threshold","p":"var"},{"name":"n","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"p","t":"var"},"t":"match"},"doc":"Match-arm captures `threshold` and `n`; inner LetRec captures both.","kind":"fn","name":"count_below","params":["p"],"type":{"effects":[],"k":"fn","params":[{"args":[{"k":"con","name":"Int"},{"k":"con","name":"Int"}],"k":"con","name":"Pair"}],"ret":{"k":"con","name":"Int"}}},{"body":{"lhs":{"args":[{"args":[{"args":[{"lit":{"kind":"int","value":10},"t":"lit"},{"lit":{"kind":"int","value":0},"t":"lit"}],"ctor":"MkPair","t":"ctor","type":"Pair"}],"fn":{"name":"count_below","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"args":[{"lit":{"kind":"int","value":10},"t":"lit"},{"lit":{"kind":"int","value":5},"t":"lit"}],"ctor":"MkPair","t":"ctor","type":"Pair"}],"fn":{"name":"count_below","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"args":[{"args":[{"args":[{"lit":{"kind":"int","value":10},"t":"lit"},{"lit":{"kind":"int","value":15},"t":"lit"}],"ctor":"MkPair","t":"ctor","type":"Pair"}],"fn":{"name":"count_below","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"t":"seq"},"t":"seq"},"doc":"Drive count_below at MkPair 10 {0,5,15}. Expected: 0, 5, 9.","kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"local_rec_match_capture","schema":"ailang/v0"}
-32
View File
@@ -1,32 +0,0 @@
{
"schema": "ailang/v0",
"name": "lt_at_int_smoke",
"imports": [],
"defs": [
{
"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": "if",
"cond": {
"t": "app",
"fn": { "t": "var", "name": "lt" },
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 3 } },
{ "t": "lit", "lit": { "kind": "int", "value": 5 } }
]
},
"then": { "t": "lit", "lit": { "kind": "int", "value": 1 } },
"else": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
}]
}
}
]
}
-113
View File
@@ -1,113 +0,0 @@
{
"schema": "ailang/v0",
"name": "max3",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "max",
"type": {
"k": "fn",
"params": [
{ "k": "con", "name": "Int" },
{ "k": "con", "name": "Int" }
],
"ret": { "k": "con", "name": "Int" },
"effects": []
},
"params": ["a", "b"],
"body": {
"t": "if",
"cond": {
"t": "app",
"fn": { "t": "var", "name": ">" },
"args": [
{ "t": "var", "name": "a" },
{ "t": "var", "name": "b" }
]
},
"then": { "t": "var", "name": "a" },
"else": { "t": "var", "name": "b" }
}
},
{
"kind": "fn",
"name": "max3",
"type": {
"k": "fn",
"params": [
{ "k": "con", "name": "Int" },
{ "k": "con", "name": "Int" },
{ "k": "con", "name": "Int" }
],
"ret": { "k": "con", "name": "Int" },
"effects": []
},
"params": ["a", "b", "c"],
"doc": "Demonstriert verschachteltes if (statt max-call) zum Test des Block-Trackings.",
"body": {
"t": "if",
"cond": {
"t": "app",
"fn": { "t": "var", "name": ">" },
"args": [
{ "t": "var", "name": "a" },
{ "t": "var", "name": "b" }
]
},
"then": {
"t": "if",
"cond": {
"t": "app",
"fn": { "t": "var", "name": ">" },
"args": [
{ "t": "var", "name": "a" },
{ "t": "var", "name": "c" }
]
},
"then": { "t": "var", "name": "a" },
"else": { "t": "var", "name": "c" }
},
"else": {
"t": "if",
"cond": {
"t": "app",
"fn": { "t": "var", "name": ">" },
"args": [
{ "t": "var", "name": "b" },
{ "t": "var", "name": "c" }
]
},
"then": { "t": "var", "name": "b" },
"else": { "t": "var", "name": "c" }
}
}
},
{
"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": "max3" },
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 3 } },
{ "t": "lit", "lit": { "kind": "int", "value": 17 } },
{ "t": "lit", "lit": { "kind": "int", "value": 9 } }
]
}
]
}
}
]
}
-112
View File
@@ -1,112 +0,0 @@
{
"schema": "ailang/v0",
"name": "maybe_int",
"imports": [],
"defs": [
{
"kind": "type",
"name": "Maybe",
"vars": ["a"],
"doc": "Optional value with a polymorphic payload.",
"ctors": [
{ "name": "None", "fields": [] },
{
"name": "Some",
"fields": [{ "k": "var", "name": "a" }]
}
]
},
{
"kind": "fn",
"name": "or_else",
"type": {
"k": "fn",
"params": [
{
"k": "con",
"name": "Maybe",
"args": [{ "k": "con", "name": "Int" }]
},
{ "k": "con", "name": "Int" }
],
"ret": { "k": "con", "name": "Int" },
"effects": []
},
"params": ["m", "d"],
"doc": "Returns the wrapped Int for Some(x) and the default d for None.",
"body": {
"t": "match",
"scrutinee": { "t": "var", "name": "m" },
"arms": [
{
"pat": { "p": "ctor", "ctor": "None", "fields": [] },
"body": { "t": "var", "name": "d" }
},
{
"pat": {
"p": "ctor",
"ctor": "Some",
"fields": [{ "p": "var", "name": "x" }]
},
"body": { "t": "var", "name": "x" }
}
]
}
},
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"doc": "Print or_else for both arms; expected 7 then 99.",
"body": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_int",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "or_else" },
"args": [
{
"t": "ctor",
"type": "Maybe",
"ctor": "Some",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 7 } }
]
},
{ "t": "lit", "lit": { "kind": "int", "value": 99 } }
]
}
]
},
"rhs": {
"t": "do",
"op": "io/print_int",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "or_else" },
"args": [
{
"t": "ctor",
"type": "Maybe",
"ctor": "None",
"args": []
},
{ "t": "lit", "lit": { "kind": "int", "value": 99 } }
]
}
]
}
}
}
]
}
-120
View File
@@ -1,120 +0,0 @@
{
"schema": "ailang/v0",
"name": "mono_hash_pin_smoke",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "ord_to_int",
"type": {
"k": "fn",
"params": [{ "k": "con", "name": "prelude.Ordering" }],
"ret": { "k": "con", "name": "Int" },
"effects": []
},
"params": ["o"],
"body": {
"t": "match",
"scrutinee": { "t": "var", "name": "o" },
"arms": [
{ "pat": { "p": "ctor", "type": "prelude.Ordering", "ctor": "LT", "fields": [] }, "body": { "t": "lit", "lit": { "kind": "int", "value": -1 } } },
{ "pat": { "p": "ctor", "type": "prelude.Ordering", "ctor": "EQ", "fields": [] }, "body": { "t": "lit", "lit": { "kind": "int", "value": 0 } } },
{ "pat": { "p": "ctor", "type": "prelude.Ordering", "ctor": "GT", "fields": [] }, "body": { "t": "lit", "lit": { "kind": "int", "value": 1 } } }
]
}
},
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn", "params": [], "ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"body": {
"t": "seq",
"lhs": {
"t": "do", "op": "io/print_bool",
"args": [{
"t": "app", "fn": { "t": "var", "name": "eq" },
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 1 } },
{ "t": "lit", "lit": { "kind": "int", "value": 1 } }
]
}]
},
"rhs": {
"t": "seq",
"lhs": {
"t": "do", "op": "io/print_bool",
"args": [{
"t": "app", "fn": { "t": "var", "name": "eq" },
"args": [
{ "t": "lit", "lit": { "kind": "bool", "value": true } },
{ "t": "lit", "lit": { "kind": "bool", "value": true } }
]
}]
},
"rhs": {
"t": "seq",
"lhs": {
"t": "do", "op": "io/print_bool",
"args": [{
"t": "app", "fn": { "t": "var", "name": "eq" },
"args": [
{ "t": "lit", "lit": { "kind": "str", "value": "a" } },
{ "t": "lit", "lit": { "kind": "str", "value": "a" } }
]
}]
},
"rhs": {
"t": "seq",
"lhs": {
"t": "do", "op": "io/print_int",
"args": [{
"t": "app", "fn": { "t": "var", "name": "ord_to_int" },
"args": [{
"t": "app", "fn": { "t": "var", "name": "compare" },
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 1 } },
{ "t": "lit", "lit": { "kind": "int", "value": 2 } }
]
}]
}]
},
"rhs": {
"t": "seq",
"lhs": {
"t": "do", "op": "io/print_int",
"args": [{
"t": "app", "fn": { "t": "var", "name": "ord_to_int" },
"args": [{
"t": "app", "fn": { "t": "var", "name": "compare" },
"args": [
{ "t": "lit", "lit": { "kind": "bool", "value": false } },
{ "t": "lit", "lit": { "kind": "bool", "value": true } }
]
}]
}]
},
"rhs": {
"t": "do", "op": "io/print_int",
"args": [{
"t": "app", "fn": { "t": "var", "name": "ord_to_int" },
"args": [{
"t": "app", "fn": { "t": "var", "name": "compare" },
"args": [
{ "t": "lit", "lit": { "kind": "str", "value": "a" } },
{ "t": "lit", "lit": { "kind": "str", "value": "b" } }
]
}]
}]
}
}
}
}
}
}
}
]
}
@@ -1,29 +0,0 @@
{
"schema": "ailang/v0",
"name": "mq1_xmod_constraint_class",
"imports": [{ "module": "mq1_xmod_constraint_class_dep" }],
"defs": [
{
"kind": "fn",
"name": "useShow",
"doc": "Positive mq.1 fixture: a polymorphic fn that takes a single value and a Show constraint, ignores the value, and returns Unit. Exercises the qualified `Constraint.class` shape end-to-end (loader + validator + check_workspace).",
"type": {
"k": "forall",
"vars": ["a"],
"constraints": [
{ "class": "mq1_xmod_constraint_class_dep.Show",
"type": { "k": "var", "name": "a" } }
],
"body": {
"k": "fn",
"params": [{ "k": "var", "name": "a" }],
"param_modes": ["borrow"],
"ret": { "k": "con", "name": "Unit" },
"effects": []
}
},
"params": ["_x"],
"body": { "t": "lit", "lit": { "kind": "unit" } }
}
]
}
@@ -1,23 +0,0 @@
{
"schema": "ailang/v0",
"name": "mq1_xmod_constraint_class_dep",
"imports": [],
"defs": [
{
"kind": "class",
"name": "Show",
"param": "a",
"methods": [
{
"name": "show",
"type": {
"k": "fn",
"params": [{ "k": "var", "name": "a" }],
"ret": { "k": "con", "name": "Str" },
"effects": []
}
}
]
}
]
}
-36
View File
@@ -1,36 +0,0 @@
{
"schema": "ailang/v0",
"name": "mq3_class_eq_vs_fn_eq",
"imports": [
{ "module": "mq3_class_eq_vs_fn_eq_classmod" },
{ "module": "mq3_class_eq_vs_fn_eq_fnmod" }
],
"defs": [
{
"kind": "fn",
"name": "main",
"doc": "mq.3.6 fixture (c): bare `myeq 1 2` in a workspace with `class MyEq` (in classmod) and `fn myeq` (in fnmod) both imported. Fn wins per lookup precedence; the typechecker emits `class-method-shadowed-by-fn` warning so the LLM-author sees the shadow.",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"body": {
"t": "do",
"op": "io/print_bool",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "myeq" },
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 1 } },
{ "t": "lit", "lit": { "kind": "int", "value": 2 } }
]
}
]
}
}
]
}
@@ -1,47 +0,0 @@
{
"schema": "ailang/v0",
"name": "mq3_class_eq_vs_fn_eq_classmod",
"imports": [],
"defs": [
{
"kind": "class",
"name": "MyEq",
"param": "a",
"methods": [
{
"name": "myeq",
"type": {
"k": "fn",
"params": [
{ "k": "var", "name": "a" },
{ "k": "var", "name": "a" }
],
"param_modes": ["borrow", "borrow"],
"ret": { "k": "con", "name": "Bool" },
"effects": []
}
}
]
},
{
"kind": "instance",
"class": "MyEq",
"type": { "k": "con", "name": "Int" },
"methods": [
{
"name": "myeq",
"body": {
"t": "lam",
"params": ["x", "y"],
"paramTypes": [
{ "k": "con", "name": "Int" },
{ "k": "con", "name": "Int" }
],
"retType": { "k": "con", "name": "Bool" },
"body": { "t": "lit", "lit": { "kind": "bool", "value": true } }
}
}
]
}
]
}
@@ -1,24 +0,0 @@
{
"schema": "ailang/v0",
"name": "mq3_class_eq_vs_fn_eq_fnmod",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "myeq",
"doc": "mq.3.6 fixture (c) helper: free fn `myeq` that shadows the class method `myeq` declared in `mq3_class_eq_vs_fn_eq_classmod`. Always returns false so the fn-wins precedence is observable at runtime if the e2e test ever runs the binary.",
"type": {
"k": "fn",
"params": [
{ "k": "con", "name": "Int" },
{ "k": "con", "name": "Int" }
],
"param_modes": ["borrow", "borrow"],
"ret": { "k": "con", "name": "Bool" },
"effects": []
},
"params": ["x", "y"],
"body": { "t": "lit", "lit": { "kind": "bool", "value": false } }
}
]
}
-33
View File
@@ -1,33 +0,0 @@
{
"schema": "ailang/v0",
"name": "mq3_two_show_ambiguous",
"imports": [
{ "module": "mq3_two_show_ambiguous_a" },
{ "module": "mq3_two_show_ambiguous_b" }
],
"defs": [
{
"kind": "fn",
"name": "main",
"doc": "mq.3.6 fixture (a): bare `show 42` in a workspace where two Show classes (in modA and modB) each ship Show Int. Without an explicit qualifier the dispatch is genuinely ambiguous; the typechecker must fire `ambiguous-method-resolution` naming both candidate classes.",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"body": {
"t": "do",
"op": "io/print_str",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "show" },
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }]
}
]
}
}
]
}
@@ -1,45 +0,0 @@
{
"schema": "ailang/v0",
"name": "mq3_two_show_ambiguous_a",
"imports": [],
"defs": [
{
"kind": "class",
"name": "Show",
"param": "a",
"methods": [
{
"name": "show",
"type": {
"k": "fn",
"params": [{ "k": "var", "name": "a" }],
"param_modes": ["borrow"],
"ret": { "k": "con", "name": "Str" },
"effects": []
}
}
]
},
{
"kind": "instance",
"class": "Show",
"type": { "k": "con", "name": "Int" },
"methods": [
{
"name": "show",
"body": {
"t": "lam",
"params": ["x"],
"paramTypes": [{ "k": "con", "name": "Int" }],
"retType": { "k": "con", "name": "Str" },
"body": {
"t": "app",
"fn": { "t": "var", "name": "int_to_str" },
"args": [{ "t": "var", "name": "x" }]
}
}
}
]
}
]
}
@@ -1,45 +0,0 @@
{
"schema": "ailang/v0",
"name": "mq3_two_show_ambiguous_b",
"imports": [],
"defs": [
{
"kind": "class",
"name": "Show",
"param": "a",
"methods": [
{
"name": "show",
"type": {
"k": "fn",
"params": [{ "k": "var", "name": "a" }],
"param_modes": ["borrow"],
"ret": { "k": "con", "name": "Str" },
"effects": []
}
}
]
},
{
"kind": "instance",
"class": "Show",
"type": { "k": "con", "name": "Int" },
"methods": [
{
"name": "show",
"body": {
"t": "lam",
"params": ["x"],
"paramTypes": [{ "k": "con", "name": "Int" }],
"retType": { "k": "con", "name": "Str" },
"body": {
"t": "app",
"fn": { "t": "var", "name": "int_to_str" },
"args": [{ "t": "var", "name": "x" }]
}
}
}
]
}
]
}
-33
View File
@@ -1,33 +0,0 @@
{
"schema": "ailang/v0",
"name": "mq3_two_show_qualified",
"imports": [
{ "module": "mq3_two_show_ambiguous_a" },
{ "module": "mq3_two_show_ambiguous_b" }
],
"defs": [
{
"kind": "fn",
"name": "main",
"doc": "mq.3.6 fixture (b): explicit qualifier `mq3_two_show_ambiguous_a.Show.show 42` disambiguates the same workspace as fixture (a). Resolves cleanly to modA's class; typecheck passes.",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"body": {
"t": "do",
"op": "io/print_str",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "mq3_two_show_ambiguous_a.Show.show" },
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }]
}
]
}
}
]
}
-32
View File
@@ -1,32 +0,0 @@
{
"schema": "ailang/v0",
"name": "ne_at_int_smoke",
"imports": [],
"defs": [
{
"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": "if",
"cond": {
"t": "app",
"fn": { "t": "var", "name": "ne" },
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 3 } },
{ "t": "lit", "lit": { "kind": "int", "value": 5 } }
]
},
"then": { "t": "lit", "lit": { "kind": "int", "value": 1 } },
"else": { "t": "lit", "lit": { "kind": "int", "value": 0 } }
}]
}
}
]
}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"body":{"body":{"cond":{"args":[{"name":"i","t":"var"},{"name":"n","t":"var"}],"fn":{"name":">","t":"var"},"t":"app"},"else":{"args":[{"body":{"cond":{"args":[{"name":"j","t":"var"},{"name":"i","t":"var"}],"fn":{"name":">","t":"var"},"t":"app"},"else":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"},{"args":[{"args":[{"name":"j","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"inner","t":"var"},"t":"app"}],"fn":{"name":"+","t":"var"},"t":"app"},"t":"if","then":{"lit":{"kind":"int","value":0},"t":"lit"}},"in":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"inner","t":"var"},"t":"app"},"name":"inner","params":["j"],"t":"letrec","type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"args":[{"args":[{"name":"i","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"outer","t":"var"},"t":"app"}],"fn":{"name":"+","t":"var"},"t":"app"},"t":"if","then":{"lit":{"kind":"int","value":0},"t":"lit"}},"in":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"outer","t":"var"},"t":"app"},"name":"outer","params":["i"],"t":"letrec","type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},"doc":"Sum 1 + 2 + ... + n by nested LetRec helpers; inner captures outer's param i.","kind":"fn","name":"nested_sum","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"nested_sum","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":3},"t":"lit"}],"fn":{"name":"nested_sum","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"args":[{"args":[{"lit":{"kind":"int","value":5},"t":"lit"}],"fn":{"name":"nested_sum","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"t":"seq"},"t":"seq"},"doc":"Drive nested_sum at 1, 3, 5. Expected (per line): 1, 6, 15.","kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"nested_let_rec","schema":"ailang/v0"}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"body":{"arms":[{"body":{"args":[{"name":"a","t":"var"},{"name":"b","t":"var"}],"fn":{"name":"+","t":"var"},"t":"app"},"pat":{"ctor":"Cons","fields":[{"name":"a","p":"var"},{"ctor":"Cons","fields":[{"name":"b","p":"var"},{"p":"wild"}],"p":"ctor"}],"p":"ctor"}},{"body":{"lit":{"kind":"int","value":0},"t":"lit"},"pat":{"p":"wild"}}],"scrutinee":{"name":"xs","t":"var"},"t":"match"},"doc":"Sum of the first two elements of an Int list, or 0 if shorter than two.","kind":"fn","name":"first_two_sum","params":["xs"],"type":{"effects":[],"k":"fn","params":[{"args":[{"k":"con","name":"Int"}],"k":"con","name":"std_list.List"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"args":[{"args":[{"lit":{"kind":"int","value":10},"t":"lit"},{"args":[{"lit":{"kind":"int","value":20},"t":"lit"},{"args":[{"lit":{"kind":"int","value":30},"t":"lit"},{"args":[],"ctor":"Nil","t":"ctor","type":"std_list.List"}],"ctor":"Cons","t":"ctor","type":"std_list.List"}],"ctor":"Cons","t":"ctor","type":"std_list.List"}],"ctor":"Cons","t":"ctor","type":"std_list.List"}],"fn":{"name":"first_two_sum","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[{"module":"std_list"}],"name":"nested_pat","schema":"ailang/v0"}
-83
View File
@@ -1,83 +0,0 @@
{
"schema": "ailang/v0",
"name": "ordering_match",
"imports": [],
"defs": [
{
"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": "match",
"scrutinee": {
"t": "ctor",
"type": "prelude.Ordering",
"ctor": "LT",
"args": []
},
"arms": [
{
"pat": {
"p": "ctor",
"ctor": "LT",
"fields": []
},
"body": {
"t": "lit",
"lit": {
"kind": "int",
"value": 1
}
}
},
{
"pat": {
"p": "ctor",
"ctor": "EQ",
"fields": []
},
"body": {
"t": "lit",
"lit": {
"kind": "int",
"value": 2
}
}
},
{
"pat": {
"p": "ctor",
"ctor": "GT",
"fields": []
},
"body": {
"t": "lit",
"lit": {
"kind": "int",
"value": 3
}
}
}
]
}
]
},
"doc": "Iter 23.1 fixture: pattern-match on prelude Ordering ctor without explicit prelude import."
}
]
}
@@ -1 +0,0 @@
{"defs":[{"ctors":[{"fields":[],"name":"Nil"},{"fields":[{"k":"con","name":"Int"},{"k":"con","name":"IntList"}],"name":"Cons"}],"doc":"Recursive Int list — boxed.","kind":"type","name":"IntList"},{"ctors":[{"fields":[{"k":"con","name":"IntList"},{"k":"con","name":"IntList"}],"name":"Pair"}],"doc":"Two IntLists side by side. Both fields are pointer-typed; the test exercises move-tracking against EACH slot independently.","kind":"type","name":"Pair"},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":0},"t":"lit"},"pat":{"ctor":"Nil","fields":[],"p":"ctor"}},{"body":{"args":[{"name":"h","t":"var"},{"args":[{"name":"t","t":"var"}],"fn":{"name":"sum_list","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":"Consume xs, sum its elements.","kind":"fn","name":"sum_list","params":["xs"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"IntList"}],"ret":{"k":"con","name":"Int"}}},{"body":{"body":{"arms":[{"body":{"args":[{"args":[{"name":"a","t":"var"}],"fn":{"name":"sum_list","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"pat":{"ctor":"Pair","fields":[{"name":"a","p":"var"},{"p":"wild"}],"p":"ctor"}}],"scrutinee":{"name":"p","t":"var"},"t":"match"},"name":"p","t":"let","value":{"args":[{"args":[{"lit":{"kind":"int","value":1},"t":"lit"},{"args":[{"lit":{"kind":"int","value":2},"t":"lit"},{"args":[{"lit":{"kind":"int","value":3},"t":"lit"},{"args":[],"ctor":"Nil","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"},{"args":[{"lit":{"kind":"int","value":4},"t":"lit"},{"args":[{"lit":{"kind":"int","value":5},"t":"lit"},{"args":[{"lit":{"kind":"int","value":6},"t":"lit"},{"args":[],"ctor":"Nil","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"ctor":"Pair","t":"ctor","type":"Pair"}},"doc":"Build Pair([1,2,3], [4,5,6]); pattern-bind first slot only; sum first list. The wildcarded second slot's IntList lives only inside the Pair box; closing the Pair's let scope must dec it (non-moved) while skipping the moved first slot.","kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"pat_extract_partial_drop","schema":"ailang/v0"}
-79
View File
@@ -1,79 +0,0 @@
{
"schema": "ailang/v0",
"name": "poly_apply",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "apply",
"type": {
"k": "forall",
"vars": ["a", "b"],
"body": {
"k": "fn",
"params": [
{
"k": "fn",
"params": [{ "k": "var", "name": "a" }],
"ret": { "k": "var", "name": "b" },
"effects": []
},
{ "k": "var", "name": "a" }
],
"ret": { "k": "var", "name": "b" },
"effects": []
}
},
"params": ["f", "x"],
"body": {
"t": "app",
"fn": { "t": "var", "name": "f" },
"args": [{ "t": "var", "name": "x" }]
}
},
{
"kind": "fn",
"name": "succ",
"type": {
"k": "fn",
"params": [{ "k": "con", "name": "Int" }],
"ret": { "k": "con", "name": "Int" },
"effects": []
},
"params": ["n"],
"body": {
"t": "app",
"fn": { "t": "var", "name": "+" },
"args": [
{ "t": "var", "name": "n" },
{ "t": "lit", "lit": { "kind": "int", "value": 1 } }
]
}
},
{
"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": "succ" },
{ "t": "lit", "lit": { "kind": "int", "value": 41 } }
]
}
]
}
}
]
}
-63
View File
@@ -1,63 +0,0 @@
{
"schema": "ailang/v0",
"name": "poly_id",
"imports": [],
"defs": [
{
"kind": "fn",
"name": "id",
"type": {
"k": "forall",
"vars": ["a"],
"body": {
"k": "fn",
"params": [{ "k": "var", "name": "a" }],
"ret": { "k": "var", "name": "a" },
"effects": []
}
},
"params": ["x"],
"body": { "t": "var", "name": "x" }
},
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"body": {
"t": "seq",
"lhs": {
"t": "do",
"op": "io/print_int",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "id" },
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 42 } }
]
}
]
},
"rhs": {
"t": "do",
"op": "io/print_bool",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "id" },
"args": [
{ "t": "lit", "lit": { "kind": "bool", "value": true } }
]
}
]
}
}
}
]
}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"body":{"args":[{"name":"x","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"+","t":"var"},"t":"app"},"doc":"Helper: increment Int. Used as the Fn(Int) -> Int instance.","kind":"fn","name":"succ","params":["x"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"name":"b","t":"var"}],"fn":{"name":"not","t":"var"},"t":"app"},"doc":"Helper: boolean negation as a top-level fn (so it has an adapter for value-position).","kind":"fn","name":"flip","params":["b"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Bool"}],"ret":{"k":"con","name":"Bool"}}},{"body":{"body":{"cond":{"args":[{"name":"k","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"},"else":{"args":[{"args":[{"name":"k","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},{"args":[{"name":"acc","t":"var"}],"fn":{"name":"f","t":"var"},"t":"app"}],"fn":{"name":"loop","t":"var"},"t":"app"},"t":"if","then":{"name":"acc","t":"var"}},"in":{"args":[{"name":"n","t":"var"},{"name":"x","t":"var"}],"fn":{"name":"loop","t":"var"},"t":"app"},"name":"loop","params":["k","acc"],"t":"letrec","type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"},{"k":"var","name":"a"}],"ret":{"k":"var","name":"a"}}},"doc":"Apply f to x exactly n times. Polymorphic in a.","kind":"fn","name":"apply_n_times","params":["n","x","f"],"type":{"body":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"},{"k":"var","name":"a"},{"effects":[],"k":"fn","params":[{"k":"var","name":"a"}],"ret":{"k":"var","name":"a"}}],"ret":{"k":"var","name":"a"}},"k":"forall","vars":["a"]}},{"body":{"lhs":{"args":[{"args":[{"lit":{"kind":"int","value":5},"t":"lit"},{"lit":{"kind":"int","value":0},"t":"lit"},{"name":"succ","t":"var"}],"fn":{"name":"apply_n_times","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"args":[{"args":[{"lit":{"kind":"int","value":4},"t":"lit"},{"lit":{"kind":"bool","value":false},"t":"lit"},{"name":"flip","t":"var"}],"fn":{"name":"apply_n_times","t":"var"},"t":"app"}],"op":"io/print_bool","t":"do"},"t":"seq"},"doc":"Drive apply_n_times at Int (succ 5 times from 0) and Bool (not 4 times from false).","kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"poly_rec_capture","schema":"ailang/v0"}
@@ -1 +0,0 @@
{"defs":[{"ctors":[{"fields":[{"k":"con","name":"Int"}],"name":"MkWrap"}],"kind":"type","name":"Wrap"},{"ctors":[{"fields":[{"k":"con","name":"Wrap"},{"k":"con","name":"Wrap"}],"name":"MkCell"}],"kind":"type","name":"Cell"},{"ctors":[{"fields":[{"k":"con","name":"Cell"},{"k":"con","name":"Cell"}],"name":"MkPair"}],"kind":"type","name":"Pair"},{"body":{"args":[{"args":[{"args":[{"name":"n","t":"var"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"},{"args":[{"lit":{"kind":"int","value":2},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"}],"ctor":"MkCell","t":"ctor","type":"Cell"},{"args":[{"args":[{"lit":{"kind":"int","value":3},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"},{"args":[{"lit":{"kind":"int","value":4},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"}],"ctor":"MkCell","t":"ctor","type":"Cell"}],"ctor":"MkPair","t":"ctor","type":"Pair"},"kind":"fn","name":"build_pair","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Pair"},"ret_mode":"own"}},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":1},"t":"lit"},"pat":{"ctor":"MkCell","fields":[{"name":"w1","p":"var"},{"name":"w2","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"c","t":"var"},"t":"match"},"kind":"fn","name":"use_cell","params":["c"],"suppress":[{"because":"RC codegen test: shape used to feed App-bound let-close partial-drop into use_cell","code":"over-strict-mode"}],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"k":"con","name":"Cell"}],"ret":{"k":"con","name":"Int"}}},{"body":{"body":{"args":[{"arms":[{"body":{"args":[{"name":"a","t":"var"}],"fn":{"name":"use_cell","t":"var"},"t":"app"},"pat":{"ctor":"MkPair","fields":[{"name":"a","p":"var"},{"p":"wild"}],"p":"ctor"}}],"scrutinee":{"name":"p","t":"var"},"t":"match"}],"op":"io/print_int","t":"do"},"name":"p","t":"let","value":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"build_pair","t":"var"},"t":"app"}},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"rc_app_let_partial_drop_leak","schema":"ailang/v0"}
-59
View File
@@ -1,59 +0,0 @@
{
"schema": "ailang/v0",
"name": "rc_box_drop",
"imports": [],
"defs": [
{
"kind": "type",
"name": "Box",
"vars": [],
"doc": "Single-cell ADT around an Int. Iter 18c.3 RC fixture: shallow free is sufficient because Box has no boxed children.",
"ctors": [
{
"name": "MkBox",
"fields": [{ "k": "con", "name": "Int" }]
}
]
},
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"doc": "Bind a heap-allocated MkBox to `b`, read its Int via match, print it. Under --alloc=rc, codegen emits `ailang_rc_dec(b)` at the let scope close: `b` is unique, has zero consume uses (only the match scrutinee, a borrow), and the body's tail value is the printed Unit, not `b` itself. The Box has no boxed children so shallow `free()` is correct.",
"body": {
"t": "let",
"name": "b",
"value": {
"t": "ctor",
"type": "Box",
"ctor": "MkBox",
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }]
},
"body": {
"t": "match",
"scrutinee": { "t": "var", "name": "b" },
"arms": [
{
"pat": {
"p": "ctor",
"ctor": "MkBox",
"fields": [{ "p": "var", "name": "x" }]
},
"body": {
"t": "do",
"op": "io/print_int",
"args": [{ "t": "var", "name": "x" }]
}
}
]
}
}
}
]
}
@@ -1 +0,0 @@
{"defs":[{"ctors":[{"fields":[],"name":"INil"},{"fields":[{"k":"con","name":"Int"},{"k":"con","name":"IntList"}],"name":"ICons"}],"drop-iterative":true,"kind":"type","name":"IntList"},{"body":{"cond":{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"},"else":{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},{"args":[{"name":"n","t":"var"},{"name":"acc","t":"var"}],"ctor":"ICons","t":"ctor","type":"IntList"}],"fn":{"name":"cons_n_acc","t":"var"},"t":"app","tail":true},"t":"if","then":{"name":"acc","t":"var"}},"doc":"Tail-recursive list builder. acc-prepended.","kind":"fn","name":"cons_n_acc","params":["n","acc"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"},{"k":"con","name":"IntList"}],"ret":{"k":"con","name":"IntList"}}},{"body":{"args":[{"name":"n","t":"var"},{"args":[],"ctor":"INil","t":"ctor","type":"IntList"}],"fn":{"name":"cons_n_acc","t":"var"},"t":"app"},"doc":"Build [1, 2, ..., n] :: IntList. Order is reverse of build but immaterial for head/sum.","kind":"fn","name":"cons_n","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"IntList"}}},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":0},"t":"lit"},"pat":{"ctor":"INil","fields":[],"p":"ctor"}},{"body":{"name":"h","t":"var"},"pat":{"ctor":"ICons","fields":[{"name":"h","p":"var"},{"name":"t","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"xs","t":"var"},"t":"match"},"doc":"Take ownership of an IntList; return its head if ICons, else 0. The (own ...) signature signals 18d.4 to emit an Own-param drop at fn return — which under the (drop-iterative) annotation is the iterative-worklist body, freeing the entire chain via the heap-allocated worklist instead of recursive cascade.","kind":"fn","name":"head_or_zero","params":["xs"],"suppress":[{"because":"Iter 18e test: forces (drop-iterative) cascade via Own-param drop at fn return","code":"over-strict-mode"}],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"k":"con","name":"IntList"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"args":[{"args":[{"lit":{"kind":"int","value":1000000},"t":"lit"}],"fn":{"name":"cons_n","t":"var"},"t":"app"}],"fn":{"name":"head_or_zero","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"rc_drop_iterative_long_list","schema":"ailang/v0"}
@@ -1 +0,0 @@
{"defs":[{"ctors":[{"fields":[],"name":"TLeaf"},{"fields":[{"k":"con","name":"Int"},{"k":"con","name":"Tree"},{"k":"con","name":"Tree"}],"name":"TNode"}],"kind":"type","name":"Tree"},{"body":{"cond":{"args":[{"name":"d","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"},"else":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"},{"args":[{"args":[{"name":"d","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"}],"fn":{"name":"build","t":"var"},"t":"app"},{"args":[{"args":[{"name":"d","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"}],"fn":{"name":"build","t":"var"},"t":"app"}],"ctor":"TNode","t":"ctor","type":"Tree"},"t":"if","then":{"args":[],"ctor":"TLeaf","t":"ctor","type":"Tree"}},"kind":"fn","name":"build","params":["d"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Tree"},"ret_mode":"own"}},{"body":{"body":{"arms":[{"body":{"lit":{"kind":"int","value":0},"t":"lit"},"pat":{"ctor":"TLeaf","fields":[],"p":"ctor"}},{"body":{"lit":{"kind":"int","value":1},"t":"lit"},"pat":{"ctor":"TNode","fields":[{"name":"v","p":"var"},{"name":"l","p":"var"},{"name":"r","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"a","t":"var"},"t":"match"},"name":"a","t":"let","value":{"name":"t","t":"var"}},"kind":"fn","name":"pin_aliased","params":["t"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Tree"}],"ret":{"k":"con","name":"Int"}}},{"body":{"cond":{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"},"else":{"body":{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},{"name":"t","t":"var"}],"fn":{"name":"loop","t":"var"},"t":"app"},"name":"_v","t":"let","value":{"args":[{"name":"t","t":"var"}],"fn":{"name":"pin_aliased","t":"var"},"t":"app"}},"t":"if","then":{"lit":{"kind":"int","value":0},"t":"lit"}},"kind":"fn","name":"loop","params":["n","t"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"},{"k":"con","name":"Tree"}],"ret":{"k":"con","name":"Int"}}},{"body":{"body":{"args":[{"args":[{"lit":{"kind":"int","value":3},"t":"lit"},{"name":"t","t":"var"}],"fn":{"name":"loop","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"name":"t","t":"let","value":{"args":[{"lit":{"kind":"int","value":2},"t":"lit"}],"fn":{"name":"build","t":"var"},"t":"app"}},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"rc_let_alias_implicit_param","schema":"ailang/v0"}
@@ -1 +0,0 @@
{"defs":[{"ctors":[{"fields":[{"k":"con","name":"Int"}],"name":"MkT"}],"kind":"type","name":"T"},{"body":{"args":[{"name":"n","t":"var"}],"ctor":"MkT","t":"ctor","type":"T"},"kind":"fn","name":"alloc","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"T"}}},{"body":{"arms":[{"body":{"name":"v","t":"var"},"pat":{"ctor":"MkT","fields":[{"name":"v","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"x","t":"var"},"t":"match"},"kind":"fn","name":"unbox","params":["x"],"type":{"effects":[],"k":"fn","param_modes":["borrow"],"params":[{"k":"con","name":"T"}],"ret":{"k":"con","name":"Int"}}},{"body":{"body":{"args":[{"args":[{"name":"x","t":"var"}],"fn":{"name":"unbox","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"name":"x","t":"let","value":{"args":[{"lit":{"kind":"int","value":7},"t":"lit"}],"fn":{"name":"alloc","t":"var"},"t":"app"}},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"rc_let_implicit_returning_app","schema":"ailang/v0"}
-1
View File
@@ -1 +0,0 @@
{"defs":[{"ctors":[{"fields":[],"name":"TLeaf"},{"fields":[{"k":"con","name":"Int"},{"k":"con","name":"Tree"},{"k":"con","name":"Tree"}],"name":"TNode"}],"kind":"type","name":"Tree"},{"body":{"cond":{"args":[{"name":"d","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"},"else":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"},{"args":[{"args":[{"name":"d","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"}],"fn":{"name":"build","t":"var"},"t":"app"},{"args":[{"args":[{"name":"d","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"}],"fn":{"name":"build","t":"var"},"t":"app"}],"ctor":"TNode","t":"ctor","type":"Tree"},"t":"if","then":{"args":[],"ctor":"TLeaf","t":"ctor","type":"Tree"}},"kind":"fn","name":"build","params":["d"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Tree"},"ret_mode":"own"}},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":0},"t":"lit"},"pat":{"ctor":"TLeaf","fields":[],"p":"ctor"}},{"body":{"lit":{"kind":"int","value":1},"t":"lit"},"pat":{"ctor":"TNode","fields":[{"name":"v","p":"var"},{"name":"l","p":"var"},{"name":"r","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"t","t":"var"},"t":"match"},"kind":"fn","name":"pin","params":["t"],"type":{"effects":[],"k":"fn","param_modes":["borrow"],"params":[{"k":"con","name":"Tree"}],"ret":{"k":"con","name":"Int"}}},{"body":{"body":{"args":[{"args":[{"name":"t","t":"var"}],"fn":{"name":"pin","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"name":"t","t":"let","value":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"build","t":"var"},"t":"app"}},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"rc_let_owned_app_leak","schema":"ailang/v0"}
-139
View File
@@ -1,139 +0,0 @@
{
"schema": "ailang/v0",
"name": "rc_list_drop",
"imports": [],
"defs": [
{
"kind": "type",
"name": "IntList",
"doc": "Recursive Int list. Iter 18c.4 RC fixture: codegen emits `drop_rc_list_drop_IntList` whose `Cons` arm recursively calls itself on the tail field.",
"ctors": [
{ "name": "Nil", "fields": [] },
{
"name": "Cons",
"fields": [
{ "k": "con", "name": "Int" },
{ "k": "con", "name": "IntList" }
]
}
]
},
{
"kind": "fn",
"name": "sum_list",
"type": {
"k": "fn",
"params": [{ "k": "con", "name": "IntList" }],
"ret": { "k": "con", "name": "Int" },
"effects": []
},
"params": ["xs"],
"doc": "Recursive fold over IntList.",
"body": {
"t": "match",
"scrutinee": { "t": "var", "name": "xs" },
"arms": [
{
"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": "t" }
]
},
"body": {
"t": "app",
"fn": { "t": "var", "name": "+" },
"args": [
{ "t": "var", "name": "h" },
{
"t": "app",
"fn": { "t": "var", "name": "sum_list" },
"args": [{ "t": "var", "name": "t" }]
}
]
}
}
]
}
},
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"doc": "Build a 5-element IntList [1,2,3,4,5] and print its sum (15). Under --alloc=rc the recursive drop_rc_list_drop_IntList fn cascades through the tail at process exit when sum_list returns ownership-implicit (the consume_count of `xs` is 1 so no dec at the outer let; the test's correctness invariant is the byte-identical stdout — leak quantification is 18f's bench).",
"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": "Cons",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 4 } },
{
"t": "ctor",
"type": "IntList",
"ctor": "Cons",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 5 } },
{
"t": "ctor",
"type": "IntList",
"ctor": "Nil",
"args": []
}
]
}
]
}
]
}
]
}
]
},
"body": {
"t": "do",
"op": "io/print_int",
"args": [
{
"t": "app",
"fn": { "t": "var", "name": "sum_list" },
"args": [{ "t": "var", "name": "xs" }]
}
]
}
}
}
]
}
-113
View File
@@ -1,113 +0,0 @@
{
"schema": "ailang/v0",
"name": "rc_list_drop_borrow",
"imports": [],
"defs": [
{
"kind": "type",
"name": "IntList",
"doc": "Recursive Int list. Iter 18c.4 RC fixture: codegen emits a recursive drop fn; this fixture keeps the binder consume_count at 0 so the drop call actually fires at scope close, exercising the recursive cascade at runtime over a 5-element list.",
"ctors": [
{ "name": "Nil", "fields": [] },
{
"name": "Cons",
"fields": [
{ "k": "con", "name": "Int" },
{ "k": "con", "name": "IntList" }
]
}
]
},
{
"kind": "fn",
"name": "main",
"type": {
"k": "fn",
"params": [],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
},
"params": [],
"doc": "Build a 5-element IntList and print only its head via match. xs has consume_count == 0 (only the match scrutinee, a borrow), so under --alloc=rc the let scope close emits `drop_rc_list_drop_borrow_IntList(xs)` which recursively dec-cascades over the whole 5-cell chain.",
"body": {
"t": "let",
"name": "xs",
"value": {
"t": "ctor",
"type": "IntList",
"ctor": "Cons",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 11 } },
{
"t": "ctor",
"type": "IntList",
"ctor": "Cons",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 22 } },
{
"t": "ctor",
"type": "IntList",
"ctor": "Cons",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 33 } },
{
"t": "ctor",
"type": "IntList",
"ctor": "Cons",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 44 } },
{
"t": "ctor",
"type": "IntList",
"ctor": "Cons",
"args": [
{ "t": "lit", "lit": { "kind": "int", "value": 55 } },
{
"t": "ctor",
"type": "IntList",
"ctor": "Nil",
"args": []
}
]
}
]
}
]
}
]
}
]
},
"body": {
"t": "match",
"scrutinee": { "t": "var", "name": "xs" },
"arms": [
{
"pat": { "p": "ctor", "ctor": "Nil", "fields": [] },
"body": {
"t": "do",
"op": "io/print_int",
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 0 } }]
}
},
{
"pat": {
"p": "ctor",
"ctor": "Cons",
"fields": [
{ "p": "var", "name": "h" },
{ "p": "var", "name": "t" }
]
},
"body": {
"t": "do",
"op": "io/print_int",
"args": [{ "t": "var", "name": "h" }]
}
}
]
}
}
}
]
}

Some files were not shown because too many files have changed in this diff Show More