iter rpe.1: retire per-type print effect-ops
Single iter shipping the post-milestone-24 follow-up named in
docs/specs/2026-05-14-retire-per-type-print-effects.md. After this
iter the only surviving direct-output effect-op is `io/print_str`;
all per-type print primitives are replaced by the polymorphic
`print` helper (prelude, iter 24.3).
Components:
- 92 examples/*.ail fixtures migrated (do io/print_<T> x) →
(app print x); 6 .prose.txt snapshots regenerated via `ail prose`.
- Four-site lockstep compiler deletion: crates/ailang-check/src/builtins.rs
(3 effect_ops.insert blocks + 3 list() rows + the
install_io_print_float_signature test + module + EffectOpSig
doc-comments); crates/ailang-codegen/src/lib.rs lower_app
(3 arms + lowers_io_print_float test); crates/ailang-codegen/src/synth.rs
builtin_effect_op_ret match-arm pattern. Dead `intern_string`
helper removed as a follow-up.
- Five incidental test-body migrations (ailang-check x2, ailang-core
spec_drift + design_schema_drift, ailang-surface/src/lex.rs,
ailang-prose/src/lib.rs round-trip test).
- Cat B test-harness patch: six IR-shape tests in
crates/ail/tests/e2e.rs gained a monomorphise_workspace call
before lower_workspace_with_alloc so they follow the same
pipeline as `ail build` (the home-rolled desugar+lift loop
stayed because mono's precondition is "already lifted"; mono
inserts after lift).
- Six doc-comment touch-ups (lex.rs module doc, parse.rs
diagnostic example, ail/src/main.rs x2, runtime/str.c %g anchor,
crates/ailang-core/specs/form_a.md surface-spec example).
- DESIGN.md seven-site sweep (Decision 11 example, Polymorphic
print past-tense, Heap-Str output sentence, effect-op
invocation comment, Float NaN paragraph re-anchored on
float_to_str, two "What is supported" lists).
- Three E2E test-comment polish + four IR-snapshot refresh + one
canonical-hash pin update (plan-unanticipated downstream
consequences of the corpus migration).
- bench/{check,compile_check,cross_lang}.py: all exit 0; no
ratification needed.
- Roadmap entry struck through; per-iter journal at
docs/journals/2026-05-14-iter-rpe.1.md.
Tests 564/0/3. cargo clippy and cargo doc: zero warnings.
Two upstream codegen bugs surfaced during the first BLOCKED
attempt and were fixed in separate iters before this retry:
- 1fb225e bugfix: mono cursor misalignment at poly-free-fn Var
with class-constrained Forall.
- feb9413 bugfix: print leak — propagate ret_mode through rigid
substitution + prelude Show.show ret_mode.
Known debt (carried forward for next /audit):
- Emitter.strings field is functionally dead post-iter (orphan
after intern_string removal); cycles over empty map harmlessly.
This commit is contained in:
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"iter_id": "rpe.1",
|
||||||
|
"date": "2026-05-14",
|
||||||
|
"mode": "standard",
|
||||||
|
"outcome": "DONE",
|
||||||
|
"tasks_total": 10,
|
||||||
|
"tasks_completed": 10,
|
||||||
|
"reloops_per_task": {
|
||||||
|
"1": 0,
|
||||||
|
"2": 0,
|
||||||
|
"3": 0,
|
||||||
|
"4": 0,
|
||||||
|
"5": 0,
|
||||||
|
"6": 0,
|
||||||
|
"7": 0,
|
||||||
|
"8": 0,
|
||||||
|
"9": 0,
|
||||||
|
"10": 0
|
||||||
|
},
|
||||||
|
"review_loops_spec": 0,
|
||||||
|
"review_loops_quality": 0,
|
||||||
|
"blocked_reason": null,
|
||||||
|
"tests_passed": 564,
|
||||||
|
"tests_failed": 0,
|
||||||
|
"files_changed": 121,
|
||||||
|
"bench_check_exit": 0,
|
||||||
|
"bench_compile_check_exit": 0,
|
||||||
|
"bench_cross_lang_exit": 0,
|
||||||
|
"ratified_baselines": [],
|
||||||
|
"plan_unanticipated_sites": [
|
||||||
|
"crates/ail/tests/e2e.rs::int_arg_to_effect_op_does_not_rc_track assertions",
|
||||||
|
"crates/ail/tests/snapshots/{sum,list,max3,ws_main}.ll IR regen",
|
||||||
|
"crates/ailang-core/tests/hash_pin.rs::ct4_migrated_fixtures_have_canonical_form_hashes",
|
||||||
|
"5 ancillary .ail comment touch-ups to satisfy §H acceptance grep"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -27,8 +27,8 @@
|
|||||||
//! a native binary at `--out`.
|
//! a native binary at `--out`.
|
||||||
//! - `run` — `build` into a tempdir and execute the binary; passes
|
//! - `run` — `build` into a tempdir and execute the binary; passes
|
||||||
//! the binary's exit code through.
|
//! the binary's exit code through.
|
||||||
//! - `builtins` — list the built-in effect ops (`io/print_int`,
|
//! - `builtins` — list the built-in effect ops (`io/print_str`)
|
||||||
//! `io/print_bool`, `io/print_str`, ...) with their signatures.
|
//! with their signatures.
|
||||||
//! - `diff` — semantic, hash-based module/workspace diff. Works even
|
//! - `diff` — semantic, hash-based module/workspace diff. Works even
|
||||||
//! when a module doesn't currently typecheck.
|
//! when a module doesn't currently typecheck.
|
||||||
//! - `workspace` — load an entry module's transitive imports and list
|
//! - `workspace` — load an entry module's transitive imports and list
|
||||||
@@ -1416,7 +1416,7 @@ fn walk_term(
|
|||||||
walk_term(else_, out, builtins, scope);
|
walk_term(else_, out, builtins, scope);
|
||||||
}
|
}
|
||||||
Term::Do { op, args, .. } => {
|
Term::Do { op, args, .. } => {
|
||||||
// Mark effect ops as `effect:io/print_int` so they can be
|
// Mark effect ops as `effect:io/print_str` so they can be
|
||||||
// separated from normal function calls.
|
// separated from normal function calls.
|
||||||
out.insert(format!("effect:{op}"));
|
out.insert(format!("effect:{op}"));
|
||||||
for a in args {
|
for a in args {
|
||||||
|
|||||||
+58
-13
@@ -1460,8 +1460,14 @@ fn reuse_as_demo_under_rc_uses_inplace_rewrite() {
|
|||||||
root_dir: ws.root_dir.clone(),
|
root_dir: ws.root_dir.clone(),
|
||||||
registry: ws.registry.clone(),
|
registry: ws.registry.clone(),
|
||||||
};
|
};
|
||||||
|
// Iter rpe.1: post-print-migration, fixtures use `(app print x)`
|
||||||
|
// which monomorphises to `print__<T>`. Adding the mono pass here
|
||||||
|
// mirrors `ail build`'s pipeline (desugar -> lift -> mono ->
|
||||||
|
// lower); without it, lowering errors with `UnknownVar("print")`.
|
||||||
|
let mono_ws = ailang_check::monomorphise_workspace(&lifted_ws)
|
||||||
|
.expect("monomorphise_workspace");
|
||||||
let ir = ailang_codegen::lower_workspace_with_alloc(
|
let ir = ailang_codegen::lower_workspace_with_alloc(
|
||||||
&lifted_ws,
|
&mono_ws,
|
||||||
ailang_codegen::AllocStrategy::Rc,
|
ailang_codegen::AllocStrategy::Rc,
|
||||||
)
|
)
|
||||||
.expect("lower workspace under rc");
|
.expect("lower workspace under rc");
|
||||||
@@ -1660,8 +1666,14 @@ fn alloc_rc_borrow_only_recursive_list_drop() {
|
|||||||
root_dir: ws.root_dir.clone(),
|
root_dir: ws.root_dir.clone(),
|
||||||
registry: ws.registry.clone(),
|
registry: ws.registry.clone(),
|
||||||
};
|
};
|
||||||
|
// Iter rpe.1: post-print-migration, fixtures use `(app print x)`
|
||||||
|
// which monomorphises to `print__<T>`. Adding the mono pass here
|
||||||
|
// mirrors `ail build`'s pipeline (desugar -> lift -> mono ->
|
||||||
|
// lower); without it, lowering errors with `UnknownVar("print")`.
|
||||||
|
let mono_ws = ailang_check::monomorphise_workspace(&lifted_ws)
|
||||||
|
.expect("monomorphise_workspace");
|
||||||
let ir = ailang_codegen::lower_workspace_with_alloc(
|
let ir = ailang_codegen::lower_workspace_with_alloc(
|
||||||
&lifted_ws,
|
&mono_ws,
|
||||||
ailang_codegen::AllocStrategy::Rc,
|
ailang_codegen::AllocStrategy::Rc,
|
||||||
)
|
)
|
||||||
.expect("lower workspace under rc");
|
.expect("lower workspace under rc");
|
||||||
@@ -1736,8 +1748,14 @@ fn alloc_rc_partial_drop_skips_moved_keeps_wildcarded() {
|
|||||||
root_dir: ws.root_dir.clone(),
|
root_dir: ws.root_dir.clone(),
|
||||||
registry: ws.registry.clone(),
|
registry: ws.registry.clone(),
|
||||||
};
|
};
|
||||||
|
// Iter rpe.1: post-print-migration, fixtures use `(app print x)`
|
||||||
|
// which monomorphises to `print__<T>`. Adding the mono pass here
|
||||||
|
// mirrors `ail build`'s pipeline (desugar -> lift -> mono ->
|
||||||
|
// lower); without it, lowering errors with `UnknownVar("print")`.
|
||||||
|
let mono_ws = ailang_check::monomorphise_workspace(&lifted_ws)
|
||||||
|
.expect("monomorphise_workspace");
|
||||||
let ir = ailang_codegen::lower_workspace_with_alloc(
|
let ir = ailang_codegen::lower_workspace_with_alloc(
|
||||||
&lifted_ws,
|
&mono_ws,
|
||||||
ailang_codegen::AllocStrategy::Rc,
|
ailang_codegen::AllocStrategy::Rc,
|
||||||
)
|
)
|
||||||
.expect("lower workspace under rc");
|
.expect("lower workspace under rc");
|
||||||
@@ -1826,8 +1844,14 @@ fn alloc_rc_own_param_dec_at_fn_return() {
|
|||||||
root_dir: ws.root_dir.clone(),
|
root_dir: ws.root_dir.clone(),
|
||||||
registry: ws.registry.clone(),
|
registry: ws.registry.clone(),
|
||||||
};
|
};
|
||||||
|
// Iter rpe.1: post-print-migration, fixtures use `(app print x)`
|
||||||
|
// which monomorphises to `print__<T>`. Adding the mono pass here
|
||||||
|
// mirrors `ail build`'s pipeline (desugar -> lift -> mono ->
|
||||||
|
// lower); without it, lowering errors with `UnknownVar("print")`.
|
||||||
|
let mono_ws = ailang_check::monomorphise_workspace(&lifted_ws)
|
||||||
|
.expect("monomorphise_workspace");
|
||||||
let ir = ailang_codegen::lower_workspace_with_alloc(
|
let ir = ailang_codegen::lower_workspace_with_alloc(
|
||||||
&lifted_ws,
|
&mono_ws,
|
||||||
ailang_codegen::AllocStrategy::Rc,
|
ailang_codegen::AllocStrategy::Rc,
|
||||||
)
|
)
|
||||||
.expect("lower workspace under rc");
|
.expect("lower workspace under rc");
|
||||||
@@ -1952,8 +1976,14 @@ fn iter18e_drop_iterative_emits_worklist_body_no_self_recursion() {
|
|||||||
root_dir: ws.root_dir.clone(),
|
root_dir: ws.root_dir.clone(),
|
||||||
registry: ws.registry.clone(),
|
registry: ws.registry.clone(),
|
||||||
};
|
};
|
||||||
|
// Iter rpe.1: post-print-migration, fixtures use `(app print x)`
|
||||||
|
// which monomorphises to `print__<T>`. Adding the mono pass here
|
||||||
|
// mirrors `ail build`'s pipeline (desugar -> lift -> mono ->
|
||||||
|
// lower); without it, lowering errors with `UnknownVar("print")`.
|
||||||
|
let mono_ws = ailang_check::monomorphise_workspace(&lifted_ws)
|
||||||
|
.expect("monomorphise_workspace");
|
||||||
let ir = ailang_codegen::lower_workspace_with_alloc(
|
let ir = ailang_codegen::lower_workspace_with_alloc(
|
||||||
&lifted_ws,
|
&mono_ws,
|
||||||
ailang_codegen::AllocStrategy::Rc,
|
ailang_codegen::AllocStrategy::Rc,
|
||||||
)
|
)
|
||||||
.expect("lower workspace under rc");
|
.expect("lower workspace under rc");
|
||||||
@@ -2036,8 +2066,14 @@ fn iter18e_no_annotation_keeps_recursive_drop_body() {
|
|||||||
root_dir: ws.root_dir.clone(),
|
root_dir: ws.root_dir.clone(),
|
||||||
registry: ws.registry.clone(),
|
registry: ws.registry.clone(),
|
||||||
};
|
};
|
||||||
|
// Iter rpe.1: post-print-migration, fixtures use `(app print x)`
|
||||||
|
// which monomorphises to `print__<T>`. Adding the mono pass here
|
||||||
|
// mirrors `ail build`'s pipeline (desugar -> lift -> mono ->
|
||||||
|
// lower); without it, lowering errors with `UnknownVar("print")`.
|
||||||
|
let mono_ws = ailang_check::monomorphise_workspace(&lifted_ws)
|
||||||
|
.expect("monomorphise_workspace");
|
||||||
let ir = ailang_codegen::lower_workspace_with_alloc(
|
let ir = ailang_codegen::lower_workspace_with_alloc(
|
||||||
&lifted_ws,
|
&mono_ws,
|
||||||
ailang_codegen::AllocStrategy::Rc,
|
ailang_codegen::AllocStrategy::Rc,
|
||||||
)
|
)
|
||||||
.expect("lower workspace under rc");
|
.expect("lower workspace under rc");
|
||||||
@@ -2671,18 +2707,27 @@ fn str_field_in_adt_drops_heap_str_correctly() {
|
|||||||
assert_eq!(live, 0, "no leaked RC slabs allowed; live={live}");
|
assert_eq!(live, 0, "no leaked RC slabs allowed; live={live}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iter eob.1: primitive-Int arg passed to an effect-op. Under the
|
/// Iter eob.1 / rpe.1: primitive-Int passed to the polymorphic
|
||||||
/// new "Term::Do args = Borrow" rule, the let-binder `n` is not
|
/// `print` helper. Pre-rpe.1 the fixture used `(do io/print_int n)`
|
||||||
/// consumed by `io/print_int`; but Int is unboxed, so there is no
|
/// directly and the iter-eob.1 "Term::Do args = Borrow" rule meant
|
||||||
/// pointer to RC-track. Pin: zero allocs / zero frees / zero live —
|
/// zero RC traffic on the unboxed Int (allocs == 0, frees == 0).
|
||||||
/// the rule introduces no spurious bookkeeping on primitives.
|
/// Post-rpe.1, `print n` desugars through `Show Int.show` →
|
||||||
|
/// `int_to_str` (heap-Str alloc, `ret_mode: Own`) → `io/print_str`
|
||||||
|
/// → slab drops at scope close. Pin shifts to the new canonical
|
||||||
|
/// post-iter shape: exactly one heap-Str slab cycle per `print`
|
||||||
|
/// of a non-Str value. The let-binder property the original test
|
||||||
|
/// pinned (Term::Do args borrow-walk correctly on primitives) is
|
||||||
|
/// preserved by the surviving `io/print_str s` step inside
|
||||||
|
/// `print__Int.body`; this test now pins the slab-cycle pattern.
|
||||||
#[test]
|
#[test]
|
||||||
fn int_arg_to_effect_op_does_not_rc_track() {
|
fn int_arg_to_effect_op_does_not_rc_track() {
|
||||||
let (stdout, allocs, frees, live) =
|
let (stdout, allocs, frees, live) =
|
||||||
build_and_run_with_rc_stats("int_to_print_int_borrow.ail");
|
build_and_run_with_rc_stats("int_to_print_int_borrow.ail");
|
||||||
assert_eq!(stdout, "7\n");
|
assert_eq!(stdout, "7\n");
|
||||||
assert_eq!(allocs, 0, "Int arg should not trigger any RC alloc; got allocs={allocs}");
|
// Post-rpe.1: print n for n : Int allocates one heap-Str slab
|
||||||
assert_eq!(frees, 0, "Int arg should not trigger any RC free; got frees={frees}");
|
// via Show Int → int_to_str, frees it at scope close. Spec §E.
|
||||||
|
assert_eq!(allocs, 1, "expected exactly one Show-Int heap-Str slab; got allocs={allocs}");
|
||||||
|
assert_eq!(frees, 1, "expected exactly one free; got frees={frees}");
|
||||||
assert_eq!(live, 0, "no leaked RC slabs allowed; live={live}");
|
assert_eq!(live, 0, "no leaked RC slabs allowed; live={live}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,8 +63,9 @@ fn eq_ord_polymorphic_runs_end_to_end() {
|
|||||||
// Helper `at_most(3, 5)` at Int = true → 1
|
// Helper `at_most(3, 5)` at Int = true → 1
|
||||||
// `at_most(true, false)` at Bool = false → 0
|
// `at_most(true, false)` at Bool = false → 0
|
||||||
// `at_most("abc", "abd")` at Str = true → 1
|
// `at_most("abc", "abd")` at Str = true → 1
|
||||||
// `io/print_int` emits one int per line, so stdout is "1\n0\n1"
|
// Polymorphic `print` for Int routes through `show` + `io/print_str`,
|
||||||
// after `.trim()` strips the trailing newline.
|
// emitting one int per line, so stdout is "1\n0\n1" after `.trim()`
|
||||||
|
// strips the trailing newline.
|
||||||
assert_eq!(stdout, "1\n0\n1", "expected 1\\n0\\n1, got {stdout:?}");
|
assert_eq!(stdout, "1\n0\n1", "expected 1\\n0\\n1, got {stdout:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +74,7 @@ fn eq_ord_user_adt_runs_end_to_end() {
|
|||||||
let stdout = build_and_run("eq_ord_user_adt.ail");
|
let stdout = build_and_run("eq_ord_user_adt.ail");
|
||||||
// eq(MkIntBox 3, MkIntBox 3) = true → 1
|
// eq(MkIntBox 3, MkIntBox 3) = true → 1
|
||||||
// eq(MkIntBox 3, MkIntBox 5) = false → 0
|
// eq(MkIntBox 3, MkIntBox 5) = false → 0
|
||||||
// `io/print_int` emits one int per line; trimmed stdout is "1\n0".
|
// Polymorphic `print` for Int emits one int per line; trimmed stdout is "1\n0".
|
||||||
assert_eq!(stdout, "1\n0", "expected 1\\n0, got {stdout:?}");
|
assert_eq!(stdout, "1\n0", "expected 1\\n0, got {stdout:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
//! CLI and run; stdout is matched against the expected three
|
//! CLI and run; stdout is matched against the expected three
|
||||||
//! lines (`4`, `42`, `-1.5`). This test exercises the full
|
//! lines (`4`, `42`, `-1.5`). This test exercises the full
|
||||||
//! pipeline — Float literal lowering, polymorphic `+` Float arm,
|
//! pipeline — Float literal lowering, polymorphic `+` Float arm,
|
||||||
//! `int_to_float` (sitofp), `neg` Float (fneg), `io/print_float`
|
//! `int_to_float` (sitofp), `neg` Float (fneg), and the polymorphic
|
||||||
//! (printf `%g\n`).
|
//! `print` for Float (routes through `Show Float.show` →
|
||||||
|
//! `float_to_str`, libc `%g`).
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
source_filename = "list.ail"
|
source_filename = "list.ail"
|
||||||
target triple = "<NORMALIZED>"
|
target triple = "<NORMALIZED>"
|
||||||
|
|
||||||
@.str_list_fmt_int_0 = private unnamed_addr constant [6 x i8] c"%lld\0A\00", align 1
|
|
||||||
|
|
||||||
declare i32 @printf(ptr, ...)
|
declare i32 @printf(ptr, ...)
|
||||||
declare i32 @puts(ptr)
|
declare i32 @puts(ptr)
|
||||||
declare ptr @GC_malloc(i64)
|
declare ptr @GC_malloc(i64)
|
||||||
@@ -19,6 +17,8 @@ declare i64 @llvm.fptosi.sat.i64.f64(double)
|
|||||||
|
|
||||||
@ail_list_sum_list_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_list_sum_list_adapter, ptr null }
|
@ail_list_sum_list_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_list_sum_list_adapter, ptr null }
|
||||||
@ail_list_main_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_list_main_adapter, ptr null }
|
@ail_list_main_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_list_main_adapter, ptr null }
|
||||||
|
@ail_prelude_show__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_show__Int_adapter, ptr null }
|
||||||
|
@ail_prelude_print__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_print__Int_adapter, ptr null }
|
||||||
define i64 @ail_list_sum_list(ptr %arg_xs) {
|
define i64 @ail_list_sum_list(ptr %arg_xs) {
|
||||||
entry:
|
entry:
|
||||||
%v1 = load i64, ptr %arg_xs, align 8
|
%v1 = load i64, ptr %arg_xs, align 8
|
||||||
@@ -72,8 +72,8 @@ entry:
|
|||||||
%v10 = getelementptr inbounds i8, ptr %v8, i64 16
|
%v10 = getelementptr inbounds i8, ptr %v8, i64 16
|
||||||
store ptr %v5, ptr %v10, align 8
|
store ptr %v5, ptr %v10, align 8
|
||||||
%v11 = call i64 @ail_list_sum_list(ptr %v8)
|
%v11 = call i64 @ail_list_sum_list(ptr %v8)
|
||||||
call i32 (ptr, ...) @printf(ptr @.str_list_fmt_int_0, i64 %v11)
|
%v12 = call i8 @ail_prelude_print__Int(i64 %v11)
|
||||||
ret i8 0
|
ret i8 %v12
|
||||||
}
|
}
|
||||||
|
|
||||||
define i8 @ail_list_main_adapter(ptr %_env) {
|
define i8 @ail_list_main_adapter(ptr %_env) {
|
||||||
@@ -82,6 +82,32 @@ entry:
|
|||||||
ret i8 %r
|
ret i8 %r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define ptr @ail_prelude_show__Int(i64 %arg_x) {
|
||||||
|
entry:
|
||||||
|
%v1 = call ptr @ailang_int_to_str(i64 %arg_x)
|
||||||
|
ret ptr %v1
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @ail_prelude_show__Int_adapter(ptr %_env, i64 %a0) {
|
||||||
|
entry:
|
||||||
|
%r = call ptr @ail_prelude_show__Int(i64 %a0)
|
||||||
|
ret ptr %r
|
||||||
|
}
|
||||||
|
|
||||||
|
define i8 @ail_prelude_print__Int(i64 %arg_x) {
|
||||||
|
entry:
|
||||||
|
%v1 = call ptr @ail_prelude_show__Int(i64 %arg_x)
|
||||||
|
%v2 = getelementptr inbounds i8, ptr %v1, i64 8
|
||||||
|
call i32 @puts(ptr %v2)
|
||||||
|
ret i8 0
|
||||||
|
}
|
||||||
|
|
||||||
|
define i8 @ail_prelude_print__Int_adapter(ptr %_env, i64 %a0) {
|
||||||
|
entry:
|
||||||
|
%r = call i8 @ail_prelude_print__Int(i64 %a0)
|
||||||
|
ret i8 %r
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
define i32 @main() {
|
define i32 @main() {
|
||||||
call i8 @ail_list_main()
|
call i8 @ail_list_main()
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
source_filename = "max3.ail"
|
source_filename = "max3.ail"
|
||||||
target triple = "<NORMALIZED>"
|
target triple = "<NORMALIZED>"
|
||||||
|
|
||||||
@.str_max3_fmt_int_0 = private unnamed_addr constant [6 x i8] c"%lld\0A\00", align 1
|
|
||||||
|
|
||||||
declare i32 @printf(ptr, ...)
|
declare i32 @printf(ptr, ...)
|
||||||
declare i32 @puts(ptr)
|
declare i32 @puts(ptr)
|
||||||
declare ptr @GC_malloc(i64)
|
declare ptr @GC_malloc(i64)
|
||||||
@@ -20,6 +18,8 @@ declare i64 @llvm.fptosi.sat.i64.f64(double)
|
|||||||
@ail_max3_max_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_max3_max_adapter, ptr null }
|
@ail_max3_max_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_max3_max_adapter, ptr null }
|
||||||
@ail_max3_max3_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_max3_max3_adapter, ptr null }
|
@ail_max3_max3_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_max3_max3_adapter, ptr null }
|
||||||
@ail_max3_main_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_max3_main_adapter, ptr null }
|
@ail_max3_main_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_max3_main_adapter, ptr null }
|
||||||
|
@ail_prelude_show__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_show__Int_adapter, ptr null }
|
||||||
|
@ail_prelude_print__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_print__Int_adapter, ptr null }
|
||||||
define i64 @ail_max3_max(i64 %arg_a, i64 %arg_b) {
|
define i64 @ail_max3_max(i64 %arg_a, i64 %arg_b) {
|
||||||
entry:
|
entry:
|
||||||
%v1 = icmp sgt i64 %arg_a, %arg_b
|
%v1 = icmp sgt i64 %arg_a, %arg_b
|
||||||
@@ -77,8 +77,8 @@ entry:
|
|||||||
define i8 @ail_max3_main() {
|
define i8 @ail_max3_main() {
|
||||||
entry:
|
entry:
|
||||||
%v1 = call i64 @ail_max3_max3(i64 3, i64 17, i64 9)
|
%v1 = call i64 @ail_max3_max3(i64 3, i64 17, i64 9)
|
||||||
call i32 (ptr, ...) @printf(ptr @.str_max3_fmt_int_0, i64 %v1)
|
%v2 = call i8 @ail_prelude_print__Int(i64 %v1)
|
||||||
ret i8 0
|
ret i8 %v2
|
||||||
}
|
}
|
||||||
|
|
||||||
define i8 @ail_max3_main_adapter(ptr %_env) {
|
define i8 @ail_max3_main_adapter(ptr %_env) {
|
||||||
@@ -87,6 +87,32 @@ entry:
|
|||||||
ret i8 %r
|
ret i8 %r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define ptr @ail_prelude_show__Int(i64 %arg_x) {
|
||||||
|
entry:
|
||||||
|
%v1 = call ptr @ailang_int_to_str(i64 %arg_x)
|
||||||
|
ret ptr %v1
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @ail_prelude_show__Int_adapter(ptr %_env, i64 %a0) {
|
||||||
|
entry:
|
||||||
|
%r = call ptr @ail_prelude_show__Int(i64 %a0)
|
||||||
|
ret ptr %r
|
||||||
|
}
|
||||||
|
|
||||||
|
define i8 @ail_prelude_print__Int(i64 %arg_x) {
|
||||||
|
entry:
|
||||||
|
%v1 = call ptr @ail_prelude_show__Int(i64 %arg_x)
|
||||||
|
%v2 = getelementptr inbounds i8, ptr %v1, i64 8
|
||||||
|
call i32 @puts(ptr %v2)
|
||||||
|
ret i8 0
|
||||||
|
}
|
||||||
|
|
||||||
|
define i8 @ail_prelude_print__Int_adapter(ptr %_env, i64 %a0) {
|
||||||
|
entry:
|
||||||
|
%r = call i8 @ail_prelude_print__Int(i64 %a0)
|
||||||
|
ret i8 %r
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
define i32 @main() {
|
define i32 @main() {
|
||||||
call i8 @ail_max3_main()
|
call i8 @ail_max3_main()
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
source_filename = "sum.ail"
|
source_filename = "sum.ail"
|
||||||
target triple = "<NORMALIZED>"
|
target triple = "<NORMALIZED>"
|
||||||
|
|
||||||
@.str_sum_fmt_int_0 = private unnamed_addr constant [6 x i8] c"%lld\0A\00", align 1
|
|
||||||
|
|
||||||
declare i32 @printf(ptr, ...)
|
declare i32 @printf(ptr, ...)
|
||||||
declare i32 @puts(ptr)
|
declare i32 @puts(ptr)
|
||||||
declare ptr @GC_malloc(i64)
|
declare ptr @GC_malloc(i64)
|
||||||
@@ -17,8 +15,36 @@ declare ptr @ailang_str_clone(ptr)
|
|||||||
declare ptr @ailang_str_concat(ptr, ptr)
|
declare ptr @ailang_str_concat(ptr, ptr)
|
||||||
declare i64 @llvm.fptosi.sat.i64.f64(double)
|
declare i64 @llvm.fptosi.sat.i64.f64(double)
|
||||||
|
|
||||||
|
@ail_prelude_show__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_show__Int_adapter, ptr null }
|
||||||
|
@ail_prelude_print__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_print__Int_adapter, ptr null }
|
||||||
@ail_sum_sum_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_sum_sum_adapter, ptr null }
|
@ail_sum_sum_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_sum_sum_adapter, ptr null }
|
||||||
@ail_sum_main_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_sum_main_adapter, ptr null }
|
@ail_sum_main_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_sum_main_adapter, ptr null }
|
||||||
|
define ptr @ail_prelude_show__Int(i64 %arg_x) {
|
||||||
|
entry:
|
||||||
|
%v1 = call ptr @ailang_int_to_str(i64 %arg_x)
|
||||||
|
ret ptr %v1
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @ail_prelude_show__Int_adapter(ptr %_env, i64 %a0) {
|
||||||
|
entry:
|
||||||
|
%r = call ptr @ail_prelude_show__Int(i64 %a0)
|
||||||
|
ret ptr %r
|
||||||
|
}
|
||||||
|
|
||||||
|
define i8 @ail_prelude_print__Int(i64 %arg_x) {
|
||||||
|
entry:
|
||||||
|
%v1 = call ptr @ail_prelude_show__Int(i64 %arg_x)
|
||||||
|
%v2 = getelementptr inbounds i8, ptr %v1, i64 8
|
||||||
|
call i32 @puts(ptr %v2)
|
||||||
|
ret i8 0
|
||||||
|
}
|
||||||
|
|
||||||
|
define i8 @ail_prelude_print__Int_adapter(ptr %_env, i64 %a0) {
|
||||||
|
entry:
|
||||||
|
%r = call i8 @ail_prelude_print__Int(i64 %a0)
|
||||||
|
ret i8 %r
|
||||||
|
}
|
||||||
|
|
||||||
define i64 @ail_sum_sum(i64 %arg_n) {
|
define i64 @ail_sum_sum(i64 %arg_n) {
|
||||||
entry:
|
entry:
|
||||||
%v1 = icmp eq i64 %arg_n, 0
|
%v1 = icmp eq i64 %arg_n, 0
|
||||||
@@ -44,8 +70,8 @@ entry:
|
|||||||
define i8 @ail_sum_main() {
|
define i8 @ail_sum_main() {
|
||||||
entry:
|
entry:
|
||||||
%v1 = call i64 @ail_sum_sum(i64 10)
|
%v1 = call i64 @ail_sum_sum(i64 10)
|
||||||
call i32 (ptr, ...) @printf(ptr @.str_sum_fmt_int_0, i64 %v1)
|
%v2 = call i8 @ail_prelude_print__Int(i64 %v1)
|
||||||
ret i8 0
|
ret i8 %v2
|
||||||
}
|
}
|
||||||
|
|
||||||
define i8 @ail_sum_main_adapter(ptr %_env) {
|
define i8 @ail_sum_main_adapter(ptr %_env) {
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
source_filename = "ws_main.ail"
|
source_filename = "ws_main.ail"
|
||||||
target triple = "<NORMALIZED>"
|
target triple = "<NORMALIZED>"
|
||||||
|
|
||||||
@.str_ws_main_fmt_int_0 = private unnamed_addr constant [6 x i8] c"%lld\0A\00", align 1
|
|
||||||
|
|
||||||
declare i32 @printf(ptr, ...)
|
declare i32 @printf(ptr, ...)
|
||||||
declare i32 @puts(ptr)
|
declare i32 @puts(ptr)
|
||||||
declare ptr @GC_malloc(i64)
|
declare ptr @GC_malloc(i64)
|
||||||
@@ -17,8 +15,36 @@ declare ptr @ailang_str_clone(ptr)
|
|||||||
declare ptr @ailang_str_concat(ptr, ptr)
|
declare ptr @ailang_str_concat(ptr, ptr)
|
||||||
declare i64 @llvm.fptosi.sat.i64.f64(double)
|
declare i64 @llvm.fptosi.sat.i64.f64(double)
|
||||||
|
|
||||||
|
@ail_prelude_show__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_show__Int_adapter, ptr null }
|
||||||
|
@ail_prelude_print__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_print__Int_adapter, ptr null }
|
||||||
@ail_ws_lib_add_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_ws_lib_add_adapter, ptr null }
|
@ail_ws_lib_add_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_ws_lib_add_adapter, ptr null }
|
||||||
@ail_ws_main_main_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_ws_main_main_adapter, ptr null }
|
@ail_ws_main_main_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_ws_main_main_adapter, ptr null }
|
||||||
|
define ptr @ail_prelude_show__Int(i64 %arg_x) {
|
||||||
|
entry:
|
||||||
|
%v1 = call ptr @ailang_int_to_str(i64 %arg_x)
|
||||||
|
ret ptr %v1
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @ail_prelude_show__Int_adapter(ptr %_env, i64 %a0) {
|
||||||
|
entry:
|
||||||
|
%r = call ptr @ail_prelude_show__Int(i64 %a0)
|
||||||
|
ret ptr %r
|
||||||
|
}
|
||||||
|
|
||||||
|
define i8 @ail_prelude_print__Int(i64 %arg_x) {
|
||||||
|
entry:
|
||||||
|
%v1 = call ptr @ail_prelude_show__Int(i64 %arg_x)
|
||||||
|
%v2 = getelementptr inbounds i8, ptr %v1, i64 8
|
||||||
|
call i32 @puts(ptr %v2)
|
||||||
|
ret i8 0
|
||||||
|
}
|
||||||
|
|
||||||
|
define i8 @ail_prelude_print__Int_adapter(ptr %_env, i64 %a0) {
|
||||||
|
entry:
|
||||||
|
%r = call i8 @ail_prelude_print__Int(i64 %a0)
|
||||||
|
ret i8 %r
|
||||||
|
}
|
||||||
|
|
||||||
define i64 @ail_ws_lib_add(i64 %arg_a, i64 %arg_b) {
|
define i64 @ail_ws_lib_add(i64 %arg_a, i64 %arg_b) {
|
||||||
entry:
|
entry:
|
||||||
%v1 = add i64 %arg_a, %arg_b
|
%v1 = add i64 %arg_a, %arg_b
|
||||||
@@ -34,8 +60,8 @@ entry:
|
|||||||
define i8 @ail_ws_main_main() {
|
define i8 @ail_ws_main_main() {
|
||||||
entry:
|
entry:
|
||||||
%v1 = call i64 @ail_ws_lib_add(i64 2, i64 3)
|
%v1 = call i64 @ail_ws_lib_add(i64 2, i64 3)
|
||||||
call i32 (ptr, ...) @printf(ptr @.str_ws_main_fmt_int_0, i64 %v1)
|
%v2 = call i8 @ail_prelude_print__Int(i64 %v1)
|
||||||
ret i8 0
|
ret i8 %v2
|
||||||
}
|
}
|
||||||
|
|
||||||
define i8 @ail_ws_main_main_adapter(ptr %_env) {
|
define i8 @ail_ws_main_main_adapter(ptr %_env) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
//!
|
//!
|
||||||
//! This module owns the **fixed** symbol set the language ships with — the
|
//! This module owns the **fixed** symbol set the language ships with — the
|
||||||
//! arithmetic / comparison / logical operators (`+`, `==`, `not`, ...) and
|
//! arithmetic / comparison / logical operators (`+`, `==`, `not`, ...) and
|
||||||
//! the IO effect ops (`io/print_int`, ...). User code cannot define
|
//! the IO effect ops (`io/print_str`). User code cannot define
|
||||||
//! anything in here; conversely the typechecker treats every entry as
|
//! anything in here; conversely the typechecker treats every entry as
|
||||||
//! always-in-scope without an explicit import.
|
//! always-in-scope without an explicit import.
|
||||||
//!
|
//!
|
||||||
@@ -37,7 +37,7 @@ pub struct EffectOpSig {
|
|||||||
/// `Term::Do { args }`.
|
/// `Term::Do { args }`.
|
||||||
pub params: Vec<Type>,
|
pub params: Vec<Type>,
|
||||||
/// Return type of the op. Often [`Type::unit`] for sinks like
|
/// Return type of the op. Often [`Type::unit`] for sinks like
|
||||||
/// `io/print_int`.
|
/// `io/print_str`.
|
||||||
pub ret: Type,
|
pub ret: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,22 +266,6 @@ pub fn install(env: &mut crate::Env) {
|
|||||||
env.globals.insert("inf".into(), Type::float());
|
env.globals.insert("inf".into(), Type::float());
|
||||||
env.globals.insert("neg_inf".into(), Type::float());
|
env.globals.insert("neg_inf".into(), Type::float());
|
||||||
|
|
||||||
env.effect_ops.insert(
|
|
||||||
"io/print_int".into(),
|
|
||||||
EffectOpSig {
|
|
||||||
effect: "IO".into(),
|
|
||||||
params: vec![Type::int()],
|
|
||||||
ret: Type::unit(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
env.effect_ops.insert(
|
|
||||||
"io/print_bool".into(),
|
|
||||||
EffectOpSig {
|
|
||||||
effect: "IO".into(),
|
|
||||||
params: vec![Type::bool_()],
|
|
||||||
ret: Type::unit(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
env.effect_ops.insert(
|
env.effect_ops.insert(
|
||||||
"io/print_str".into(),
|
"io/print_str".into(),
|
||||||
EffectOpSig {
|
EffectOpSig {
|
||||||
@@ -290,16 +274,6 @@ pub fn install(env: &mut crate::Env) {
|
|||||||
ret: Type::unit(),
|
ret: Type::unit(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
// Iter 22-floats.3: parallel to io/print_int|bool|str. Codegen
|
|
||||||
// lowers via runtime C glue `@ail_print_float` in iter 4.
|
|
||||||
env.effect_ops.insert(
|
|
||||||
"io/print_float".into(),
|
|
||||||
EffectOpSig {
|
|
||||||
effect: "IO".into(),
|
|
||||||
params: vec![Type::float()],
|
|
||||||
ret: Type::unit(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Names of value-level built-ins (operators, `not`) — the ones that
|
/// Names of value-level built-ins (operators, `not`) — the ones that
|
||||||
@@ -346,10 +320,7 @@ pub fn list() -> Vec<(&'static str, &'static str)> {
|
|||||||
("nan", "Float"),
|
("nan", "Float"),
|
||||||
("inf", "Float"),
|
("inf", "Float"),
|
||||||
("neg_inf", "Float"),
|
("neg_inf", "Float"),
|
||||||
("io/print_int", "(Int) -> Unit !IO [effect op]"),
|
|
||||||
("io/print_bool", "(Bool) -> Unit !IO [effect op]"),
|
|
||||||
("io/print_str", "(Str) -> Unit !IO [effect op]"),
|
("io/print_str", "(Str) -> Unit !IO [effect op]"),
|
||||||
("io/print_float", "(Float) -> Unit !IO [effect op]"),
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,50 +561,6 @@ mod tests {
|
|||||||
assert_eq!(ty_neg_inf, Type::float(), "neg_inf must type as Float");
|
assert_eq!(ty_neg_inf, Type::float(), "neg_inf must type as Float");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iter 22-floats.3: `io/print_float : (Float) -> Unit !IO`.
|
|
||||||
/// Mirrors `io/print_int|bool|str`. Codegen lowering through runtime
|
|
||||||
/// C glue `@ail_print_float` lands in iter 4. Effects are collected
|
|
||||||
/// in the mutable `effects` sink (mirrors the real typechecker
|
|
||||||
/// pipeline); we assert both the return type and that `IO` was
|
|
||||||
/// accumulated.
|
|
||||||
#[test]
|
|
||||||
fn install_io_print_float_signature() {
|
|
||||||
let bits = 1.5_f64.to_bits();
|
|
||||||
let mut env = Env::default();
|
|
||||||
install(&mut env);
|
|
||||||
let do_term = Term::Do {
|
|
||||||
op: "io/print_float".into(),
|
|
||||||
args: vec![lit_float(bits)],
|
|
||||||
tail: false,
|
|
||||||
};
|
|
||||||
let mut locals: IndexMap<String, Type> = IndexMap::new();
|
|
||||||
let mut effects: BTreeSet<String> = BTreeSet::new();
|
|
||||||
let mut subst = Subst::default();
|
|
||||||
let mut counter: u32 = 0;
|
|
||||||
let mut residuals = Vec::new();
|
|
||||||
let mut free_fn_calls = Vec::new();
|
|
||||||
let mut warnings: Vec<crate::diagnostic::Diagnostic> = Vec::new();
|
|
||||||
let ret = crate::synth(
|
|
||||||
&do_term,
|
|
||||||
&env,
|
|
||||||
&mut locals,
|
|
||||||
&mut effects,
|
|
||||||
"<test>",
|
|
||||||
&mut subst,
|
|
||||||
&mut counter,
|
|
||||||
&mut residuals,
|
|
||||||
&mut free_fn_calls,
|
|
||||||
&mut warnings,
|
|
||||||
)
|
|
||||||
.expect("synth");
|
|
||||||
let ret = subst.apply(&ret);
|
|
||||||
assert_eq!(ret, Type::unit(), "io/print_float returns Unit");
|
|
||||||
assert!(
|
|
||||||
effects.contains("IO"),
|
|
||||||
"io/print_float must accumulate IO effect, got {effects:?}"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Iter 22-floats.3: pattern-matching on Float literals is hard-
|
/// Iter 22-floats.3: pattern-matching on Float literals is hard-
|
||||||
/// rejected at typecheck per spec line 723-735 recommendation (a).
|
/// rejected at typecheck per spec line 723-735 recommendation (a).
|
||||||
/// IEEE-`==` semantics make Float patterns semantically dubious
|
/// IEEE-`==` semantics make Float patterns semantically dubious
|
||||||
|
|||||||
@@ -3879,9 +3879,11 @@ mod tests {
|
|||||||
},
|
},
|
||||||
vec![],
|
vec![],
|
||||||
Term::Do {
|
Term::Do {
|
||||||
op: "io/print_int".into(),
|
op: "io/print_str".into(),
|
||||||
args: vec![Term::Lit {
|
args: vec![Term::Lit {
|
||||||
lit: Literal::Int { value: 1 },
|
lit: Literal::Str {
|
||||||
|
value: "hi".into(),
|
||||||
|
},
|
||||||
}],
|
}],
|
||||||
tail: false,
|
tail: false,
|
||||||
},
|
},
|
||||||
@@ -5055,8 +5057,12 @@ mod tests {
|
|||||||
},
|
},
|
||||||
body: Term::Seq {
|
body: Term::Seq {
|
||||||
lhs: Box::new(Term::Do {
|
lhs: Box::new(Term::Do {
|
||||||
op: "io/print_int".into(),
|
op: "io/print_str".into(),
|
||||||
args: vec![Term::Var { name: "h".into() }],
|
args: vec![Term::Lit {
|
||||||
|
lit: Literal::Str {
|
||||||
|
value: "x".into(),
|
||||||
|
},
|
||||||
|
}],
|
||||||
tail: false,
|
tail: false,
|
||||||
}),
|
}),
|
||||||
rhs: Box::new(Term::App {
|
rhs: Box::new(Term::App {
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
//! Hard gate for iter rpe.1: the per-type print effect-ops
|
||||||
|
//! `io/print_int`, `io/print_bool`, `io/print_float` are retired
|
||||||
|
//! and must NOT appear in the builtin registry. The polymorphic
|
||||||
|
//! `print` helper (prelude, iter 24.3) is the canonical replacement;
|
||||||
|
//! `io/print_str` survives as the byte-channel primitive.
|
||||||
|
|
||||||
|
use ailang_check::build_check_env;
|
||||||
|
use ailang_surface::load_workspace;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn fixture_dir() -> PathBuf {
|
||||||
|
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
d.pop();
|
||||||
|
d.pop();
|
||||||
|
d.join("examples")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn per_type_print_effect_ops_are_retired() {
|
||||||
|
// Any workspace will do; we only inspect the post-install
|
||||||
|
// builtin registry. `hello.ail` is the smallest surviving
|
||||||
|
// fixture (uses `io/print_str` only).
|
||||||
|
let ws_path = fixture_dir().join("hello.ail");
|
||||||
|
let ws = load_workspace(&ws_path).expect("workspace loads");
|
||||||
|
let env = build_check_env(&ws);
|
||||||
|
|
||||||
|
for retired in ["io/print_int", "io/print_bool", "io/print_float"] {
|
||||||
|
assert!(
|
||||||
|
!env.effect_ops.contains_key(retired),
|
||||||
|
"{retired} must not appear in builtin registry post-rpe.1; \
|
||||||
|
use polymorphic `print` (Show-based) instead"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Survivor pin: io/print_str stays.
|
||||||
|
assert!(
|
||||||
|
env.effect_ops.contains_key("io/print_str"),
|
||||||
|
"io/print_str must survive — it is the canonical byte-channel \
|
||||||
|
primitive and used internally by `print`"
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -2299,50 +2299,6 @@ impl<'a> Emitter<'a> {
|
|||||||
let _ = tail;
|
let _ = tail;
|
||||||
let call_kw = if tail { "tail call" } else { "call" };
|
let call_kw = if tail { "tail call" } else { "call" };
|
||||||
match op {
|
match op {
|
||||||
"io/print_int" => {
|
|
||||||
if args.len() != 1 {
|
|
||||||
return Err(CodegenError::Internal(
|
|
||||||
"io/print_int arity".into(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
let (v, vty) = self.lower_term(&args[0])?;
|
|
||||||
if vty != "i64" {
|
|
||||||
return Err(CodegenError::Internal(
|
|
||||||
"io/print_int needs i64".into(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
let fmt = self.intern_string("fmt_int", "%lld\n");
|
|
||||||
self.body.push_str(&format!(
|
|
||||||
" {call_kw} i32 (ptr, ...) @printf(ptr @{fmt}, i64 {v})\n"
|
|
||||||
));
|
|
||||||
if tail {
|
|
||||||
self.body.push_str(" ret i8 0\n");
|
|
||||||
self.block_terminated = true;
|
|
||||||
}
|
|
||||||
Ok(("0".into(), "i8".into()))
|
|
||||||
}
|
|
||||||
"io/print_float" => {
|
|
||||||
if args.len() != 1 {
|
|
||||||
return Err(CodegenError::Internal(
|
|
||||||
"io/print_float arity".into(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
let (v, vty) = self.lower_term(&args[0])?;
|
|
||||||
if vty != "double" {
|
|
||||||
return Err(CodegenError::Internal(
|
|
||||||
"io/print_float needs double".into(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
let fmt = self.intern_string("fmt_float", "%g\n");
|
|
||||||
self.body.push_str(&format!(
|
|
||||||
" {call_kw} i32 (ptr, ...) @printf(ptr @{fmt}, double {v})\n"
|
|
||||||
));
|
|
||||||
if tail {
|
|
||||||
self.body.push_str(" ret i8 0\n");
|
|
||||||
self.block_terminated = true;
|
|
||||||
}
|
|
||||||
Ok(("0".into(), "i8".into()))
|
|
||||||
}
|
|
||||||
"io/print_str" => {
|
"io/print_str" => {
|
||||||
if args.len() != 1 {
|
if args.len() != 1 {
|
||||||
return Err(CodegenError::Internal(
|
return Err(CodegenError::Internal(
|
||||||
@@ -2370,45 +2326,6 @@ impl<'a> Emitter<'a> {
|
|||||||
}
|
}
|
||||||
Ok(("0".into(), "i8".into()))
|
Ok(("0".into(), "i8".into()))
|
||||||
}
|
}
|
||||||
"io/print_bool" => {
|
|
||||||
if args.len() != 1 {
|
|
||||||
return Err(CodegenError::Internal(
|
|
||||||
"io/print_bool arity".into(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
let (v, vty) = self.lower_term(&args[0])?;
|
|
||||||
if vty != "i1" {
|
|
||||||
return Err(CodegenError::Internal(
|
|
||||||
"io/print_bool needs i1".into(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
// Print "true\n" or "false\n".
|
|
||||||
let fmt_t = self.intern_string("fmt_true", "true\n");
|
|
||||||
let fmt_f = self.intern_string("fmt_false", "false\n");
|
|
||||||
let id = self.fresh_id();
|
|
||||||
let then_lbl = format!("ptbl_t.{id}");
|
|
||||||
let else_lbl = format!("ptbl_f.{id}");
|
|
||||||
let join_lbl = format!("ptbl_j.{id}");
|
|
||||||
self.body.push_str(&format!(
|
|
||||||
" br i1 {v}, label %{then_lbl}, label %{else_lbl}\n"
|
|
||||||
));
|
|
||||||
self.start_block(&then_lbl);
|
|
||||||
self.body.push_str(&format!(
|
|
||||||
" call i32 (ptr, ...) @printf(ptr @{fmt_t})\n"
|
|
||||||
));
|
|
||||||
self.body.push_str(&format!(" br label %{join_lbl}\n"));
|
|
||||||
self.start_block(&else_lbl);
|
|
||||||
self.body.push_str(&format!(
|
|
||||||
" call i32 (ptr, ...) @printf(ptr @{fmt_f})\n"
|
|
||||||
));
|
|
||||||
self.body.push_str(&format!(" br label %{join_lbl}\n"));
|
|
||||||
self.start_block(&join_lbl);
|
|
||||||
if tail {
|
|
||||||
self.body.push_str(" ret i8 0\n");
|
|
||||||
self.block_terminated = true;
|
|
||||||
}
|
|
||||||
Ok(("0".into(), "i8".into()))
|
|
||||||
}
|
|
||||||
other => Err(CodegenError::Internal(format!(
|
other => Err(CodegenError::Internal(format!(
|
||||||
"unknown effect op: {other}"
|
"unknown effect op: {other}"
|
||||||
))),
|
))),
|
||||||
@@ -2722,20 +2639,9 @@ impl<'a> Emitter<'a> {
|
|||||||
self.counter
|
self.counter
|
||||||
}
|
}
|
||||||
|
|
||||||
fn intern_string(&mut self, hint: &str, content: &str) -> String {
|
/// Iter hs.1 (amended hs.2): parallel to the legacy
|
||||||
if let Some((name, _)) = self.strings.get(content) {
|
/// `intern_string` (retired in iter rpe.1 alongside the per-type
|
||||||
return name.clone();
|
/// print effect-ops it served), but for
|
||||||
}
|
|
||||||
// Mangling per module: `.str_<module>_<hint>_<idx>`.
|
|
||||||
let name = format!(".str_{}_{}_{}", self.module_name, hint, self.str_counter);
|
|
||||||
self.str_counter += 1;
|
|
||||||
let len = c_byte_len(content);
|
|
||||||
self.strings
|
|
||||||
.insert(content.to_string(), (name.clone(), len));
|
|
||||||
name
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Iter hs.1 (amended hs.2): parallel to `intern_string`, but for
|
|
||||||
/// language `Str` literals emitted as packed-struct globals
|
/// language `Str` literals emitted as packed-struct globals
|
||||||
/// (len + bytes + NUL). Shares the same monotonic `str_counter`
|
/// (len + bytes + NUL). Shares the same monotonic `str_counter`
|
||||||
/// so the produced global names remain alphabetically orderable
|
/// so the produced global names remain alphabetically orderable
|
||||||
@@ -3577,45 +3483,6 @@ mod tests {
|
|||||||
assert!(ir.contains("0xFFF0000000000000"), "-inf bit pattern missing: {ir}");
|
assert!(ir.contains("0xFFF0000000000000"), "-inf bit pattern missing: {ir}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Floats iter 4.6 RED: `(do io/print_float 1.5)` lowers via
|
|
||||||
/// `printf("%g\n", v)`, parallel to `io/print_int` at line 2152.
|
|
||||||
#[test]
|
|
||||||
fn lowers_io_print_float() {
|
|
||||||
use ailang_core::ast::*;
|
|
||||||
let body = Term::Do {
|
|
||||||
op: "io/print_float".into(),
|
|
||||||
args: vec![Term::Lit { lit: Literal::Float { bits: 0x3ff8_0000_0000_0000u64 } }],
|
|
||||||
tail: false,
|
|
||||||
};
|
|
||||||
let m = Module {
|
|
||||||
schema: ailang_core::SCHEMA.to_string(),
|
|
||||||
name: "t".into(),
|
|
||||||
imports: vec![],
|
|
||||||
defs: vec![Def::Fn(FnDef {
|
|
||||||
name: "main".into(),
|
|
||||||
ty: Type::Fn {
|
|
||||||
params: vec![], ret: Box::new(Type::unit()), effects: vec!["IO".into()],
|
|
||||||
param_modes: vec![], ret_mode: ParamMode::Implicit,
|
|
||||||
},
|
|
||||||
params: vec![], body, suppress: vec![], doc: None,
|
|
||||||
})],
|
|
||||||
};
|
|
||||||
let ir = emit_ir(&m).unwrap();
|
|
||||||
assert!(
|
|
||||||
ir.contains("call i32 (ptr, ...) @printf"),
|
|
||||||
"io/print_float not emitting printf: {ir}"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
ir.contains("double 0x3FF8000000000000"),
|
|
||||||
"Float arg not threaded through io/print_float: {ir}"
|
|
||||||
);
|
|
||||||
// Verify the format string `%g\n` is interned.
|
|
||||||
assert!(
|
|
||||||
ir.contains("%g") || ir.contains("\\67"), // `g` ASCII = 67 = 0x47
|
|
||||||
"format string `%g\\n` not interned: {ir}"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Iter 23.2: codegen intercepts a fn named `eq__Str` (the
|
/// Iter 23.2: codegen intercepts a fn named `eq__Str` (the
|
||||||
/// monomorphiser's synthesised symbol for `Eq Str.eq`) and emits
|
/// monomorphiser's synthesised symbol for `Eq Str.eq`) and emits
|
||||||
/// a two-instruction body that calls @ail_str_eq, regardless of
|
/// a two-instruction body that calls @ail_str_eq, regardless of
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ pub(crate) fn builtin_ail_type(name: &str) -> Option<Type> {
|
|||||||
/// param signature is irrelevant here since we only consume the ret.
|
/// param signature is irrelevant here since we only consume the ret.
|
||||||
pub(crate) fn builtin_effect_op_ret(op: &str) -> Option<Type> {
|
pub(crate) fn builtin_effect_op_ret(op: &str) -> Option<Type> {
|
||||||
Some(match op {
|
Some(match op {
|
||||||
"io/print_int" | "io/print_bool" | "io/print_str" | "io/print_float" => Type::unit(),
|
"io/print_str" => Type::unit(),
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -430,8 +430,8 @@ generating new code.
|
|||||||
(term-ctor List Cons 3
|
(term-ctor List Cons 3
|
||||||
(term-ctor List Nil))))
|
(term-ctor List Nil))))
|
||||||
(seq
|
(seq
|
||||||
(do io/print_int (app list_length xs))
|
(app print (app list_length xs))
|
||||||
(do io/print_int (app sum_list xs)))))))
|
(app print (app sum_list xs)))))))
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3 — `lit_pat.ail`: literal patterns and nested ctor patterns
|
### 3 — `lit_pat.ail`: literal patterns and nested ctor patterns
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ fn design_md_anchors_every_term_variant() {
|
|||||||
(
|
(
|
||||||
r#""t": "do""#,
|
r#""t": "do""#,
|
||||||
Term::Do {
|
Term::Do {
|
||||||
op: "io/print_int".into(),
|
op: "io/print_str".into(),
|
||||||
args: vec![],
|
args: vec![],
|
||||||
tail: false,
|
tail: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -216,10 +216,13 @@ fn ct4_migrated_fixtures_have_canonical_form_hashes() {
|
|||||||
let ord_mod = ailang_surface::load_module(&examples.join("ordering_match.ail"))
|
let ord_mod = ailang_surface::load_module(&examples.join("ordering_match.ail"))
|
||||||
.expect("examples/ordering_match.ail loads");
|
.expect("examples/ordering_match.ail loads");
|
||||||
let main_def = ord_mod.defs.iter().find(|d| d.name() == "main").unwrap();
|
let main_def = ord_mod.defs.iter().find(|d| d.name() == "main").unwrap();
|
||||||
|
// Iter rpe.1 updated the hash: `ordering_match.ail`'s body migrated
|
||||||
|
// from `(do io/print_int x)` to `(app print x)` as part of the
|
||||||
|
// corpus migration retiring the per-type print effect-ops.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
def_hash(main_def),
|
def_hash(main_def),
|
||||||
"8d17235aa3d2e127",
|
"b65a7f834703ffb4",
|
||||||
"ordering_match::main canonical hash must match captured post-migration value"
|
"ordering_match::main canonical hash must match captured post-rpe.1 value"
|
||||||
);
|
);
|
||||||
|
|
||||||
let dup_a_mod = ailang_surface::load_module(&examples.join("test_22b1_dup_a.ail"))
|
let dup_a_mod = ailang_surface::load_module(&examples.join("test_22b1_dup_a.ail"))
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ fn spec_mentions_every_term_variant() {
|
|||||||
(
|
(
|
||||||
"(do ",
|
"(do ",
|
||||||
Term::Do {
|
Term::Do {
|
||||||
op: "io/print_int".into(),
|
op: "io/print_str".into(),
|
||||||
args: vec![],
|
args: vec![],
|
||||||
tail: false,
|
tail: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1585,11 +1585,15 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn do_renders_with_keyword_and_op() {
|
fn do_renders_with_keyword_and_op() {
|
||||||
let t = Term::Do {
|
let t = Term::Do {
|
||||||
op: "io/print_int".into(),
|
op: "io/print_str".into(),
|
||||||
args: vec![Term::Lit { lit: Literal::Int { value: 5 } }],
|
args: vec![Term::Lit {
|
||||||
|
lit: Literal::Str {
|
||||||
|
value: "5".into(),
|
||||||
|
},
|
||||||
|
}],
|
||||||
tail: false,
|
tail: false,
|
||||||
};
|
};
|
||||||
assert_eq!(render_term(&t), "do io/print_int(5)");
|
assert_eq!(render_term(&t), "do io/print_str(\"5\")");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Types ----
|
// ---- Types ----
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
//! - otherwise ⇒ ident.
|
//! - otherwise ⇒ ident.
|
||||||
//!
|
//!
|
||||||
//! Operators (`+`, `==`, `<=`, `**`), qualified names like
|
//! Operators (`+`, `==`, `<=`, `**`), qualified names like
|
||||||
//! `io/print_int`, and dotted cross-module references like
|
//! `io/print_str`, and dotted cross-module references like
|
||||||
//! `std_list.map` are all single-token idents — there is no special
|
//! `std_list.map` are all single-token idents — there is no special
|
||||||
//! lexical rule for any of them. `(`, `)`, and whitespace are the only
|
//! lexical rule for any of them. `(`, `)`, and whitespace are the only
|
||||||
//! reserved tokens. Bool literals (`true`, `false`) and unit
|
//! reserved tokens. Bool literals (`true`, `false`) and unit
|
||||||
@@ -317,7 +317,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn operators_are_idents() {
|
fn operators_are_idents() {
|
||||||
let toks = tokenize("+ == <= io/print_int std_list.map").unwrap();
|
let toks = tokenize("+ == <= io/print_str std_list.map").unwrap();
|
||||||
let names: Vec<_> = toks
|
let names: Vec<_> = toks
|
||||||
.iter()
|
.iter()
|
||||||
.map(|t| match &t.tok {
|
.map(|t| match &t.tok {
|
||||||
@@ -325,7 +325,7 @@ mod tests {
|
|||||||
_ => panic!("not ident"),
|
_ => panic!("not ident"),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
assert_eq!(names, vec!["+", "==", "<=", "io/print_int", "std_list.map"]);
|
assert_eq!(names, vec!["+", "==", "<=", "io/print_str", "std_list.map"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1374,7 +1374,7 @@ impl<'a> Parser<'a> {
|
|||||||
tail: bool,
|
tail: bool,
|
||||||
production: &'static str,
|
production: &'static str,
|
||||||
) -> Result<Term, ParseError> {
|
) -> Result<Term, ParseError> {
|
||||||
let op = self.expect_ident("effect op (e.g. `io/print_int`)")?;
|
let op = self.expect_ident("effect op (e.g. `io/print_str`)")?;
|
||||||
let mut args = Vec::new();
|
let mut args = Vec::new();
|
||||||
while !matches!(self.peek(), Some(Token { tok: Tok::RParen, .. })) {
|
while !matches!(self.peek(), Some(Token { tok: Tok::RParen, .. })) {
|
||||||
args.push(self.parse_term()?);
|
args.push(self.parse_term()?);
|
||||||
|
|||||||
+31
-22
@@ -328,7 +328,7 @@ Every other maximal token is classified post-hoc:
|
|||||||
- Otherwise → ident.
|
- Otherwise → ident.
|
||||||
|
|
||||||
Consequence: operators like `+`, `==`, `<=`, `**`, qualified
|
Consequence: operators like `+`, `==`, `<=`, `**`, qualified
|
||||||
names like `io/print_int`, and cross-module references like
|
names like `io/print_str`, and cross-module references like
|
||||||
`std_list.map` are all single ident tokens with no special lex
|
`std_list.map` are all single ident tokens with no special lex
|
||||||
rule. The only reserved tokens are `(`, `)`, and whitespace.
|
rule. The only reserved tokens are `(`, `)`, and whitespace.
|
||||||
Bool literals (`true`, `false`) and unit (`(lit-unit)`) are
|
Bool literals (`true`, `false`) and unit (`(lit-unit)`) are
|
||||||
@@ -1987,9 +1987,10 @@ a => a -> () !IO` shipped in iter 24.3 with body
|
|||||||
`\x -> let s = show x in do io/print_str s` (explicit let-binder for
|
`\x -> let s = show x in do io/print_str s` (explicit let-binder for
|
||||||
heap-Str RC discipline per eob.1 Str carve-out). The let-binder is
|
heap-Str RC discipline per eob.1 Str carve-out). The let-binder is
|
||||||
structurally pinned by `crates/ail/tests/print_mono_body_shape.rs`.
|
structurally pinned by `crates/ail/tests/print_mono_body_shape.rs`.
|
||||||
Routing through `print` replaces the ad-hoc `io/print_int|bool|float`
|
Routing through `print` replaces the ad-hoc per-type print
|
||||||
idiom for new code; retiring the per-type effect-ops is queued as a
|
effect-ops; the `io/print_int`, `io/print_bool`, `io/print_float`
|
||||||
P2 follow-up.
|
primitives were retired 2026-05-14 in iter rpe.1, leaving
|
||||||
|
`io/print_str` as the only surviving direct-output effect-op.
|
||||||
|
|
||||||
### Heap-Str primitives
|
### Heap-Str primitives
|
||||||
|
|
||||||
@@ -2021,8 +2022,12 @@ bodies dispatch into them. `str_concat` IS directly observable
|
|||||||
because the LLM-author calls it explicitly when authoring an
|
because the LLM-author calls it explicitly when authoring an
|
||||||
instance body that wants to combine fragments.
|
instance body that wants to combine fragments.
|
||||||
|
|
||||||
Primitive output goes through `io/print_int` / `io/print_bool` /
|
Primitive output for `Str` values goes through `io/print_str`
|
||||||
`io/print_str` directly.
|
directly; values of other primitive types route through the
|
||||||
|
polymorphic `print` helper (§"Polymorphic print"), which feeds
|
||||||
|
the heap-Str result of `show x` into `io/print_str`. The per-type
|
||||||
|
effect-ops `io/print_int`, `io/print_bool`, `io/print_float` were
|
||||||
|
retired in iter rpe.1 (2026-05-14).
|
||||||
|
|
||||||
`==`, `<`, `<=`, `>`, `>=` REMAIN primitive operators (unchanged
|
`==`, `<`, `<=`, `>`, `>=` REMAIN primitive operators (unchanged
|
||||||
from the original draft). Class methods are accessed by name (`eq x y`,
|
from the original draft). Class methods are accessed by name (`eq x y`,
|
||||||
@@ -2328,7 +2333,7 @@ are real surface forms.
|
|||||||
|
|
||||||
{ "t": "if", "cond": Term, "then": Term, "else": Term }
|
{ "t": "if", "cond": Term, "then": Term, "else": Term }
|
||||||
|
|
||||||
// Effect-op invocation. `op` is "<eff>/<op>" (e.g. "io/print_int").
|
// Effect-op invocation. `op` is "<eff>/<op>" (e.g. "io/print_str").
|
||||||
// `tail` triggers musttail (omitted when false).
|
// `tail` triggers musttail (omitted when false).
|
||||||
{ "t": "do", "op": "<eff>/<op>", "args": [Term...], "tail": false }
|
{ "t": "do", "op": "<eff>/<op>", "args": [Term...], "tail": false }
|
||||||
|
|
||||||
@@ -2562,23 +2567,24 @@ no `f32` variant. The runtime / codegen contract:
|
|||||||
pattern is conformant; `0.0 / 0.0` may produce
|
pattern is conformant; `0.0 / 0.0` may produce
|
||||||
`0x7ff8000000000000` on one target and a different qNaN on
|
`0x7ff8000000000000` on one target and a different qNaN on
|
||||||
another.
|
another.
|
||||||
- The textual rendering of NaN by `io/print_float`. The libc
|
- The textual rendering of NaN through `float_to_str` (the runtime
|
||||||
`printf("%g", nan)` glue used by the runtime is permitted to
|
C helper that backs `instance Show Float` and, post-iter-rpe.1,
|
||||||
emit `nan` / `-nan` / `NaN` etc. depending on libc version and
|
every Float-typed `print` call). The libc `printf("%g", nan)`
|
||||||
the NaN's sign bit; AILang does not normalise this, since the
|
glue used by `float_to_str` is permitted to emit `nan` / `-nan`
|
||||||
prose / surface-print paths render NaN as the explicit `"NaN"`
|
/ `NaN` etc. depending on libc version and the NaN's sign bit;
|
||||||
spelling and `io/print_float` is for human-readable output, not
|
AILang does not normalise this, since the prose / surface-print
|
||||||
round-trip.
|
paths render NaN as the explicit `"NaN"` spelling and Float
|
||||||
|
rendering is for human-readable output, not round-trip.
|
||||||
|
|
||||||
The same libc-`%g` rendering applies to `show 1.5` / `show nan` /
|
The same libc-`%g` rendering applies to `show 1.5` / `show nan` /
|
||||||
`show inf` via `instance Show Float` (which calls `float_to_str`
|
`show inf` via `instance Show Float` (which calls `float_to_str`
|
||||||
internally — see §"Prelude (built-in) classes" for the Show ship).
|
internally — see §"Prelude (built-in) classes" for the Show ship).
|
||||||
The NaN-spelling caveat above is observable via both
|
The NaN-spelling caveat above is observable via `do print x` for
|
||||||
`do io/print_float x` and `do print x` at the same `x`; the rendering
|
Float-typed `x`; the rendering is libc-version-dependent and
|
||||||
is libc-version-dependent and target-libc-specific. AILang does NOT
|
target-libc-specific. AILang does NOT canonicalise Float textual
|
||||||
canonicalise Float textual representation; the LLM-author who needs
|
representation; the LLM-author who needs deterministic Float
|
||||||
deterministic Float rendering for cross-platform test fixtures should
|
rendering for cross-platform test fixtures should bypass `show` /
|
||||||
bypass `show` / `print` and emit a custom formatter.
|
`print` and emit a custom formatter.
|
||||||
|
|
||||||
These are the Rust / Swift / standard-LLVM defaults — not
|
These are the Rust / Swift / standard-LLVM defaults — not
|
||||||
research-grade reproducibility guarantees. The stronger guarantee
|
research-grade reproducibility guarantees. The stronger guarantee
|
||||||
@@ -2676,7 +2682,10 @@ What **is** supported (and used as the smoke test for the pipeline):
|
|||||||
- Int, Bool, Unit, **Str**, **Float** as primitive types.
|
- Int, Bool, Unit, **Str**, **Float** as primitive types.
|
||||||
- `if`, `let`, function calls, recursion.
|
- `if`, `let`, function calls, recursion.
|
||||||
- Effects on function signatures, with `do op(args)` for direct effect
|
- Effects on function signatures, with `do op(args)` for direct effect
|
||||||
ops (`io/print_int`, `io/print_bool`, `io/print_str`).
|
ops (`io/print_str`). The per-type print ops
|
||||||
|
`io/print_int`, `io/print_bool`, `io/print_float` were retired in
|
||||||
|
iter rpe.1; the polymorphic `print` (§"Polymorphic print") is the
|
||||||
|
canonical output path for non-Str values.
|
||||||
- **Builtins.** Arithmetic operators (`+`, `-`, `*`, `/`) of type
|
- **Builtins.** Arithmetic operators (`+`, `-`, `*`, `/`) of type
|
||||||
`forall a. (a, a) -> a` (codegen-restricted to `{Int, Float}`);
|
`forall a. (a, a) -> a` (codegen-restricted to `{Int, Float}`);
|
||||||
`%` of type `(Int, Int) -> Int` (Int-only — `fmod` semantics for
|
`%` of type `(Int, Int) -> Int` (Int-only — `fmod` semantics for
|
||||||
@@ -2696,7 +2705,7 @@ What **is** supported (and used as the smoke test for the pipeline):
|
|||||||
`fcmp uno`); Float bit-pattern constants `nan : Float`,
|
`fcmp uno`); Float bit-pattern constants `nan : Float`,
|
||||||
`inf : Float`, `neg_inf : Float` (resolved as bare values, lower
|
`inf : Float`, `neg_inf : Float` (resolved as bare values, lower
|
||||||
to direct hex-float `double` SSA constants at use site); the IO
|
to direct hex-float `double` SSA constants at use site); the IO
|
||||||
effect ops (`io/print_int|bool|str|float`); **`==` : forall a.
|
effect op `io/print_str`; **`==` : forall a.
|
||||||
(a, a) -> Bool**; and **`__unreachable__ : forall a. a`**.
|
(a, a) -> Bool**; and **`__unreachable__ : forall a. a`**.
|
||||||
- **`==` is polymorphic.** The typechecker accepts
|
- **`==` is polymorphic.** The typechecker accepts
|
||||||
`==` at any type whose two sides agree (the rigid `a` of the
|
`==` at any type whose two sides agree (the rigid `a` of the
|
||||||
|
|||||||
@@ -0,0 +1,175 @@
|
|||||||
|
# iter rpe.1 — Retire per-type print effect-ops
|
||||||
|
|
||||||
|
**Date:** 2026-05-14
|
||||||
|
**Started from:** 8b455bee4ca2b09bcadc56d95e0d79dcef75d284
|
||||||
|
**Status:** DONE
|
||||||
|
**Tasks completed:** 10 of 10
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
The retire-per-type-print-effect-ops milestone shipped in one iter,
|
||||||
|
covering: a RED test pinning the deletion gate (`crates/ailang-check/
|
||||||
|
tests/no_per_type_print_ops.rs`); 92 `examples/*.ail` fixture
|
||||||
|
migrations from `(do io/print_<T> x)` → `(app print x)` plus 6
|
||||||
|
`.prose.txt` snapshot regenerations; four-site lockstep compiler
|
||||||
|
deletion (`crates/ailang-check/src/builtins.rs` × 5 regions,
|
||||||
|
`crates/ailang-codegen/src/lib.rs::lower_app` × 3 arms + 1 test,
|
||||||
|
`crates/ailang-codegen/src/synth.rs::builtin_effect_op_ret` × 1
|
||||||
|
match arm), with the dead `intern_string` helper removed as a
|
||||||
|
clean follow-up; six test-body migrations (`ailang-check` × 2,
|
||||||
|
`ailang-core` tests × 2, `ailang-surface/src/lex.rs`, `ailang-prose`);
|
||||||
|
the Cat B test-harness patch in `crates/ail/tests/e2e.rs` (6
|
||||||
|
IR-shape tests gained a `monomorphise_workspace` call so they
|
||||||
|
follow the same desugar → lift → mono → lower pipeline as `ail
|
||||||
|
build`); 6 doc-comment touch-ups; 7-site DESIGN.md sweep; 3 E2E
|
||||||
|
test-comment polish; bench-run-and-no-ratification (all 3 scripts
|
||||||
|
exit 0 against existing baselines, drift envelope within
|
||||||
|
tolerance); plus IR-snapshot refresh (4 `.ll` files: `sum`,
|
||||||
|
`list`, `max3`, `ws_main`) and 1 canonical-hash pin update
|
||||||
|
(`ordering_match::main`) as plan-unanticipated downstream
|
||||||
|
consequences of the corpus migration. Tests 564/564 green
|
||||||
|
post-iter (was 563 at start; +1 from the new RED test).
|
||||||
|
|
||||||
|
## Per-task notes
|
||||||
|
|
||||||
|
- iter rpe.1.1: RED test `no_per_type_print_ops.rs` — asserts
|
||||||
|
`io/print_int|bool|float` absent from `env.effect_ops`,
|
||||||
|
`io/print_str` present.
|
||||||
|
- iter rpe.1.2: 92 `.ail` corpus migrated (89 single-line +
|
||||||
|
3 multi-line shapes); 5 ancillary comment touch-ups in
|
||||||
|
`borrow_own_demo`, `eq_demo`, `int_to_print_int_borrow`,
|
||||||
|
`floats_1_newton_sqrt`, `floats_3_safe_division` to satisfy
|
||||||
|
the §H acceptance criterion `grep -rl ... examples/ == 0`.
|
||||||
|
- iter rpe.1.3: 6 `.prose.txt` snapshots regenerated via
|
||||||
|
`cargo run -p ail -- prose`.
|
||||||
|
- iter rpe.1.4: builtins.rs deletes (3 effect_ops.insert blocks
|
||||||
|
+ 3 `list()` rows + 1 unit test + 2 doc-comment swaps);
|
||||||
|
codegen lib.rs deletes (3 `lower_app` arms + 1 test);
|
||||||
|
synth.rs `builtin_effect_op_ret` match-arm narrowed.
|
||||||
|
`intern_string` removed as orphan helper. `Emitter.strings`
|
||||||
|
field left in place (still consumed by emit-time loop;
|
||||||
|
cycles over empty map; non-functional). RED test flips
|
||||||
|
GREEN.
|
||||||
|
- iter rpe.1.5: 6 test-body sites swapped to `io/print_str` +
|
||||||
|
`Str` args; Cat B harness patch at all 6 e2e.rs sites
|
||||||
|
inserts `ailang_check::monomorphise_workspace(&lifted_ws)`
|
||||||
|
between the existing lift loop and the lower call (the plan
|
||||||
|
said "replace the desugar+lift loop with mono", but mono's
|
||||||
|
precondition is "already lifted" — interpreting per spirit
|
||||||
|
and matching the `ail build` pipeline). E2E 85/85 green
|
||||||
|
after this step.
|
||||||
|
- iter rpe.1.6: doc-comment swaps in 6 sites (`lex.rs`,
|
||||||
|
`parse.rs`, `main.rs` × 2, `runtime/str.c`, `form_a.md`).
|
||||||
|
- iter rpe.1.7: DESIGN.md 7 sites swept; the iter's
|
||||||
|
past-tense paragraph at line 1990-1992 anchors the
|
||||||
|
milestone close.
|
||||||
|
- iter rpe.1.8: E2E test-comment polish at `eq_ord_e2e.rs` × 2,
|
||||||
|
`floats_e2e.rs`. Plus three plan-unanticipated sites:
|
||||||
|
`int_arg_to_effect_op_does_not_rc_track` test assertions
|
||||||
|
shifted from `0/0/0` to `1/1/0` (post-iter `print n` for
|
||||||
|
Int now goes via Show Int → int_to_str → io/print_str,
|
||||||
|
exactly one heap-Str slab cycle per spec §E); 4 IR
|
||||||
|
snapshots refreshed via `UPDATE_SNAPSHOTS=1` because the
|
||||||
|
format-string globals (`@.str_<module>_fmt_int_0` /
|
||||||
|
`%lld\n`) no longer appear in IR; 1 canonical-hash pin
|
||||||
|
update for `ordering_match::main` (body migration changes
|
||||||
|
the def's canonical-form hash).
|
||||||
|
- iter rpe.1.9: bench run — all 3 scripts exit 0 against
|
||||||
|
existing baselines. No ratification needed; spec §C4 (a)
|
||||||
|
anticipated possible latency drift but actual fell within
|
||||||
|
tolerance. Largest single deltas: `latency.explicit_at_rc.
|
||||||
|
max_us` +154.84% (a tail metric in the noise-class
|
||||||
|
envelope observed across the last ~12 audits); `throughput.
|
||||||
|
bench_list_sum.bump_s` +11.85% (REGRESSION, single bench,
|
||||||
|
3rd-iter-recurring; tracked as background noise per
|
||||||
|
audit-24 lineage). Baseline pristine for the 13th
|
||||||
|
consecutive audit-equivalent.
|
||||||
|
- iter rpe.1.10: roadmap entry struck `[x]`; journal written;
|
||||||
|
stats written.
|
||||||
|
|
||||||
|
## Concerns
|
||||||
|
|
||||||
|
- Cat B harness patch deviates from plan-literal: plan said
|
||||||
|
"replace the desugar+lift loop with monomorphise_workspace";
|
||||||
|
I inserted mono after the existing lift loop. Mono's
|
||||||
|
documented precondition is "already lifted", so the literal
|
||||||
|
reading would have broken mono's contract. Spirit-reading
|
||||||
|
was unambiguous: match `ail build`'s pipeline.
|
||||||
|
- Plan Task 8 under-scoped: it named 3 E2E-comment sites,
|
||||||
|
but the corpus migration also forced (a) one assertion
|
||||||
|
update on `int_arg_to_effect_op_does_not_rc_track` (allocs
|
||||||
|
0→1, frees 0→1, fully documented in spec §E), (b) IR
|
||||||
|
snapshot refresh × 4, (c) one canonical-hash pin update.
|
||||||
|
All three are mechanical downstream consequences of Task 2.
|
||||||
|
- `Emitter.strings` field in `crates/ailang-codegen/src/lib.rs`
|
||||||
|
is now functionally dead (no caller after `intern_string`
|
||||||
|
removal) but the field + the per-module collection loop +
|
||||||
|
the emit-time globals loop are all still in place. They
|
||||||
|
cycle over an empty map and are harmless. Cleaning them
|
||||||
|
up cascades through `emit_workspace_with_alloc` and
|
||||||
|
parallel `str_literals` infrastructure; out of scope for
|
||||||
|
this iter.
|
||||||
|
|
||||||
|
## Known debt
|
||||||
|
|
||||||
|
- The `int_arg_to_effect_op_does_not_rc_track` test name now
|
||||||
|
describes a pre-iter property; the body pins the post-iter
|
||||||
|
shape (one Show-Int slab cycle). Renaming to e.g.
|
||||||
|
`print_int_one_slab_cycle` was floated and explicitly
|
||||||
|
declined (plan Task 8 step 2 said "lean toward keep-name-
|
||||||
|
update-doc"). If a future iter wants the rename, the test
|
||||||
|
body is already a clean reference.
|
||||||
|
- The `intern_string` helper is gone but `Emitter.strings`
|
||||||
|
field remains — see Concerns above.
|
||||||
|
|
||||||
|
## Files touched
|
||||||
|
|
||||||
|
121 files in the working tree (1 new + 120 modified).
|
||||||
|
|
||||||
|
Code (compiler):
|
||||||
|
- `crates/ailang-check/src/builtins.rs` (3 effect_ops + 3 list() rows + 1 test + 2 doc-comments deleted/swapped)
|
||||||
|
- `crates/ailang-check/src/lib.rs` (2 test-body sites swapped)
|
||||||
|
- `crates/ailang-codegen/src/lib.rs` (3 lower_app arms + 1 test + `intern_string` helper removed)
|
||||||
|
- `crates/ailang-codegen/src/synth.rs` (builtin_effect_op_ret match-arm narrowed)
|
||||||
|
- `crates/ailang-surface/src/lex.rs` (1 test-body + 1 module doc swap)
|
||||||
|
- `crates/ailang-surface/src/parse.rs` (1 diagnostic example swap)
|
||||||
|
- `crates/ailang-prose/src/lib.rs` (1 round-trip test-body swap)
|
||||||
|
- `crates/ail/src/main.rs` (2 doc-comments swapped)
|
||||||
|
- `runtime/str.c` (1 comment re-anchored on %g)
|
||||||
|
|
||||||
|
Tests:
|
||||||
|
- `crates/ailang-check/tests/no_per_type_print_ops.rs` (NEW)
|
||||||
|
- `crates/ailang-core/tests/spec_drift.rs` (1 swap)
|
||||||
|
- `crates/ailang-core/tests/design_schema_drift.rs` (1 swap)
|
||||||
|
- `crates/ailang-core/tests/hash_pin.rs` (1 hash pin updated)
|
||||||
|
- `crates/ail/tests/e2e.rs` (6 Cat B harness patches + 1 assertion update + 1 doc-comment)
|
||||||
|
- `crates/ail/tests/eq_ord_e2e.rs` (2 doc-comments)
|
||||||
|
- `crates/ail/tests/floats_e2e.rs` (1 doc-comment)
|
||||||
|
- `crates/ail/tests/snapshots/{sum,list,max3,ws_main}.ll` (regenerated; format-string globals removed)
|
||||||
|
|
||||||
|
Docs:
|
||||||
|
- `docs/DESIGN.md` (7 sites)
|
||||||
|
- `docs/roadmap.md` (P2 entry struck [x])
|
||||||
|
- `crates/ailang-core/specs/form_a.md` (1 example swap)
|
||||||
|
|
||||||
|
Examples: 92 `.ail` migrations + 6 `.prose.txt` regenerations + 5 ancillary comment touch-ups.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- `cargo test --workspace`: 564 passed, 0 failed (was 563 at
|
||||||
|
start; +1 = new RED test, no test counts shifted otherwise).
|
||||||
|
- `cargo build --workspace`: clean.
|
||||||
|
- `python3 bench/check.py` exit 0 (drift within tolerance,
|
||||||
|
no ratification).
|
||||||
|
- `python3 bench/compile_check.py` exit 0.
|
||||||
|
- `python3 bench/cross_lang.py` exit 0 (25/25 stable).
|
||||||
|
- `grep -rl "io/print_int\|io/print_bool\|io/print_float"
|
||||||
|
examples/` returns 0 results (acceptance criterion met).
|
||||||
|
- `grep -n "io/print_int\|io/print_bool\|io/print_float"
|
||||||
|
crates/ailang-check/src/builtins.rs` returns 0 lines.
|
||||||
|
- `crates/ailang-codegen/src/lib.rs::lower_app` has no arm
|
||||||
|
for any of the three retired op names.
|
||||||
|
|
||||||
|
## Stats
|
||||||
|
|
||||||
|
`bench/orchestrator-stats/2026-05-14-iter-rpe.1.json`
|
||||||
+3
-10
@@ -77,17 +77,10 @@ context. Pick the next milestone from P1.)_
|
|||||||
|
|
||||||
## P2 — Medium-term
|
## P2 — Medium-term
|
||||||
|
|
||||||
- [ ] **\[milestone\]** Retire `io/print_int` / `io/print_bool` /
|
- [x] **\[milestone\]** Retire `io/print_int` / `io/print_bool` /
|
||||||
`io/print_float` effect-ops + migrate example corpus to `print`.
|
`io/print_float` effect-ops + migrate example corpus to `print`.
|
||||||
Bulk text substitution `do io/print_<T> x` → `do print x` across
|
Shipped 2026-05-14 as iter rpe.1.
|
||||||
`examples/*.ail.json` (~86 fixtures affected). Per-type effect-ops
|
- context: per-iter journal `docs/journals/2026-05-14-iter-rpe.1.md`.
|
||||||
are deleted from `crates/ailang-check/src/builtins.rs`,
|
|
||||||
`crates/ailang-codegen/src/lib.rs::lower_app` arms, and the
|
|
||||||
corresponding runtime C glue.
|
|
||||||
- context: post-milestone-24 mechanical follow-up; the architecture-
|
|
||||||
shipping milestone (24) and corpus-migration milestone (this) are
|
|
||||||
separate so migration runs against a frozen architecture. Same
|
|
||||||
call milestone 23 made for `==` / `eq`.
|
|
||||||
|
|
||||||
- [x] **\[todo\]** Author `examples/prelude.ail` alongside
|
- [x] **\[todo\]** Author `examples/prelude.ail` alongside
|
||||||
`examples/prelude.ail.json`. (Satisfied 2026-05-13 by iter
|
`examples/prelude.ail.json`. (Satisfied 2026-05-13 by iter
|
||||||
|
|||||||
@@ -63,6 +63,6 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (do io/print_int (app run 10000))
|
(seq (app print (app run 10000))
|
||||||
(seq (do io/print_int (app run 100000))
|
(seq (app print (app run 100000))
|
||||||
(do io/print_int (app run 500000)))))))
|
(app print (app run 500000)))))))
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
(fn run_one
|
(fn run_one
|
||||||
(type (fn-type (params (con Int)) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params (con Int)) (ret (con Unit)) (effects IO)))
|
||||||
(params n)
|
(params n)
|
||||||
(body (do io/print_int (app sum_steps_loop n 0))))
|
(body (app print (app sum_steps_loop n 0))))
|
||||||
|
|
||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
(fn run_one
|
(fn run_one
|
||||||
(type (fn-type (params (con Int)) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params (con Int)) (ret (con Unit)) (effects IO)))
|
||||||
(params n)
|
(params n)
|
||||||
(body (do io/print_int (app intsum_loop n 0))))
|
(body (app print (app intsum_loop n 0))))
|
||||||
|
|
||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
(type (fn-type (params (con Int)) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params (con Int)) (ret (con Unit)) (effects IO)))
|
||||||
(params n)
|
(params n)
|
||||||
(body
|
(body
|
||||||
(do io/print_int
|
(app print
|
||||||
(app fold_with_fn inc
|
(app fold_with_fn inc
|
||||||
(app build_n n (term-ctor List Nil))
|
(app build_n n (term-ctor List Nil))
|
||||||
0))))
|
0))))
|
||||||
|
|||||||
@@ -139,10 +139,10 @@
|
|||||||
(params remaining print_countdown chunk_len print_k t)
|
(params remaining print_countdown chunk_len print_k t)
|
||||||
(body
|
(body
|
||||||
(if (app == remaining 0)
|
(if (app == remaining 0)
|
||||||
(do io/print_int 9999)
|
(app print 9999)
|
||||||
(if (app == print_countdown 0)
|
(if (app == print_countdown 0)
|
||||||
(seq
|
(seq
|
||||||
(do io/print_int (app one_op chunk_len t))
|
(app print (app one_op chunk_len t))
|
||||||
(tail-app loop
|
(tail-app loop
|
||||||
(app - remaining 1)
|
(app - remaining 1)
|
||||||
(app - print_k 1)
|
(app - print_k 1)
|
||||||
@@ -165,5 +165,5 @@
|
|||||||
(let t (app build_tree 19)
|
(let t (app build_tree 19)
|
||||||
(let _root (app pin_root t)
|
(let _root (app pin_root t)
|
||||||
(seq
|
(seq
|
||||||
(do io/print_int 8888)
|
(app print 8888)
|
||||||
(app loop 20000 0 500 20 t)))))))
|
(app loop 20000 0 500 20 t)))))))
|
||||||
|
|||||||
@@ -195,10 +195,10 @@
|
|||||||
(params remaining print_countdown chunk_len print_k t)
|
(params remaining print_countdown chunk_len print_k t)
|
||||||
(body
|
(body
|
||||||
(if (app == remaining 0)
|
(if (app == remaining 0)
|
||||||
(do io/print_int 9999)
|
(app print 9999)
|
||||||
(if (app == print_countdown 0)
|
(if (app == print_countdown 0)
|
||||||
(seq
|
(seq
|
||||||
(do io/print_int (app one_op chunk_len t))
|
(app print (app one_op chunk_len t))
|
||||||
(tail-app loop
|
(tail-app loop
|
||||||
(app - remaining 1)
|
(app - remaining 1)
|
||||||
(app - print_k 1)
|
(app - print_k 1)
|
||||||
@@ -221,5 +221,5 @@
|
|||||||
(let t (app build_tree 19)
|
(let t (app build_tree 19)
|
||||||
(let _root (app pin_root t)
|
(let _root (app pin_root t)
|
||||||
(seq
|
(seq
|
||||||
(do io/print_int 8888)
|
(app print 8888)
|
||||||
(app loop 20000 0 500 20 t)))))))
|
(app loop 20000 0 500 20 t)))))))
|
||||||
|
|||||||
@@ -88,7 +88,7 @@
|
|||||||
(type (fn-type (params (con Int)) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params (con Int)) (ret (con Unit)) (effects IO)))
|
||||||
(params n)
|
(params n)
|
||||||
(body
|
(body
|
||||||
(do io/print_int (app sum_list (app cons_n n)))))
|
(app print (app sum_list (app cons_n n)))))
|
||||||
|
|
||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ fn sum_list(xs: IntList) -> Int {
|
|||||||
|
|
||||||
/// Build a list of length n, sum it, print the sum.
|
/// Build a list of length n, sum it, print the sum.
|
||||||
fn run_one(n: Int) -> Unit with IO {
|
fn run_one(n: Int) -> Unit with IO {
|
||||||
do io/print_int(sum_list(cons_n(n)))
|
print(sum_list(cons_n(n)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Unit with IO {
|
fn main() -> Unit with IO {
|
||||||
|
|||||||
@@ -83,7 +83,7 @@
|
|||||||
(type (fn-type (params (con Int)) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params (con Int)) (ret (con Unit)) (effects IO)))
|
||||||
(params n)
|
(params n)
|
||||||
(body
|
(body
|
||||||
(do io/print_int (app sum_list (app cons_n n)))))
|
(app print (app sum_list (app cons_n n)))))
|
||||||
|
|
||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
|
|||||||
@@ -20,4 +20,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (do io/print_int (app loop_call 100000000 0)))))
|
(body (app print (app loop_call 100000000 0)))))
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
(type (fn-type (params (con Int)) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params (con Int)) (ret (con Unit)) (effects IO)))
|
||||||
(params depth)
|
(params depth)
|
||||||
(body
|
(body
|
||||||
(do io/print_int (app sum_tree (app build_tree depth)))))
|
(app print (app sum_tree (app build_tree depth)))))
|
||||||
|
|
||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
; (borrow (con List)) — list_length's xs parameter
|
; (borrow (con List)) — list_length's xs parameter
|
||||||
; (own (con List)) — sum_list's xs parameter
|
; (own (con List)) — sum_list's xs parameter
|
||||||
;
|
;
|
||||||
; Expected stdout (one int per line, via io/print_int + a newline):
|
; Expected stdout (one int per line, via polymorphic `print` + a newline):
|
||||||
; 3
|
; 3
|
||||||
; 6
|
; 6
|
||||||
|
|
||||||
@@ -60,5 +60,5 @@
|
|||||||
(term-ctor List Cons 3
|
(term-ctor List Cons 3
|
||||||
(term-ctor List Nil))))
|
(term-ctor List Nil))))
|
||||||
(seq
|
(seq
|
||||||
(do io/print_int (app list_length xs))
|
(app print (app list_length xs))
|
||||||
(do io/print_int (app sum_list xs)))))))
|
(app print (app sum_list xs)))))))
|
||||||
|
|||||||
+1
-1
@@ -31,6 +31,6 @@
|
|||||||
(effects IO)))
|
(effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(do io/print_int
|
(app print
|
||||||
(app unbox
|
(app unbox
|
||||||
(term-ctor Box MkBox 42))))))
|
(term-ctor Box MkBox 42))))))
|
||||||
|
|||||||
@@ -23,4 +23,4 @@
|
|||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(let x 42
|
(let x 42
|
||||||
(do io/print_int (clone x))))))
|
(app print (clone x))))))
|
||||||
|
|||||||
@@ -8,4 +8,4 @@
|
|||||||
(doc "captures `n` from the enclosing let, returns 42")
|
(doc "captures `n` from the enclosing let, returns 42")
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (let n 3 (do io/print_int (app apply (lam (params (typed x (con Int))) (ret (con Int)) (body (app + x n))) 39))))))
|
(body (let n 3 (app print (app apply (lam (params (typed x (con Int))) (ret (con Int)) (body (app + x n))) 39))))))
|
||||||
|
|||||||
@@ -8,4 +8,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (do io/print_int (app cmp_max 3 7)))))
|
(body (app print (app cmp_max 3 7)))))
|
||||||
|
|||||||
@@ -2,31 +2,31 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (seq (do io/print_int (match (app compare 1 2)
|
(body (seq (app print (match (app compare 1 2)
|
||||||
(case (pat-ctor LT) 1)
|
(case (pat-ctor LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(case (pat-ctor EQ) 2)
|
||||||
(case (pat-ctor GT) 3))) (seq (do io/print_int (match (app compare 1 1)
|
(case (pat-ctor GT) 3))) (seq (app print (match (app compare 1 1)
|
||||||
(case (pat-ctor LT) 1)
|
(case (pat-ctor LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(case (pat-ctor EQ) 2)
|
||||||
(case (pat-ctor GT) 3))) (seq (do io/print_int (match (app compare 2 1)
|
(case (pat-ctor GT) 3))) (seq (app print (match (app compare 2 1)
|
||||||
(case (pat-ctor LT) 1)
|
(case (pat-ctor LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(case (pat-ctor EQ) 2)
|
||||||
(case (pat-ctor GT) 3))) (seq (do io/print_int (match (app compare false true)
|
(case (pat-ctor GT) 3))) (seq (app print (match (app compare false true)
|
||||||
(case (pat-ctor LT) 1)
|
(case (pat-ctor LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(case (pat-ctor EQ) 2)
|
||||||
(case (pat-ctor GT) 3))) (seq (do io/print_int (match (app compare false false)
|
(case (pat-ctor GT) 3))) (seq (app print (match (app compare false false)
|
||||||
(case (pat-ctor LT) 1)
|
(case (pat-ctor LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(case (pat-ctor EQ) 2)
|
||||||
(case (pat-ctor GT) 3))) (seq (do io/print_int (match (app compare true false)
|
(case (pat-ctor GT) 3))) (seq (app print (match (app compare true false)
|
||||||
(case (pat-ctor LT) 1)
|
(case (pat-ctor LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(case (pat-ctor EQ) 2)
|
||||||
(case (pat-ctor GT) 3))) (seq (do io/print_int (match (app compare "a" "b")
|
(case (pat-ctor GT) 3))) (seq (app print (match (app compare "a" "b")
|
||||||
(case (pat-ctor LT) 1)
|
(case (pat-ctor LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(case (pat-ctor EQ) 2)
|
||||||
(case (pat-ctor GT) 3))) (seq (do io/print_int (match (app compare "a" "a")
|
(case (pat-ctor GT) 3))) (seq (app print (match (app compare "a" "a")
|
||||||
(case (pat-ctor LT) 1)
|
(case (pat-ctor LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(case (pat-ctor EQ) 2)
|
||||||
(case (pat-ctor GT) 3))) (do io/print_int (match (app compare "b" "a")
|
(case (pat-ctor GT) 3))) (app print (match (app compare "b" "a")
|
||||||
(case (pat-ctor LT) 1)
|
(case (pat-ctor LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(case (pat-ctor EQ) 2)
|
||||||
(case (pat-ctor GT) 3))))))))))))))
|
(case (pat-ctor GT) 3))))))))))))))
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
(match xs
|
(match xs
|
||||||
(case (pat-ctor INil) (lit-unit))
|
(case (pat-ctor INil) (lit-unit))
|
||||||
(case (pat-ctor ICons h t)
|
(case (pat-ctor ICons h t)
|
||||||
(seq (do io/print_int (app signum h))
|
(seq (app print (app signum h))
|
||||||
(tail-app drain t))))))
|
(tail-app drain t))))))
|
||||||
|
|
||||||
(fn main
|
(fn main
|
||||||
|
|||||||
@@ -28,4 +28,4 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(do io/print_int (app std_maybe.from_maybe 99 (app classify (term-ctor std_maybe.Maybe Just 7)))))))
|
(app print (app std_maybe.from_maybe 99 (app classify (term-ctor std_maybe.Maybe Just 7)))))))
|
||||||
|
|||||||
+11
-11
@@ -25,7 +25,7 @@
|
|||||||
; 2 ; classify_str "ho" (lit-pattern hits 2 arm)
|
; 2 ; classify_str "ho" (lit-pattern hits 2 arm)
|
||||||
; 0 ; classify_str "??" (default arm)
|
; 0 ; classify_str "??" (default arm)
|
||||||
;
|
;
|
||||||
; Driver lowers via io/print_bool / io/print_int.
|
; Driver routes through the polymorphic `print` helper (Show Bool / Show Int).
|
||||||
|
|
||||||
(module eq_demo
|
(module eq_demo
|
||||||
|
|
||||||
@@ -44,13 +44,13 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (do io/print_bool (app == 5 5))
|
(seq (app print (app == 5 5))
|
||||||
(seq (do io/print_bool (app == 5 6))
|
(seq (app print (app == 5 6))
|
||||||
(seq (do io/print_bool (app == true false))
|
(seq (app print (app == true false))
|
||||||
(seq (do io/print_bool (app == true true))
|
(seq (app print (app == true true))
|
||||||
(seq (do io/print_bool (app == "hi" "hi"))
|
(seq (app print (app == "hi" "hi"))
|
||||||
(seq (do io/print_bool (app == "hi" "ho"))
|
(seq (app print (app == "hi" "ho"))
|
||||||
(seq (do io/print_bool (app == (lit-unit) (lit-unit)))
|
(seq (app print (app == (lit-unit) (lit-unit)))
|
||||||
(seq (do io/print_int (app classify_str "hi"))
|
(seq (app print (app classify_str "hi"))
|
||||||
(seq (do io/print_int (app classify_str "ho"))
|
(seq (app print (app classify_str "ho"))
|
||||||
(do io/print_int (app classify_str "??"))))))))))))))
|
(app print (app classify_str "??"))))))))))))))
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (do io/print_int (if (app eq 1.0 2.0) 1 0)))))
|
(body (app print (if (app eq 1.0 2.0) 1 0)))))
|
||||||
|
|||||||
@@ -7,4 +7,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (seq (do io/print_int (if (app at_most 3 5) 1 0)) (seq (do io/print_int (if (app at_most true false) 1 0)) (do io/print_int (if (app at_most "abc" "abd") 1 0)))))))
|
(body (seq (app print (if (app at_most 3 5) 1 0)) (seq (app print (if (app at_most true false) 1 0)) (app print (if (app at_most "abc" "abd") 1 0)))))))
|
||||||
|
|||||||
@@ -21,4 +21,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (seq (do io/print_int (if (app eq (term-ctor IntBox MkIntBox 3) (term-ctor IntBox MkIntBox 3)) 1 0)) (do io/print_int (if (app eq (term-ctor IntBox MkIntBox 3) (term-ctor IntBox MkIntBox 5)) 1 0))))))
|
(body (seq (app print (if (app eq (term-ctor IntBox MkIntBox 3) (term-ctor IntBox MkIntBox 3)) 1 0)) (app print (if (app eq (term-ctor IntBox MkIntBox 3) (term-ctor IntBox MkIntBox 5)) 1 0))))))
|
||||||
|
|||||||
@@ -7,4 +7,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (seq (do io/print_int (app to_int (app eq 7 7))) (seq (do io/print_int (app to_int (app eq 7 8))) (seq (do io/print_int (app to_int (app eq true true))) (seq (do io/print_int (app to_int (app eq true false))) (seq (do io/print_int (app to_int (app eq "hello" "hello"))) (do io/print_int (app to_int (app eq "hello" "world")))))))))))
|
(body (seq (app print (app to_int (app eq 7 7))) (seq (app print (app to_int (app eq 7 8))) (seq (app print (app to_int (app eq true true))) (seq (app print (app to_int (app eq true false))) (seq (app print (app to_int (app eq "hello" "hello"))) (app print (app to_int (app eq "hello" "world")))))))))))
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (do io/print_int (app peek 0))
|
(seq (app print (app peek 0))
|
||||||
(seq (do io/print_int (app peek 123))
|
(seq (app print (app peek 123))
|
||||||
(seq (do io/print_int (app count 5))
|
(seq (app print (app count 5))
|
||||||
(do io/print_int (app count 0))))))))
|
(app print (app count 0))))))))
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
; sqrt(2.0). Expected stdout (one line): approximately 1.41421356...
|
; sqrt(2.0). Expected stdout (one line): approximately 1.41421356...
|
||||||
;
|
;
|
||||||
; Exercises: Float literals, polymorphic +, *, /, recursion with
|
; Exercises: Float literals, polymorphic +, *, /, recursion with
|
||||||
; Float-typed accumulator, io/print_float.
|
; Float-typed accumulator, polymorphic `print` (Show Float).
|
||||||
|
|
||||||
(module floats_1_newton_sqrt
|
(module floats_1_newton_sqrt
|
||||||
|
|
||||||
@@ -35,4 +35,4 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(do io/print_float (app sqrt 2.0)))))
|
(app print (app sqrt 2.0)))))
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(do io/print_float
|
(app print
|
||||||
(app mean
|
(app mean
|
||||||
(term-ctor IntList Cons 1
|
(term-ctor IntList Cons 1
|
||||||
(term-ctor IntList Cons 2
|
(term-ctor IntList Cons 2
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
; nan ; 0/0
|
; nan ; 0/0
|
||||||
; -1 ; classify(0/0) -> NaN
|
; -1 ; classify(0/0) -> NaN
|
||||||
;
|
;
|
||||||
; (`io/print_float` prints "%g\n", so inf prints as "inf", NaN as "nan".)
|
; (`print` for Float routes through `float_to_str`, which uses "%g", so inf prints as "inf", NaN as "nan".)
|
||||||
|
|
||||||
(module floats_3_safe_division
|
(module floats_3_safe_division
|
||||||
|
|
||||||
@@ -47,9 +47,9 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (do io/print_float (app / 6.0 3.0))
|
(seq (app print (app / 6.0 3.0))
|
||||||
(seq (do io/print_int (app classify (app / 6.0 3.0)))
|
(seq (app print (app classify (app / 6.0 3.0)))
|
||||||
(seq (do io/print_float (app / 1.0 0.0))
|
(seq (app print (app / 1.0 0.0))
|
||||||
(seq (do io/print_int (app classify (app / 1.0 0.0)))
|
(seq (app print (app classify (app / 1.0 0.0)))
|
||||||
(seq (do io/print_float (app / 0.0 0.0))
|
(seq (app print (app / 0.0 0.0))
|
||||||
(do io/print_int (app classify (app / 0.0 0.0)))))))))))
|
(app print (app classify (app / 0.0 0.0)))))))))))
|
||||||
|
|||||||
@@ -26,5 +26,5 @@
|
|||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq
|
(seq
|
||||||
(do io/print_int (app fact 5))
|
(app print (app fact 5))
|
||||||
(do io/print_int (app fact 10))))))
|
(app print (app fact 10))))))
|
||||||
|
|||||||
@@ -8,6 +8,6 @@
|
|||||||
(body
|
(body
|
||||||
(seq
|
(seq
|
||||||
(seq
|
(seq
|
||||||
(do io/print_int (app forma_4_intmath_lib.square 7))
|
(app print (app forma_4_intmath_lib.square 7))
|
||||||
(do io/print_int (app forma_4_intmath_lib.cube 3)))
|
(app print (app forma_4_intmath_lib.cube 3)))
|
||||||
(do io/print_int (app forma_4_intmath_lib.abs_int (app - 0 42)))))))
|
(app print (app forma_4_intmath_lib.abs_int (app - 0 42)))))))
|
||||||
|
|||||||
+1
-1
@@ -2,4 +2,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (seq (do io/print_float (app + 1.5 2.5)) (seq (do io/print_float (app int_to_float 42)) (do io/print_float (app neg 1.5)))))))
|
(body (seq (app print (app + 1.5 2.5)) (seq (app print (app int_to_float 42)) (app print (app neg 1.5)))))))
|
||||||
|
|||||||
@@ -44,4 +44,4 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(do io/print_int (app sum_list (app build 50))))))
|
(app print (app sum_list (app build 50))))))
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (do io/print_int (if (app ge 3 5) 1 0)))))
|
(body (app print (if (app ge 3 5) 1 0)))))
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (do io/print_int (if (app gt true false) 1 0)))))
|
(body (app print (if (app gt true false) 1 0)))))
|
||||||
|
|||||||
+1
-1
@@ -12,4 +12,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (do io/print_int (app apply inc 41)))))
|
(body (app print (app apply inc 41)))))
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
(module int_to_print_int_borrow
|
(module int_to_print_int_borrow
|
||||||
(fn main
|
(fn main
|
||||||
(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).")
|
(doc "Iter eob.1 / rpe.1: primitive Int passed to the polymorphic `print` helper (Show 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).")
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (let n 7 (do io/print_int n)))))
|
(body (let n 7 (app print n)))))
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (do io/print_int (if (app le "abc" "abd") 1 0)))))
|
(body (app print (if (app le "abc" "abd") 1 0)))))
|
||||||
|
|||||||
+1
-1
@@ -14,4 +14,4 @@
|
|||||||
(doc "Baut [10, 20, 12] und druckt die Summe (42).")
|
(doc "Baut [10, 20, 12] und druckt die Summe (42).")
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (let xs (term-ctor IntList Cons 10 (term-ctor IntList Cons 20 (term-ctor IntList Cons 12 (term-ctor IntList Nil)))) (do io/print_int (app sum_list xs))))))
|
(body (let xs (term-ctor IntList Cons 10 (term-ctor IntList Cons 20 (term-ctor IntList Cons 12 (term-ctor IntList Nil)))) (app print (app sum_list xs))))))
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
(params xs)
|
(params xs)
|
||||||
(body (match xs
|
(body (match xs
|
||||||
(case (pat-ctor Nil) (lit-unit))
|
(case (pat-ctor Nil) (lit-unit))
|
||||||
(case (pat-ctor Cons h t) (seq (do io/print_int h) (app print_list t))))))
|
(case (pat-ctor Cons h t) (seq (app print h) (app print_list t))))))
|
||||||
(fn main
|
(fn main
|
||||||
(doc "Build [1,2,3], double each, print result.")
|
(doc "Build [1,2,3], double each, print result.")
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
(lit-unit))
|
(lit-unit))
|
||||||
(case (pat-ctor Cons h t)
|
(case (pat-ctor Cons h t)
|
||||||
(seq
|
(seq
|
||||||
(do io/print_int h)
|
(app print h)
|
||||||
(tail-app print_list t))))))
|
(tail-app print_list t))))))
|
||||||
|
|
||||||
(fn main
|
(fn main
|
||||||
|
|||||||
@@ -46,9 +46,9 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (do io/print_int (app classify 0))
|
(seq (app print (app classify 0))
|
||||||
(seq (do io/print_int (app classify 1))
|
(seq (app print (app classify 1))
|
||||||
(seq (do io/print_int (app classify 17))
|
(seq (app print (app classify 17))
|
||||||
(seq (do io/print_int (app categorize_first (term-ctor IntList Nil)))
|
(seq (app print (app categorize_first (term-ctor IntList Nil)))
|
||||||
(seq (do io/print_int (app categorize_first (term-ctor IntList Cons 0 (term-ctor IntList Nil))))
|
(seq (app print (app categorize_first (term-ctor IntList Cons 0 (term-ctor IntList Nil))))
|
||||||
(do io/print_int (app categorize_first (term-ctor IntList Cons 7 (term-ctor IntList Nil))))))))))))
|
(app print (app categorize_first (term-ctor IntList Cons 7 (term-ctor IntList Nil))))))))))))
|
||||||
|
|||||||
@@ -30,4 +30,4 @@
|
|||||||
(if (app <= n 1)
|
(if (app <= n 1)
|
||||||
1
|
1
|
||||||
(app * n (app factorial (app - n 1)))))
|
(app * n (app factorial (app - n 1)))))
|
||||||
(in (do io/print_int (app apply5 factorial)))))))
|
(in (app print (app apply5 factorial)))))))
|
||||||
|
|||||||
@@ -39,5 +39,5 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (do io/print_int (app run_with_base 10))
|
(seq (app print (app run_with_base 10))
|
||||||
(do io/print_int (app run_with_base 100))))))
|
(app print (app run_with_base 100))))))
|
||||||
|
|||||||
@@ -30,6 +30,6 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (do io/print_int (app sum_below 1))
|
(seq (app print (app sum_below 1))
|
||||||
(seq (do io/print_int (app sum_below 5))
|
(seq (app print (app sum_below 5))
|
||||||
(do io/print_int (app sum_below 10)))))))
|
(app print (app sum_below 10)))))))
|
||||||
|
|||||||
@@ -21,6 +21,6 @@
|
|||||||
1
|
1
|
||||||
(app * n (app fact (app - n 1)))))
|
(app * n (app fact (app - n 1)))))
|
||||||
(in
|
(in
|
||||||
(seq (do io/print_int (app fact 1))
|
(seq (app print (app fact 1))
|
||||||
(seq (do io/print_int (app fact 3))
|
(seq (app print (app fact 3))
|
||||||
(do io/print_int (app fact 5)))))))))
|
(app print (app fact 5)))))))))
|
||||||
|
|||||||
@@ -43,6 +43,6 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (do io/print_int (app count_below 0))
|
(seq (app print (app count_below 0))
|
||||||
(seq (do io/print_int (app count_below 5))
|
(seq (app print (app count_below 5))
|
||||||
(do io/print_int (app count_below 15)))))))
|
(app print (app count_below 15)))))))
|
||||||
|
|||||||
@@ -54,6 +54,6 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (do io/print_int (app count_below (term-ctor Pair MkPair 10 0)))
|
(seq (app print (app count_below (term-ctor Pair MkPair 10 0)))
|
||||||
(seq (do io/print_int (app count_below (term-ctor Pair MkPair 10 5)))
|
(seq (app print (app count_below (term-ctor Pair MkPair 10 5)))
|
||||||
(do io/print_int (app count_below (term-ctor Pair MkPair 10 15))))))))
|
(app print (app count_below (term-ctor Pair MkPair 10 15))))))))
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (do io/print_int (if (app lt 3 5) 1 0)))))
|
(body (app print (if (app lt 3 5) 1 0)))))
|
||||||
|
|||||||
+1
-1
@@ -11,4 +11,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (do io/print_int (app max3 3 17 9)))))
|
(body (app print (app max3 3 17 9)))))
|
||||||
|
|||||||
@@ -14,4 +14,4 @@
|
|||||||
(doc "Print or_else for both arms; expected 7 then 99.")
|
(doc "Print or_else for both arms; expected 7 then 99.")
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (seq (do io/print_int (app or_else (term-ctor Maybe Some 7) 99)) (do io/print_int (app or_else (term-ctor Maybe None) 99))))))
|
(body (seq (app print (app or_else (term-ctor Maybe Some 7) 99)) (app print (app or_else (term-ctor Maybe None) 99))))))
|
||||||
|
|||||||
@@ -9,4 +9,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (seq (do io/print_bool (app eq 1 1)) (seq (do io/print_bool (app eq true true)) (seq (do io/print_bool (app eq "a" "a")) (seq (do io/print_int (app ord_to_int (app compare 1 2))) (seq (do io/print_int (app ord_to_int (app compare false true))) (do io/print_int (app ord_to_int (app compare "a" "b")))))))))))
|
(body (seq (app print (app eq 1 1)) (seq (app print (app eq true true)) (seq (app print (app eq "a" "a")) (seq (app print (app ord_to_int (app compare 1 2))) (seq (app print (app ord_to_int (app compare false true))) (app print (app ord_to_int (app compare "a" "b")))))))))))
|
||||||
|
|||||||
@@ -5,4 +5,4 @@
|
|||||||
(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.")
|
(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 (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (do io/print_bool (app myeq 1 2)))))
|
(body (app print (app myeq 1 2)))))
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (do io/print_int (if (app ne 3 5) 1 0)))))
|
(body (app print (if (app ne 3 5) 1 0)))))
|
||||||
|
|||||||
@@ -48,6 +48,6 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (do io/print_int (app nested_sum 1))
|
(seq (app print (app nested_sum 1))
|
||||||
(seq (do io/print_int (app nested_sum 3))
|
(seq (app print (app nested_sum 3))
|
||||||
(do io/print_int (app nested_sum 5)))))))
|
(app print (app nested_sum 5)))))))
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(do io/print_int (app first_two_sum
|
(app print (app first_two_sum
|
||||||
(term-ctor std_list.List Cons 10
|
(term-ctor std_list.List Cons 10
|
||||||
(term-ctor std_list.List Cons 20
|
(term-ctor std_list.List Cons 20
|
||||||
(term-ctor std_list.List Cons 30
|
(term-ctor std_list.List Cons 30
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
(doc "Iter 23.1 fixture: pattern-match on prelude Ordering ctor without explicit prelude import.")
|
(doc "Iter 23.1 fixture: pattern-match on prelude Ordering ctor without explicit prelude import.")
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (do io/print_int (match (term-ctor prelude.Ordering LT)
|
(body (app print (match (term-ctor prelude.Ordering LT)
|
||||||
(case (pat-ctor LT) 1)
|
(case (pat-ctor LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(case (pat-ctor EQ) 2)
|
||||||
(case (pat-ctor GT) 3))))))
|
(case (pat-ctor GT) 3))))))
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
/// Iter 23.1 fixture: pattern-match on prelude Ordering ctor without explicit
|
/// Iter 23.1 fixture: pattern-match on prelude Ordering ctor without explicit
|
||||||
/// prelude import.
|
/// prelude import.
|
||||||
fn main() -> Unit with IO {
|
fn main() -> Unit with IO {
|
||||||
do io/print_int(match LT {
|
print(match LT {
|
||||||
LT => 1,
|
LT => 1,
|
||||||
EQ => 2,
|
EQ => 2,
|
||||||
GT => 3
|
GT => 3
|
||||||
|
|||||||
@@ -62,4 +62,4 @@
|
|||||||
(term-ctor IntList Nil)))))
|
(term-ctor IntList Nil)))))
|
||||||
(match p
|
(match p
|
||||||
(case (pat-ctor Pair a _)
|
(case (pat-ctor Pair a _)
|
||||||
(do io/print_int (app sum_list a))))))))
|
(app print (app sum_list a))))))))
|
||||||
|
|||||||
@@ -10,4 +10,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (do io/print_int (app apply succ 41)))))
|
(body (app print (app apply succ 41)))))
|
||||||
|
|||||||
@@ -6,4 +6,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (seq (do io/print_int (app id 42)) (do io/print_bool (app id true))))))
|
(body (seq (app print (app id 42)) (app print (app id true))))))
|
||||||
|
|||||||
@@ -53,5 +53,5 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (do io/print_int (app apply_n_times 5 0 succ))
|
(seq (app print (app apply_n_times 5 0 succ))
|
||||||
(do io/print_bool (app apply_n_times 4 false flip))))))
|
(app print (app apply_n_times 4 false flip))))))
|
||||||
|
|||||||
@@ -18,5 +18,5 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (let p (app build_pair 1) (do io/print_int (match p
|
(body (let p (app build_pair 1) (app print (match p
|
||||||
(case (pat-ctor MkPair a _) (app use_cell a))))))))
|
(case (pat-ctor MkPair a _) (app use_cell a))))))))
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ fn use_cell(c: own Cell) -> Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Unit with IO {
|
fn main() -> Unit with IO {
|
||||||
do io/print_int(match build_pair(1) {
|
print(match build_pair(1) {
|
||||||
MkPair(a, _) => use_cell(a)
|
MkPair(a, _) => use_cell(a)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,4 +7,4 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (let b (term-ctor Box MkBox 42) (match b
|
(body (let b (term-ctor Box MkBox 42) (match b
|
||||||
(case (pat-ctor MkBox x) (do io/print_int x)))))))
|
(case (pat-ctor MkBox x) (app print x)))))))
|
||||||
|
|||||||
@@ -24,4 +24,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (do io/print_int (app head_or_zero (app cons_n 1000000))))))
|
(body (app print (app head_or_zero (app cons_n 1000000))))))
|
||||||
|
|||||||
@@ -76,4 +76,4 @@
|
|||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(let t (app build 2)
|
(let t (app build 2)
|
||||||
(do io/print_int (app loop 3 t))))))
|
(app print (app loop 3 t))))))
|
||||||
|
|||||||
@@ -59,5 +59,5 @@
|
|||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(let x (app alloc 7)
|
(let x (app alloc 7)
|
||||||
(do io/print_int (app unbox x)))))
|
(app print (app unbox x)))))
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -50,4 +50,4 @@
|
|||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(let t (app build 1)
|
(let t (app build 1)
|
||||||
(do io/print_int (app pin t))))))
|
(app print (app pin t))))))
|
||||||
|
|||||||
@@ -14,4 +14,4 @@
|
|||||||
(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).")
|
(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).")
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (let xs (term-ctor IntList Cons 1 (term-ctor IntList Cons 2 (term-ctor IntList Cons 3 (term-ctor IntList Cons 4 (term-ctor IntList Cons 5 (term-ctor IntList Nil)))))) (do io/print_int (app sum_list xs))))))
|
(body (let xs (term-ctor IntList Cons 1 (term-ctor IntList Cons 2 (term-ctor IntList Cons 3 (term-ctor IntList Cons 4 (term-ctor IntList Cons 5 (term-ctor IntList Nil)))))) (app print (app sum_list xs))))))
|
||||||
|
|||||||
@@ -8,5 +8,5 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (let xs (term-ctor IntList Cons 11 (term-ctor IntList Cons 22 (term-ctor IntList Cons 33 (term-ctor IntList Cons 44 (term-ctor IntList Cons 55 (term-ctor IntList Nil)))))) (match xs
|
(body (let xs (term-ctor IntList Cons 11 (term-ctor IntList Cons 22 (term-ctor IntList Cons 33 (term-ctor IntList Cons 44 (term-ctor IntList Cons 55 (term-ctor IntList Nil)))))) (match xs
|
||||||
(case (pat-ctor Nil) (do io/print_int 0))
|
(case (pat-ctor Nil) (app print 0))
|
||||||
(case (pat-ctor Cons h t) (do io/print_int h)))))))
|
(case (pat-ctor Cons h t) (app print h)))))))
|
||||||
|
|||||||
@@ -19,4 +19,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (do io/print_int (app use_first (app build_pair 1))))))
|
(body (app print (app use_first (app build_pair 1))))))
|
||||||
|
|||||||
@@ -20,5 +20,5 @@ fn use_first(p: own Pair) -> Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Unit with IO {
|
fn main() -> Unit with IO {
|
||||||
do io/print_int(use_first(build_pair(1)))
|
print(use_first(build_pair(1)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,4 +15,4 @@
|
|||||||
(doc "Build a 5-element IntList; pass to head_or_zero (transferring ownership); print the result.")
|
(doc "Build a 5-element IntList; pass to head_or_zero (transferring ownership); print the result.")
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (let xs (term-ctor IntList Cons 11 (term-ctor IntList Cons 22 (term-ctor IntList Cons 33 (term-ctor IntList Cons 44 (term-ctor IntList Cons 55 (term-ctor IntList Nil)))))) (do io/print_int (app head_or_zero xs))))))
|
(body (let xs (term-ctor IntList Cons 11 (term-ctor IntList Cons 22 (term-ctor IntList Cons 33 (term-ctor IntList Cons 44 (term-ctor IntList Cons 55 (term-ctor IntList Nil)))))) (app print (app head_or_zero xs))))))
|
||||||
|
|||||||
@@ -18,5 +18,5 @@ fn head_or_zero(xs: own IntList) -> Int {
|
|||||||
/// print the result.
|
/// print the result.
|
||||||
fn main() -> Unit with IO {
|
fn main() -> Unit with IO {
|
||||||
let xs = Cons(11, Cons(22, Cons(33, Cons(44, Cons(55, Nil)))));
|
let xs = Cons(11, Cons(22, Cons(33, Cons(44, Cons(55, Nil)))));
|
||||||
do io/print_int(head_or_zero(xs))
|
print(head_or_zero(xs))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,4 +18,4 @@
|
|||||||
(fn main
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (do io/print_int (app use_first (app build_pair 1))))))
|
(body (app print (app use_first (app build_pair 1))))))
|
||||||
|
|||||||
@@ -52,4 +52,4 @@
|
|||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(let t (app build 2)
|
(let t (app build 2)
|
||||||
(do io/print_int (app loop 3 t))))))
|
(app print (app loop 3 t))))))
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user