GREEN: io/print_str byte-faithful via @fputs(@stdout) — closes #29

The runtime print path now writes exactly the bytes of its
argument with no implicit trailing newline. `io/print_str` is
byte-faithful; authors who want a newline emit `(do io/print_str
"\n")` themselves.

## Codegen

`crates/ailang-codegen/src/lib.rs`:
- Module preamble: `@puts(ptr)` → `@fputs(ptr, ptr)` plus
  `@stdout = external global ptr` (libc's `FILE *stdout`).
- Effect-op lowering for `io/print_str`: emit
  `getelementptr +8` then `load ptr, ptr @stdout` then
  `call/tail call i32 @fputs(ptr bytes, ptr fp)`. Identical
  bytes-pointer GEP, distinct sink.
- The pinned IR-shape test renames from
  `print_str_calls_puts_with_bytes_pointer` to
  `print_str_calls_fputs_with_bytes_pointer_and_stdout` and now
  asserts: bytes-GEP present, stdout-load present, both module-
  preamble declarations present, and no `@puts(` call anywhere
  in the emitted IR.

## Why this shape, and not the alternatives

- *Rename `io/print_str` to `io/println_str` (issue #29 option 2)*
  — kept the auto-newline, just relabelled it. AILang's design
  bias is explicit-over-implicit (CLAUDE.md: implicit conversions
  cut). Auto-newline is a hidden runtime augmentation; the rename
  would have preserved it. Rejected.
- *Append `\n` inside the polymorphic `print` (Show-mediated)
  function in `examples/prelude.ail`* — would have been a one-line
  fix. Rejected: `print` is the Show-mediated formatter, not a
  newline emitter; baking a newline into it would have re-imposed
  the same implicit-augmentation problem one layer up, breaking
  callers that legitimately want pure-bytes output.

## Fixture / test sweep

30 `.ail` fixtures whose owning tests asserted line-separated
stdout now emit explicit `(do io/print_str "\n")` after each
print. Tests that asserted on multi-line stdout (`show_print_e2e`,
`floats_e2e`, `str_concat_e2e`, `eq_ord_e2e`, several `print_*`
smoke tests) had their fixtures sweetened the same way; assertions
themselves remain the canonical observable output. Fixtures that
never relied on the newline (no test ever read the absence of one)
were left untouched.

## Migrated metadata

- `crates/ailang-core/tests/hash_pin.rs`: the `ordering_match::main`
  canonical hash is refreshed (`b65a7f834703ffb4` →
  `8ed47b4062ce00f5`). The comment now names both successive
  corpus migrations honestly: the per-type-print-retirement (which
  moved `(do io/print_int x)` to `(app print x)`) AND this
  fputs swap (which wrapped that with `(seq ... (do io/print_str
  "\n"))`).
- `design/contracts/str-abi.md`: the consumer-ABI table now lists
  `@fputs` as the print sink. A prose paragraph documents the
  byte-faithful semantics and references this issue.
- `examples/ordering_match.prose.txt`: regenerated from the
  updated `ordering_match.ail`.
- `crates/ail/tests/snapshots/{hello,sum,max3,list,ws_main}.ll`:
  IR snapshots regenerated via `UPDATE_SNAPSHOTS=1`.
- Stale `@puts` comments in `runtime/str.c`,
  `crates/ail/tests/{e2e,show_print_e2e,print_no_leak_pin}.rs`
  replaced with `@fputs`.

## Verification

- `cargo test -p ail --test print_str_no_auto_newline_e2e` — both
  RED tests from commit c8ecfa3 now pass.
- `cargo test --workspace` — 90 test groups GREEN, 0 failures.
- `cargo build --workspace` — GREEN.
- No new clippy lints (24 warnings pre-existing in
  `crates/ailang-core/src/lib.rs:129`).
- Stats: `bench/orchestrator-stats/2026-05-21-iter-bugfix-print-
  str-fputs.json` — 1/1 tasks, 0 re-loops, 0 review loops.

## Empirical evidence cited

Caught in the 2026-05-21 Qwen3-Coder naming-A/B run
(`experiments/2026-05-21-naming-ab/runs/r1/`): every cohort wrote
`(do io/print_str "...\n")` with explicit `\n` and got doubled
newlines, failing the `t3_main_prints` stdout match across all
three cohorts. The empirical LLM-natural form already assumes the
new (post-this-commit) semantics — confirming the
feature-acceptance test in CLAUDE.md.

closes #29
This commit is contained in:
2026-05-21 12:22:45 +02:00
parent c8ecfa39b9
commit 26fb3459d8
61 changed files with 244 additions and 171 deletions
+1 -1
View File
@@ -3,4 +3,4 @@
(doc "Iter 24.1: pin that `bool_to_str` participates in RC discipline. Bind the heap-Str result to `s`, consume `s` once in `io/print_str`, let the binder drop at scope close. Under --alloc=rc with AILANG_RC_STATS=1 the atexit summary must report allocs == 1 && frees == 1 && live == 0 — the heap-Str slab allocated by str_alloc inside ailang_bool_to_str rides the same rc_header + ailang_rc_dec path as int_to_str.")
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (let s (app bool_to_str true) (do io/print_str s)))))
(body (let s (app bool_to_str true) (seq (do io/print_str s) (do io/print_str "\n"))))))
+1 -1
View File
@@ -3,4 +3,4 @@
(doc "Iter 24.1: stdout-smoke for the false branch of bool_to_str. Stdout must be `false\\n` (puts adds the newline). Companion of bool_to_str_drop_rc.ail.json (which covers the true branch and the RC-stats invariant).")
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (let s (app bool_to_str false) (do io/print_str s)))))
(body (let s (app bool_to_str false) (seq (do io/print_str s) (do io/print_str "\n"))))))
+2 -2
View File
@@ -60,5 +60,5 @@
(term-ctor List Cons 3
(term-ctor List Nil))))
(seq
(app print (app list_length xs))
(app print (app sum_list xs)))))))
(seq (app print (app list_length xs)) (do io/print_str "\n"))
(seq (app print (app sum_list xs)) (do io/print_str "\n")))))))
+10 -10
View File
@@ -2,31 +2,31 @@
(fn main
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (seq (app print (match (app compare 1 2)
(body (seq (seq (app print (match (app compare 1 2)
(case (pat-ctor LT) 1)
(case (pat-ctor EQ) 2)
(case (pat-ctor GT) 3))) (seq (app print (match (app compare 1 1)
(case (pat-ctor GT) 3))) (do io/print_str "\n")) (seq (seq (app print (match (app compare 1 1)
(case (pat-ctor LT) 1)
(case (pat-ctor EQ) 2)
(case (pat-ctor GT) 3))) (seq (app print (match (app compare 2 1)
(case (pat-ctor GT) 3))) (do io/print_str "\n")) (seq (seq (app print (match (app compare 2 1)
(case (pat-ctor LT) 1)
(case (pat-ctor EQ) 2)
(case (pat-ctor GT) 3))) (seq (app print (match (app compare false true)
(case (pat-ctor GT) 3))) (do io/print_str "\n")) (seq (seq (app print (match (app compare false true)
(case (pat-ctor LT) 1)
(case (pat-ctor EQ) 2)
(case (pat-ctor GT) 3))) (seq (app print (match (app compare false false)
(case (pat-ctor GT) 3))) (do io/print_str "\n")) (seq (seq (app print (match (app compare false false)
(case (pat-ctor LT) 1)
(case (pat-ctor EQ) 2)
(case (pat-ctor GT) 3))) (seq (app print (match (app compare true false)
(case (pat-ctor GT) 3))) (do io/print_str "\n")) (seq (seq (app print (match (app compare true false)
(case (pat-ctor LT) 1)
(case (pat-ctor EQ) 2)
(case (pat-ctor GT) 3))) (seq (app print (match (app compare "a" "b")
(case (pat-ctor GT) 3))) (do io/print_str "\n")) (seq (seq (app print (match (app compare "a" "b")
(case (pat-ctor LT) 1)
(case (pat-ctor EQ) 2)
(case (pat-ctor GT) 3))) (seq (app print (match (app compare "a" "a")
(case (pat-ctor GT) 3))) (do io/print_str "\n")) (seq (seq (app print (match (app compare "a" "a")
(case (pat-ctor LT) 1)
(case (pat-ctor EQ) 2)
(case (pat-ctor GT) 3))) (app print (match (app compare "b" "a")
(case (pat-ctor GT) 3))) (do io/print_str "\n")) (seq (app print (match (app compare "b" "a")
(case (pat-ctor LT) 1)
(case (pat-ctor EQ) 2)
(case (pat-ctor GT) 3))))))))))))))
(case (pat-ctor GT) 3))) (do io/print_str "\n")))))))))))))
+10 -10
View File
@@ -47,13 +47,13 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app eq 5 5))
(seq (app print (app eq 5 6))
(seq (app print (app eq true false))
(seq (app print (app eq true true))
(seq (app print (app eq "hi" "hi"))
(seq (app print (app eq "hi" "ho"))
(seq (app print (app eq (lit-unit) (lit-unit)))
(seq (app print (app classify_str "hi"))
(seq (app print (app classify_str "ho"))
(app print (app classify_str "??"))))))))))))))
(seq (seq (app print (app eq 5 5)) (do io/print_str "\n"))
(seq (seq (app print (app eq 5 6)) (do io/print_str "\n"))
(seq (seq (app print (app eq true false)) (do io/print_str "\n"))
(seq (seq (app print (app eq true true)) (do io/print_str "\n"))
(seq (seq (app print (app eq "hi" "hi")) (do io/print_str "\n"))
(seq (seq (app print (app eq "hi" "ho")) (do io/print_str "\n"))
(seq (seq (app print (app eq (lit-unit) (lit-unit))) (do io/print_str "\n"))
(seq (seq (app print (app classify_str "hi")) (do io/print_str "\n"))
(seq (seq (app print (app classify_str "ho")) (do io/print_str "\n"))
(seq (app print (app classify_str "??")) (do io/print_str "\n"))))))))))))))
+1 -1
View File
@@ -7,4 +7,4 @@
(fn main
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(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)))))))
(body (seq (seq (app print (if (app at_most 3 5) 1 0)) (do io/print_str "\n")) (seq (seq (app print (if (app at_most true false) 1 0)) (do io/print_str "\n")) (seq (app print (if (app at_most "abc" "abd") 1 0)) (do io/print_str "\n")))))))
+1 -1
View File
@@ -21,4 +21,4 @@
(fn main
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(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))))))
(body (seq (seq (app print (if (app eq (term-ctor IntBox MkIntBox 3) (term-ctor IntBox MkIntBox 3)) 1 0)) (do io/print_str "\n")) (seq (app print (if (app eq (term-ctor IntBox MkIntBox 3) (term-ctor IntBox MkIntBox 5)) 1 0)) (do io/print_str "\n"))))))
+1 -1
View File
@@ -7,4 +7,4 @@
(fn main
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(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")))))))))))
(body (seq (seq (app print (app to_int (app eq 7 7))) (do io/print_str "\n")) (seq (seq (app print (app to_int (app eq 7 8))) (do io/print_str "\n")) (seq (seq (app print (app to_int (app eq true true))) (do io/print_str "\n")) (seq (seq (app print (app to_int (app eq true false))) (do io/print_str "\n")) (seq (seq (app print (app to_int (app eq "hello" "hello"))) (do io/print_str "\n")) (seq (app print (app to_int (app eq "hello" "world"))) (do io/print_str "\n"))))))))))
+3 -3
View File
@@ -23,6 +23,6 @@
(let p1 (term-ctor Point Point 1 2)
(let p2 (term-ctor Point Point 1 2)
(let p3 (term-ctor Point Point 1 3)
(seq (app print (app eq (lit-unit) (lit-unit)))
(seq (app print (app eq p1 p2))
(app print (app eq p1 p3))))))))))
(seq (seq (app print (app eq (lit-unit) (lit-unit))) (do io/print_str "\n"))
(seq (seq (app print (app eq p1 p2)) (do io/print_str "\n"))
(seq (app print (app eq p1 p3)) (do io/print_str "\n"))))))))))
+4 -4
View File
@@ -51,7 +51,7 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app peek 0))
(seq (app print (app peek 123))
(seq (app print (app count 5))
(app print (app count 0))))))))
(seq (seq (app print (app peek 0)) (do io/print_str "\n"))
(seq (seq (app print (app peek 123)) (do io/print_str "\n"))
(seq (seq (app print (app count 5)) (do io/print_str "\n"))
(seq (app print (app count 0)) (do io/print_str "\n"))))))))
+3 -3
View File
@@ -4,6 +4,6 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app float_eq 1.5 1.5))
(seq (app print (app float_lt 1.0 2.0))
(app print (app float_eq 1.0 0.0)))))))
(seq (seq (app print (app float_eq 1.5 1.5)) (do io/print_str "\n"))
(seq (seq (app print (app float_lt 1.0 2.0)) (do io/print_str "\n"))
(seq (app print (app float_eq 1.0 0.0)) (do io/print_str "\n")))))))
+1 -1
View File
@@ -3,4 +3,4 @@
(doc "Iter hs.4: smoke pin for the float_to_str heap-Str builtin. `do io/print_str(float_to_str(3.5))` builds through the whole pipeline (checker resolves float_to_str:(Float)->Str, codegen lowers to call ptr @ailang_float_to_str(double 3.5), runtime/str.c's ailang_float_to_str snprintfs into a heap-Str slab via libc %g plus a `.0`-fallback for finite whole-valued doubles whose %g output lacks `.`/`e`/`E` (Gitea #7), io/print_str's @puts prints from the bytes pointer at offset 8). The exact rendering of 3.5 is libc-target-dependent; on the dev target's clang+glibc with default C locale it is the three bytes `3.5` (the fallback does not fire because `.` is already present). Single-value smoke; NaN / +Inf / -Inf edge cases are deferred per the hs.4 plan.")
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (do io/print_str (app float_to_str 3.5)))))
(body (seq (do io/print_str (app float_to_str 3.5)) (do io/print_str "\n")))))
+1 -1
View File
@@ -2,4 +2,4 @@
(fn main
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (seq (app print (app + 1.5 2.5)) (seq (app print (app int_to_float 42)) (app print (app neg 1.5)))))))
(body (seq (seq (app print (app + 1.5 2.5)) (do io/print_str "\n")) (seq (seq (app print (app int_to_float 42)) (do io/print_str "\n")) (seq (app print (app neg 1.5)) (do io/print_str "\n")))))))
+1 -1
View File
@@ -3,4 +3,4 @@
(doc "Iter eob.1: heap-Str passed to io/print_str twice in sequence. Under the new rule (Term::Do args = Borrow), the second call no longer triggers use-after-consume; the linearity check accepts the program. Under --alloc=rc + AILANG_RC_STATS=1 the slab allocates once and is freed once at scope close (allocs == 1, frees == 1, live == 0).")
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (let s (app int_to_str 42) (seq (do io/print_str s) (do io/print_str s))))))
(body (let s (app int_to_str 42) (seq (seq (do io/print_str s) (do io/print_str "\n")) (seq (do io/print_str s) (do io/print_str "\n")))))))
+1 -1
View File
@@ -3,4 +3,4 @@
(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)))
(params)
(body (let n 7 (app print n)))))
(body (let n 7 (seq (app print n) (do io/print_str "\n"))))))
+1 -1
View File
@@ -3,4 +3,4 @@
(doc "Iter hs.4: pin that `int_to_str` participates in RC discipline. Bind the heap-Str result to `s`, consume `s` once in `io/print_str`, let the binder drop at scope close. Under --alloc=rc with AILANG_RC_STATS=1 the atexit summary must report allocs == frees && live == 0 — the heap-Str slab allocated by str_alloc inside ailang_int_to_str rides the same rc_header + ailang_rc_dec path as any other RC value.")
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (let s (app int_to_str 42) (do io/print_str s)))))
(body (let s (app int_to_str 42) (seq (do io/print_str s) (do io/print_str "\n"))))))
+1 -1
View File
@@ -3,4 +3,4 @@
(doc "Iter hs.4: smoke pin for the int_to_str heap-Str builtin. `do io/print_str(int_to_str(42))` builds through the whole pipeline (checker resolves int_to_str:(Int)->Str, codegen lowers to call ptr @ailang_int_to_str(i64 42), runtime/str.c's ailang_int_to_str snprintfs into a heap-Str slab, io/print_str's @puts prints from the bytes pointer at offset 8). Single-value smoke; the spec's broader edge-case sweep (0, -1, i64::MAX, i64::MIN) is deferred to a follow-up tidy iter per the hs.4 plan.")
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (do io/print_str (app int_to_str 42)))))
(body (seq (do io/print_str (app int_to_str 42)) (do io/print_str "\n")))))
+1 -1
View File
@@ -16,7 +16,7 @@
(params xs)
(body (match xs
(case (pat-ctor Nil) (lit-unit))
(case (pat-ctor Cons h t) (seq (app print h) (app print_list t))))))
(case (pat-ctor Cons h t) (seq (seq (app print h) (do io/print_str "\n")) (app print_list t))))))
(fn main
(doc "Build [1,2,3], double each, print result.")
(type (fn-type (params) (ret (con Unit)) (effects IO)))
+1 -1
View File
@@ -46,7 +46,7 @@
(lit-unit))
(case (pat-ctor Cons h t)
(seq
(app print h)
(seq (app print h) (do io/print_str "\n"))
(tail-app print_list t))))))
(fn main
+6 -6
View File
@@ -46,9 +46,9 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app classify 0))
(seq (app print (app classify 1))
(seq (app print (app classify 17))
(seq (app print (app categorize_first (term-ctor IntList Nil)))
(seq (app print (app categorize_first (term-ctor IntList Cons 0 (term-ctor IntList Nil))))
(app print (app categorize_first (term-ctor IntList Cons 7 (term-ctor IntList Nil))))))))))))
(seq (seq (app print (app classify 0)) (do io/print_str "\n"))
(seq (seq (app print (app classify 1)) (do io/print_str "\n"))
(seq (seq (app print (app classify 17)) (do io/print_str "\n"))
(seq (seq (app print (app categorize_first (term-ctor IntList Nil))) (do io/print_str "\n"))
(seq (seq (app print (app categorize_first (term-ctor IntList Cons 0 (term-ctor IntList Nil)))) (do io/print_str "\n"))
(seq (app print (app categorize_first (term-ctor IntList Cons 7 (term-ctor IntList Nil)))) (do io/print_str "\n"))))))))))
+2 -2
View File
@@ -39,5 +39,5 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app run_with_base 10))
(app print (app run_with_base 100))))))
(seq (seq (app print (app run_with_base 10)) (do io/print_str "\n"))
(seq (app print (app run_with_base 100)) (do io/print_str "\n"))))))
+3 -3
View File
@@ -30,6 +30,6 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app sum_below 1))
(seq (app print (app sum_below 5))
(app print (app sum_below 10)))))))
(seq (seq (app print (app sum_below 1)) (do io/print_str "\n"))
(seq (seq (app print (app sum_below 5)) (do io/print_str "\n"))
(seq (app print (app sum_below 10)) (do io/print_str "\n")))))))
+3 -3
View File
@@ -21,6 +21,6 @@
1
(app * n (app fact (app - n 1)))))
(in
(seq (app print (app fact 1))
(seq (app print (app fact 3))
(app print (app fact 5)))))))))
(seq (seq (app print (app fact 1)) (do io/print_str "\n"))
(seq (seq (app print (app fact 3)) (do io/print_str "\n"))
(seq (app print (app fact 5)) (do io/print_str "\n")))))))))
+3 -3
View File
@@ -43,6 +43,6 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app count_below 0))
(seq (app print (app count_below 5))
(app print (app count_below 15)))))))
(seq (seq (app print (app count_below 0)) (do io/print_str "\n"))
(seq (seq (app print (app count_below 5)) (do io/print_str "\n"))
(seq (app print (app count_below 15)) (do io/print_str "\n")))))))
+3 -3
View File
@@ -54,6 +54,6 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app count_below (term-ctor Pair MkPair 10 0)))
(seq (app print (app count_below (term-ctor Pair MkPair 10 5)))
(app print (app count_below (term-ctor Pair MkPair 10 15))))))))
(seq (seq (app print (app count_below (term-ctor Pair MkPair 10 0))) (do io/print_str "\n"))
(seq (seq (app print (app count_below (term-ctor Pair MkPair 10 5))) (do io/print_str "\n"))
(seq (app print (app count_below (term-ctor Pair MkPair 10 15))) (do io/print_str "\n")))))))
+1 -1
View File
@@ -14,4 +14,4 @@
(doc "Print or_else for both arms; expected 7 then 99.")
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (seq (app print (app or_else (term-ctor Maybe Some 7) 99)) (app print (app or_else (term-ctor Maybe None) 99))))))
(body (seq (seq (app print (app or_else (term-ctor Maybe Some 7) 99)) (do io/print_str "\n")) (seq (app print (app or_else (term-ctor Maybe None) 99)) (do io/print_str "\n"))))))
+3 -3
View File
@@ -48,6 +48,6 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app nested_sum 1))
(seq (app print (app nested_sum 3))
(app print (app nested_sum 5)))))))
(seq (seq (app print (app nested_sum 1)) (do io/print_str "\n"))
(seq (seq (app print (app nested_sum 3)) (do io/print_str "\n"))
(seq (app print (app nested_sum 5)) (do io/print_str "\n")))))))
+1 -1
View File
@@ -3,7 +3,7 @@
(doc "Nullary user function — no params, prints a fixed line.")
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (do io/print_str "hello")))
(body (seq (do io/print_str "hello") (do io/print_str "\n"))))
(fn main
(doc "Calls the nullary `greet` as `(app greet)` — the zero-arg surface form accepted under Gitea #12.")
+2 -2
View File
@@ -3,7 +3,7 @@
(doc "Iter 23.1 fixture: pattern-match on prelude Ordering ctor without explicit prelude import.")
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (app print (match (term-ctor prelude.Ordering LT)
(body (seq (app print (match (term-ctor prelude.Ordering LT)
(case (pat-ctor LT) 1)
(case (pat-ctor EQ) 2)
(case (pat-ctor GT) 3))))))
(case (pat-ctor GT) 3))) (do io/print_str "\n")))))
+2 -1
View File
@@ -7,5 +7,6 @@ fn main() -> Unit with IO {
LT => 1,
EQ => 2,
GT => 3
})
});
do io/print_str("\n")
}
+1 -1
View File
@@ -6,4 +6,4 @@
(fn main
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (seq (app print (app id 42)) (app print (app id true))))))
(body (seq (seq (app print (app id 42)) (do io/print_str "\n")) (seq (app print (app id true)) (do io/print_str "\n"))))))
+2 -2
View File
@@ -53,5 +53,5 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app apply_n_times 5 0 succ))
(app print (app apply_n_times 4 false flip))))))
(seq (seq (app print (app apply_n_times 5 0 succ)) (do io/print_str "\n"))
(seq (app print (app apply_n_times 4 false flip)) (do io/print_str "\n"))))))
+1 -1
View File
@@ -3,4 +3,4 @@
(doc "RED pin for Gitea #7: a whole-valued Float (here, the literal 2.0) routed through polymorphic `print` (which monomorphises to Show Float.show -> float_to_str -> runtime/str.c::ailang_float_to_str -> libc snprintf %g) must render with a `.0` suffix, matching the surface printer's write_float_lit fallback (crates/ailang-surface/src/print.rs lines 624-637). The desired stdout for this fixture is the three bytes `2.0\\n`. Pre-fix, libc %g strips trailing zeros and renders `2\\n` — Int-shaped output for a Float value — which violates the surface-runtime round-trip-on-lex symmetry the language relies on.")
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (app print 2.0))))
(body (seq (app print 2.0) (do io/print_str "\n")))))
+1 -1
View File
@@ -2,4 +2,4 @@
(fn main
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (seq (seq (seq (app print 42) (app print true)) (app print "hello")) (app print 3.14)))))
(body (seq (seq (seq (seq (app print 42) (do io/print_str "\n")) (seq (app print true) (do io/print_str "\n"))) (seq (app print "hello") (do io/print_str "\n"))) (app print 3.14)))))
+1 -1
View File
@@ -10,4 +10,4 @@
(fn main
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (app print (term-ctor Item MkItem 42)))))
(body (seq (app print (term-ctor Item MkItem 42)) (do io/print_str "\n")))))
+1 -1
View File
@@ -22,7 +22,7 @@
(params xs)
(body (match xs
(case (pat-ctor Nil) (lit-unit))
(case (pat-ctor Cons h t) (seq (app print h) (tail-app print_list t))))))
(case (pat-ctor Cons h t) (seq (seq (app print h) (do io/print_str "\n")) (tail-app print_list t))))))
(fn main
(doc "Sort and print [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5].")
(type (fn-type (params) (ret (con Unit)) (effects IO)))
+10 -10
View File
@@ -18,14 +18,14 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app std_either.from_right 0 (term-ctor std_either.Either Right 42)))
(seq (app print (app std_either.from_right 99 (term-ctor std_either.Either Left 7)))
(seq (app print (app std_either.is_left (term-ctor std_either.Either Left 7)))
(seq (app print (app std_either.is_right (term-ctor std_either.Either Right 42)))
(seq (app print (app std_either.from_right 0
(seq (seq (app print (app std_either.from_right 0 (term-ctor std_either.Either Right 42))) (do io/print_str "\n"))
(seq (seq (app print (app std_either.from_right 99 (term-ctor std_either.Either Left 7))) (do io/print_str "\n"))
(seq (seq (app print (app std_either.is_left (term-ctor std_either.Either Left 7))) (do io/print_str "\n"))
(seq (seq (app print (app std_either.is_right (term-ctor std_either.Either Right 42))) (do io/print_str "\n"))
(seq (seq (app print (app std_either.from_right 0
(app std_either.map_right inc
(term-ctor std_either.Either Right 41))))
(seq (app print (app std_either.either inc inc
(term-ctor std_either.Either Left 5)))
(app print (app std_either.either inc inc
(term-ctor std_either.Either Right 100))))))))))))
(term-ctor std_either.Either Right 41)))) (do io/print_str "\n"))
(seq (seq (app print (app std_either.either inc inc
(term-ctor std_either.Either Left 5))) (do io/print_str "\n"))
(seq (app print (app std_either.either inc inc
(term-ctor std_either.Either Right 100))) (do io/print_str "\n")))))))))))
+4 -4
View File
@@ -24,7 +24,7 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app std_list.length (app std_either_list.lefts (term-ctor std_list.List Cons (term-ctor std_either.Either Left 1) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 10) (term-ctor std_list.List Cons (term-ctor std_either.Either Left 2) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 20) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 30) (term-ctor std_list.List Nil)))))))))
(seq (app print (app std_list.length (app std_either_list.rights (term-ctor std_list.List Cons (term-ctor std_either.Either Left 1) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 10) (term-ctor std_list.List Cons (term-ctor std_either.Either Left 2) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 20) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 30) (term-ctor std_list.List Nil)))))))))
(seq (app print (app std_list.length (app std_pair.fst (app std_either_list.partition_eithers (term-ctor std_list.List Cons (term-ctor std_either.Either Left 1) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 10) (term-ctor std_list.List Cons (term-ctor std_either.Either Left 2) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 20) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 30) (term-ctor std_list.List Nil))))))))))
(app print (app std_list.length (app std_pair.snd (app std_either_list.partition_eithers (term-ctor std_list.List Cons (term-ctor std_either.Either Left 1) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 10) (term-ctor std_list.List Cons (term-ctor std_either.Either Left 2) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 20) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 30) (term-ctor std_list.List Nil))))))))))))))))
(seq (seq (app print (app std_list.length (app std_either_list.lefts (term-ctor std_list.List Cons (term-ctor std_either.Either Left 1) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 10) (term-ctor std_list.List Cons (term-ctor std_either.Either Left 2) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 20) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 30) (term-ctor std_list.List Nil))))))))) (do io/print_str "\n"))
(seq (seq (app print (app std_list.length (app std_either_list.rights (term-ctor std_list.List Cons (term-ctor std_either.Either Left 1) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 10) (term-ctor std_list.List Cons (term-ctor std_either.Either Left 2) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 20) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 30) (term-ctor std_list.List Nil))))))))) (do io/print_str "\n"))
(seq (seq (app print (app std_list.length (app std_pair.fst (app std_either_list.partition_eithers (term-ctor std_list.List Cons (term-ctor std_either.Either Left 1) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 10) (term-ctor std_list.List Cons (term-ctor std_either.Either Left 2) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 20) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 30) (term-ctor std_list.List Nil)))))))))) (do io/print_str "\n"))
(seq (app print (app std_list.length (app std_pair.snd (app std_either_list.partition_eithers (term-ctor std_list.List Cons (term-ctor std_either.Either Left 1) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 10) (term-ctor std_list.List Cons (term-ctor std_either.Either Left 2) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 20) (term-ctor std_list.List Cons (term-ctor std_either.Either Right 30) (term-ctor std_list.List Nil)))))))))) (do io/print_str "\n"))))))))
+11 -11
View File
@@ -48,14 +48,14 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app std_list.length xs))
(seq (app print (app std_list.is_empty xs))
(seq (app print (app std_list.is_empty (term-ctor std_list.List Nil)))
(seq (app print (app std_maybe.from_maybe -1 (app std_list.head xs)))
(seq (app print (app std_list.length (app std_maybe.from_maybe xs (app std_list.tail xs))))
(seq (app print (app std_list.length (app std_list.append xs xs)))
(seq (app print (app std_maybe.from_maybe -1 (app std_list.head (app std_list.reverse xs))))
(seq (app print (app std_maybe.from_maybe -1 (app std_list.head (app std_list.map double xs))))
(seq (app print (app std_list.length (app std_list.filter is_even xs)))
(seq (app print (app std_list.fold_left add 0 xs))
(app print (app std_list.fold_right add 0 xs)))))))))))))))
(seq (seq (app print (app std_list.length xs)) (do io/print_str "\n"))
(seq (seq (app print (app std_list.is_empty xs)) (do io/print_str "\n"))
(seq (seq (app print (app std_list.is_empty (term-ctor std_list.List Nil))) (do io/print_str "\n"))
(seq (seq (app print (app std_maybe.from_maybe -1 (app std_list.head xs))) (do io/print_str "\n"))
(seq (seq (app print (app std_list.length (app std_maybe.from_maybe xs (app std_list.tail xs)))) (do io/print_str "\n"))
(seq (seq (app print (app std_list.length (app std_list.append xs xs))) (do io/print_str "\n"))
(seq (seq (app print (app std_maybe.from_maybe -1 (app std_list.head (app std_list.reverse xs)))) (do io/print_str "\n"))
(seq (seq (app print (app std_maybe.from_maybe -1 (app std_list.head (app std_list.map double xs)))) (do io/print_str "\n"))
(seq (seq (app print (app std_list.length (app std_list.filter is_even xs))) (do io/print_str "\n"))
(seq (seq (app print (app std_list.fold_left add 0 xs)) (do io/print_str "\n"))
(seq (app print (app std_list.fold_right add 0 xs)) (do io/print_str "\n")))))))))))))))
+6 -6
View File
@@ -24,9 +24,9 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app std_list.length (app std_list.take 0 xs)))
(seq (app print (app std_list.length (app std_list.take 3 xs)))
(seq (app print (app std_list.length (app std_list.take 100 xs)))
(seq (app print (app std_list.length (app std_list.drop 0 xs)))
(seq (app print (app std_list.length (app std_list.drop 2 xs)))
(app print (app std_list.length (app std_list.drop 100 xs)))))))))))
(seq (seq (app print (app std_list.length (app std_list.take 0 xs))) (do io/print_str "\n"))
(seq (seq (app print (app std_list.length (app std_list.take 3 xs))) (do io/print_str "\n"))
(seq (seq (app print (app std_list.length (app std_list.take 100 xs))) (do io/print_str "\n"))
(seq (seq (app print (app std_list.length (app std_list.drop 0 xs))) (do io/print_str "\n"))
(seq (seq (app print (app std_list.length (app std_list.drop 2 xs))) (do io/print_str "\n"))
(seq (app print (app std_list.length (app std_list.drop 100 xs))) (do io/print_str "\n"))))))))))
+2 -2
View File
@@ -37,5 +37,5 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app std_list.fold_left add 0 (app build 1000)))
(app print (app std_list.fold_right add 0 (app build 1000)))))))
(seq (seq (app print (app std_list.fold_left add 0 (app build 1000))) (do io/print_str "\n"))
(seq (app print (app std_list.fold_right add 0 (app build 1000))) (do io/print_str "\n"))))))
+5 -5
View File
@@ -23,8 +23,8 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app std_maybe.from_maybe 99 (term-ctor std_maybe.Maybe Just 7)))
(seq (app print (app std_maybe.from_maybe 99 (term-ctor std_maybe.Maybe Nothing)))
(seq (app print (app std_maybe.is_some (term-ctor std_maybe.Maybe Just 5)))
(seq (app print (app std_maybe.is_none (term-ctor std_maybe.Maybe Nothing)))
(app print (app std_maybe.from_maybe 0 (app std_maybe.map_maybe inc (term-ctor std_maybe.Maybe Just 41)))))))))))
(seq (seq (app print (app std_maybe.from_maybe 99 (term-ctor std_maybe.Maybe Just 7))) (do io/print_str "\n"))
(seq (seq (app print (app std_maybe.from_maybe 99 (term-ctor std_maybe.Maybe Nothing))) (do io/print_str "\n"))
(seq (seq (app print (app std_maybe.is_some (term-ctor std_maybe.Maybe Just 5))) (do io/print_str "\n"))
(seq (seq (app print (app std_maybe.is_none (term-ctor std_maybe.Maybe Nothing))) (do io/print_str "\n"))
(seq (app print (app std_maybe.from_maybe 0 (app std_maybe.map_maybe inc (term-ctor std_maybe.Maybe Just 41)))) (do io/print_str "\n")))))))))
+6 -6
View File
@@ -24,9 +24,9 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app std_pair.fst (term-ctor std_pair.Pair MkPair 7 9)))
(seq (app print (app std_pair.snd (term-ctor std_pair.Pair MkPair 7 9)))
(seq (app print (app std_pair.fst (app std_pair.swap (term-ctor std_pair.Pair MkPair 7 9))))
(seq (app print (app std_pair.snd (app std_pair.swap (term-ctor std_pair.Pair MkPair 7 9))))
(seq (app print (app std_pair.fst (app std_pair.map_first inc (term-ctor std_pair.Pair MkPair 7 9))))
(app print (app std_pair.snd (app std_pair.map_second double (term-ctor std_pair.Pair MkPair 7 9))))))))))))
(seq (seq (app print (app std_pair.fst (term-ctor std_pair.Pair MkPair 7 9))) (do io/print_str "\n"))
(seq (seq (app print (app std_pair.snd (term-ctor std_pair.Pair MkPair 7 9))) (do io/print_str "\n"))
(seq (seq (app print (app std_pair.fst (app std_pair.swap (term-ctor std_pair.Pair MkPair 7 9)))) (do io/print_str "\n"))
(seq (seq (app print (app std_pair.snd (app std_pair.swap (term-ctor std_pair.Pair MkPair 7 9)))) (do io/print_str "\n"))
(seq (seq (app print (app std_pair.fst (app std_pair.map_first inc (term-ctor std_pair.Pair MkPair 7 9)))) (do io/print_str "\n"))
(seq (app print (app std_pair.snd (app std_pair.map_second double (term-ctor std_pair.Pair MkPair 7 9)))) (do io/print_str "\n"))))))))))
+1 -1
View File
@@ -3,4 +3,4 @@
(doc "Iter 24.1: cross-realisation invariant for str_clone. Clones a heap-Str (produced by int_to_str 42) AND a static-Str (literal `abc`); both clones produce fresh heap-Str slabs that print their input bytes. Pins the uniform-consumer-ABI claim — str_clone only reads the len-field at offset 0 plus the bytes plus the NUL; it never consults the (absent for static-Str) rc_header. RC stats under --alloc=rc: allocs == 3 (int_to_str output + two str_clone outputs), frees == 3, live == 0.")
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (let src_heap (app int_to_str 42) (let c1 (app str_clone src_heap) (let c2 (app str_clone "abc") (let _a (do io/print_str c1) (do io/print_str c2))))))))
(body (let src_heap (app int_to_str 42) (let c1 (app str_clone src_heap) (let c2 (app str_clone "abc") (let _a (seq (do io/print_str c1) (do io/print_str "\n")) (seq (do io/print_str c2) (do io/print_str "\n")))))))))
+1 -1
View File
@@ -3,4 +3,4 @@
(doc "Iter 24.1: pin that `str_clone` participates in RC discipline AND emits correct bytes. Input is a static-Str literal; the clone produces a fresh heap-Str slab whose payload is byte-equal to the input. RC stats under --alloc=rc with AILANG_RC_STATS=1: allocs == 1 (the clone), frees == 1 (let-binder drop at scope close), live == 0.")
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (let s (app str_clone "hello") (do io/print_str s)))))
(body (let s (app str_clone "hello") (seq (do io/print_str s) (do io/print_str "\n"))))))
+1 -1
View File
@@ -7,4 +7,4 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (let b (term-ctor Boxed Box (app int_to_str 42)) (match b
(case (pat-ctor Box s) (do io/print_str s)))))))
(case (pat-ctor Box s) (seq (do io/print_str s) (do io/print_str "\n"))))))))
@@ -16,4 +16,4 @@
(fn main
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body (seq (app print (app r 0)) (app print (app r true))))))
(body (seq (seq (app print (app r 0)) (do io/print_str "\n")) (seq (app print (app r true)) (do io/print_str "\n"))))))
+2 -2
View File
@@ -31,5 +31,5 @@
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app safe_div 8 2))
(app print (app safe_div 15 3))))))
(seq (seq (app print (app safe_div 8 2)) (do io/print_str "\n"))
(seq (app print (app safe_div 15 3)) (do io/print_str "\n"))))))