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
@@ -0,0 +1,12 @@
{
"iter_id": "bugfix-print-str-fputs",
"date": "2026-05-21",
"mode": "mini",
"outcome": "DONE",
"tasks_total": 1,
"tasks_completed": 1,
"reloops_per_task": { "1": 0 },
"review_loops_spec": 0,
"review_loops_quality": 0,
"blocked_reason": null
}
+2 -1
View File
@@ -2580,7 +2580,8 @@ fn ail_run_accepts_ail_source_with_same_stdout_as_ail_json() {
/// wired in hs.4 — exercises checker (signature install), codegen
/// (lower_app arm + IR-header declare + is_static_callee whitelist),
/// runtime (str.c's `ailang_int_to_str` allocates a heap-Str slab,
/// @puts reads from the bytes pointer at offset 8), and the
/// @fputs reads from the bytes pointer at offset 8 with @stdout as
/// the FILE*), and the
/// unconditional `runtime/rc.c` link (str.c's weak extern of
/// `ailang_rc_alloc` resolves to the strong rc.c definition under
/// every alloc strategy after the hs.4 hoist).
+1 -1
View File
@@ -16,7 +16,7 @@
//! `ailang_rc_stats: allocs=1 frees=0 live=1`. The IR for the post-
//! mono `ail_prelude_print__Int` body contains a `call ptr
//! @ail_prelude_show__Int(...)` followed by `getelementptr +8` +
//! `@puts` + `ret i8 0` — there is no `ailang_rc_dec` on the
//! `@fputs` + `ret i8 0` — there is no `ailang_rc_dec` on the
//! show-result before return. Root cause sits at codegen's
//! `is_rc_heap_allocated` App-arm: it reads the callee's
//! `Type::Fn.ret_mode` via `synth_callee_ret_mode` and requires
+9 -6
View File
@@ -56,12 +56,15 @@ fn build_and_run(fixture: &str) -> String {
#[test]
fn print_primitives_smoke_runs_end_to_end() {
let stdout = build_and_run("show_print_smoke.ail");
// print 42 → "42\n" (int_to_str + puts)
// print true → "true\n" (bool_to_str + puts)
// print "hello" → "hello\n" (str_clone + puts)
// print 3.14 → "3.14\n" (float_to_str / libc %g + puts)
// puts emits each Str + a trailing newline; trimmed output is
// "42\ntrue\nhello\n3.14".
// Post Gitea #29 (io/print_str → @fputs), the print path no
// longer appends an implicit newline. The fixture now emits
// each value with an explicit `(do io/print_str "\n")` after
// the print, so the raw stdout is "42\ntrue\nhello\n3.14\n"
// and `.trim()` lands at "42\ntrue\nhello\n3.14".
// print 42 → "42" (int_to_str), then explicit "\n"
// print true → "true" (bool_to_str), then explicit "\n"
// print "hello" → "hello" (str_clone), then explicit "\n"
// print 3.14 → "3.14" (float_to_str / libc %g)
assert_eq!(stdout, "42\ntrue\nhello\n3.14", "got: {stdout:?}");
}
+4 -2
View File
@@ -5,7 +5,8 @@ target triple = "<NORMALIZED>"
@.str_hello_str_0 = private unnamed_addr constant <{ i64, [15 x i8] }> <{ i64 14, [15 x i8] c"Hello, AILang.\00" }>, align 8
declare i32 @printf(ptr, ...)
declare i32 @puts(ptr)
declare i32 @fputs(ptr, ptr)
@stdout = external global ptr
declare ptr @ailang_rc_alloc(i64)
declare void @ailang_rc_inc(ptr)
declare void @ailang_rc_dec(ptr)
@@ -33,7 +34,8 @@ declare i64 @llvm.fptosi.sat.i64.f64(double)
define i8 @ail_hello_main() {
entry:
%v1 = getelementptr inbounds i8, ptr getelementptr inbounds (<{ i64, [15 x i8] }>, ptr @.str_hello_str_0, i32 0, i32 0), i64 8
call i32 @puts(ptr %v1)
%v2 = load ptr, ptr @stdout, align 8
call i32 @fputs(ptr %v1, ptr %v2)
ret i8 0
}
+4 -2
View File
@@ -3,7 +3,8 @@ source_filename = "list.ail"
target triple = "<NORMALIZED>"
declare i32 @printf(ptr, ...)
declare i32 @puts(ptr)
declare i32 @fputs(ptr, ptr)
@stdout = external global ptr
declare ptr @ailang_rc_alloc(i64)
declare void @ailang_rc_inc(ptr)
declare void @ailang_rc_dec(ptr)
@@ -240,7 +241,8 @@ 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)
%v3 = load ptr, ptr @stdout, align 8
call i32 @fputs(ptr %v2, ptr %v3)
call void @ailang_rc_dec(ptr %v1)
ret i8 0
}
+4 -2
View File
@@ -3,7 +3,8 @@ source_filename = "max3.ail"
target triple = "<NORMALIZED>"
declare i32 @printf(ptr, ...)
declare i32 @puts(ptr)
declare i32 @fputs(ptr, ptr)
@stdout = external global ptr
declare ptr @ailang_rc_alloc(i64)
declare void @ailang_rc_inc(ptr)
declare void @ailang_rc_dec(ptr)
@@ -228,7 +229,8 @@ 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)
%v3 = load ptr, ptr @stdout, align 8
call i32 @fputs(ptr %v2, ptr %v3)
call void @ailang_rc_dec(ptr %v1)
ret i8 0
}
+4 -2
View File
@@ -3,7 +3,8 @@ source_filename = "sum.ail"
target triple = "<NORMALIZED>"
declare i32 @printf(ptr, ...)
declare i32 @puts(ptr)
declare i32 @fputs(ptr, ptr)
@stdout = external global ptr
declare ptr @ailang_rc_alloc(i64)
declare void @ailang_rc_inc(ptr)
declare void @ailang_rc_dec(ptr)
@@ -132,7 +133,8 @@ 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)
%v3 = load ptr, ptr @stdout, align 8
call i32 @fputs(ptr %v2, ptr %v3)
call void @ailang_rc_dec(ptr %v1)
ret i8 0
}
+4 -2
View File
@@ -3,7 +3,8 @@ source_filename = "ws_main.ail"
target triple = "<NORMALIZED>"
declare i32 @printf(ptr, ...)
declare i32 @puts(ptr)
declare i32 @fputs(ptr, ptr)
@stdout = external global ptr
declare ptr @ailang_rc_alloc(i64)
declare void @ailang_rc_inc(ptr)
declare void @ailang_rc_dec(ptr)
@@ -119,7 +120,8 @@ 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)
%v3 = load ptr, ptr @stdout, align 8
call i32 @fputs(ptr %v2, ptr %v3)
call void @ailang_rc_dec(ptr %v1)
ret i8 0
}
+54 -14
View File
@@ -519,7 +519,15 @@ fn lower_workspace_inner(ws: &Workspace, alloc: AllocStrategy, target: Target) -
}
out.push_str("declare i32 @printf(ptr, ...)\n");
out.push_str("declare i32 @puts(ptr)\n");
// `io/print_str` lowers to `fputs(s, stdout)` so the runtime emits
// exactly the bytes of `s` with NO implicit trailing newline. The
// earlier `@puts(ptr)` shape de-facto turned `io/print_str` into
// `println_str` (caught empirically in the cross-model-authoring
// naming-A/B run, Gitea #29). `@stdout` is a libc global FILE*;
// POSIX exposes it as an `extern FILE *stdout` symbol, which LLVM
// IR sees as an opaque pointer to a pointer.
out.push_str("declare i32 @fputs(ptr, ptr)\n");
out.push_str("@stdout = external global ptr\n");
// The allocator declaration name follows `alloc`. `Rc` declares
// `@ailang_rc_alloc` (canonical); `Bump` declares `@bump_malloc`
// (raw-alloc bench-floor), supplied by `runtime/bump.c`.
@@ -2720,8 +2728,8 @@ impl<'a> Emitter<'a> {
fn lower_effect_op(&mut self, op: &str, args: &[Term], tail: bool) -> Result<(String, String)> {
// `musttail` requires identical caller/callee
// prototypes (same return type, same param types). The MVP's
// runtime print helpers (`printf`, `puts`) return `i32`, but the
// AILang fn enclosing a `tail-do io/print_*` returns `Unit`
// runtime print helpers (`printf`, `fputs`) return `i32`, but
// the AILang fn enclosing a `tail-do io/print_*` returns `Unit`
// (`i8`). `musttail` would be rejected by the LLVM verifier.
// We therefore use the `tail` keyword (LLVM IR optimisation
// hint, NOT a guarantee) for `tail: true` do-ops. The optimiser
@@ -2744,14 +2752,23 @@ impl<'a> Emitter<'a> {
));
}
// `Str` values now flow as a pointer to the
// `len`-field of the packed-struct slab; @puts needs
// the bytes pointer 8 bytes further on.
// `len`-field of the packed-struct slab; @fputs needs
// the bytes pointer 8 bytes further on. Loading
// `@stdout` is mandatory: it is `extern FILE *stdout`
// in libc, an opaque pointer-to-pointer at the IR
// level, and we need the inner pointer (the FILE*) as
// the second arg to `fputs`.
let bytes = self.fresh_ssa();
self.body.push_str(&format!(
" {bytes} = getelementptr inbounds i8, ptr {v}, i64 8\n"
));
self.body
.push_str(&format!(" {call_kw} i32 @puts(ptr {bytes})\n"));
let fp = self.fresh_ssa();
self.body.push_str(&format!(
" {fp} = load ptr, ptr @stdout, align 8\n"
));
self.body.push_str(&format!(
" {call_kw} i32 @fputs(ptr {bytes}, ptr {fp})\n"
));
if tail {
self.body.push_str(" ret i8 0\n");
self.block_terminated = true;
@@ -4299,10 +4316,14 @@ mod tests {
/// after the layout migration, the `io/print_str`
/// path must `getelementptr i8` +8 onto the IR-Str pointer before
/// passing it to `@puts`, so `@puts` receives the bytes pointer
/// (skipping the `len` field) and produces correct output.
/// passing it to `@fputs`, so `@fputs` receives the bytes pointer
/// (skipping the `len` field) and produces correct output. Post
/// Gitea #29 the call lowers to `@fputs(ptr bytes, ptr fp)` where
/// `fp` is a `load ptr, ptr @stdout` — `@fputs` (unlike `@puts`)
/// does NOT append a trailing newline, so `io/print_str` is
/// byte-faithful.
#[test]
fn print_str_calls_puts_with_bytes_pointer() {
fn print_str_calls_fputs_with_bytes_pointer_and_stdout() {
let m = Module {
schema: SCHEMA.into(),
name: "t".into(),
@@ -4330,11 +4351,30 @@ mod tests {
let ir = emit_ir(&m).unwrap();
let body_idx = ir.find("define i8 @ail_t_main").expect("main body");
let body = &ir[body_idx..];
let puts_idx = body.find("@puts(").expect("@puts call present");
let before_puts = &body[..puts_idx];
let fputs_idx = body.find("@fputs(").expect("@fputs call present");
let before_fputs = &body[..fputs_idx];
assert!(
before_puts.contains("getelementptr inbounds i8, ptr ") && before_puts.contains(", i64 8"),
"expected `getelementptr inbounds i8, ptr <v>, i64 8` before @puts call; ir body was:\n{body}"
before_fputs.contains("getelementptr inbounds i8, ptr ") && before_fputs.contains(", i64 8"),
"expected `getelementptr inbounds i8, ptr <v>, i64 8` before @fputs call; ir body was:\n{body}"
);
assert!(
before_fputs.contains("load ptr, ptr @stdout"),
"expected `load ptr, ptr @stdout` before @fputs call; ir body was:\n{body}"
);
// Module preamble must declare both: fputs and the @stdout extern.
assert!(
ir.contains("declare i32 @fputs(ptr, ptr)"),
"expected `declare i32 @fputs(ptr, ptr)` in module preamble; ir was:\n{ir}"
);
assert!(
ir.contains("@stdout = external global ptr"),
"expected `@stdout = external global ptr` in module preamble; ir was:\n{ir}"
);
// After the swap there must be no `@puts` call left anywhere
// in the emitted IR — the print path is the only consumer.
assert!(
!ir.contains("@puts("),
"no @puts call should remain after the fputs swap; ir was:\n{ir}"
);
}
+9 -6
View File
@@ -245,14 +245,17 @@ fn ct4_migrated_fixtures_have_canonical_form_hashes() {
let ord_mod = ailang_surface::load_module(&examples.join("ordering_match.ail"))
.expect("examples/ordering_match.ail loads");
let main_def = ord_mod.defs.iter().find(|d| d.name() == "main").unwrap();
// The hash reflects a corpus migration: `ordering_match.ail`'s
// body moved from `(do io/print_int x)` to `(app print x)` when
// the per-type print effect-ops were retired in favour of the
// polymorphic `print` helper.
// The hash reflects two successive corpus migrations:
// (1) the per-type-print-retirement that moved the body from
// `(do io/print_int x)` to `(app print x)`;
// (2) the io/print_str byte-faithful-print fix (Gitea #29) that
// wrapped the `(app print x)` with an explicit
// `(seq ... (do io/print_str "\n"))` newline emission, because
// io/print_str no longer adds a trailing newline.
assert_eq!(
def_hash(main_def),
"b65a7f834703ffb4",
"ordering_match::main canonical hash must match captured post-per-type-print-retirement value"
"8ed47b4062ce00f5",
"ordering_match::main canonical hash must match captured post-fputs-swap value"
);
let dup_a_mod = ailang_surface::load_module(&examples.join("test_22b1_dup_a.ail"))
+5 -2
View File
@@ -60,11 +60,14 @@ Two realisations share this consumer ABI:
| static-Str | string literals (`@.str_*` LLVM globals) | none | `.rodata`, packed-struct `<{ i64, [N+1 x i8] }>` |
| heap-Str | runtime allocations (`int_to_str`, `float_to_str`, ...) | yes, at `payload - 8` | `malloc`'d via `ailang_rc_alloc(8 + len + 1)` |
Every consumer (`@puts`, `@strcmp`, `@ail_str_eq`,
Every consumer (`@fputs`, `@strcmp`, `@ail_str_eq`,
`@ail_str_compare`) GEPs `+8` from the Str pointer to reach the
bytes, regardless of realisation. The byte-comparison semantics
are inherited from libc `strcmp` — locale-independent, NUL-
terminated.
terminated. The print path uses `@fputs(bytes, @stdout)` so that
`(do io/print_str s)` writes exactly the bytes of `s` with no
implicit trailing newline (Gitea #29; the earlier `@puts` lowering
appended a newline per call).
The heap-Str realisation participates in standard RC (see
[memory model](memory-model.md)): the
+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)))
+9 -9
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))))
(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 Left 5)))
(app print (app std_either.either inc inc
(term-ctor std_either.Either Right 100))))))))))))
(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"))))))
+1 -1
View File
@@ -71,7 +71,7 @@ int ail_str_compare(const char *a, const char *b) {
* payload-8 payload (returned)
*
* Calls `ailang_rc_alloc(8 + len + 1)`. The +8 is the len field;
* the +1 is the trailing NUL byte that keeps `@strcmp` and `@puts`
* the +1 is the trailing NUL byte that keeps `@strcmp` and `@fputs`
* happy under the shared consumer ABI. Writes `len` into the first
* 8 bytes of the payload and returns the payload pointer; the
* caller is responsible for filling bytes [8 .. 8 + len) and the