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:
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
/// wired in hs.4 — exercises checker (signature install), codegen
|
||||||
/// (lower_app arm + IR-header declare + is_static_callee whitelist),
|
/// (lower_app arm + IR-header declare + is_static_callee whitelist),
|
||||||
/// runtime (str.c's `ailang_int_to_str` allocates a heap-Str slab,
|
/// 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
|
/// unconditional `runtime/rc.c` link (str.c's weak extern of
|
||||||
/// `ailang_rc_alloc` resolves to the strong rc.c definition under
|
/// `ailang_rc_alloc` resolves to the strong rc.c definition under
|
||||||
/// every alloc strategy after the hs.4 hoist).
|
/// every alloc strategy after the hs.4 hoist).
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
//! `ailang_rc_stats: allocs=1 frees=0 live=1`. The IR for the post-
|
//! `ailang_rc_stats: allocs=1 frees=0 live=1`. The IR for the post-
|
||||||
//! mono `ail_prelude_print__Int` body contains a `call ptr
|
//! mono `ail_prelude_print__Int` body contains a `call ptr
|
||||||
//! @ail_prelude_show__Int(...)` followed by `getelementptr +8` +
|
//! @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
|
//! show-result before return. Root cause sits at codegen's
|
||||||
//! `is_rc_heap_allocated` App-arm: it reads the callee's
|
//! `is_rc_heap_allocated` App-arm: it reads the callee's
|
||||||
//! `Type::Fn.ret_mode` via `synth_callee_ret_mode` and requires
|
//! `Type::Fn.ret_mode` via `synth_callee_ret_mode` and requires
|
||||||
|
|||||||
@@ -56,12 +56,15 @@ fn build_and_run(fixture: &str) -> String {
|
|||||||
#[test]
|
#[test]
|
||||||
fn print_primitives_smoke_runs_end_to_end() {
|
fn print_primitives_smoke_runs_end_to_end() {
|
||||||
let stdout = build_and_run("show_print_smoke.ail");
|
let stdout = build_and_run("show_print_smoke.ail");
|
||||||
// print 42 → "42\n" (int_to_str + puts)
|
// Post Gitea #29 (io/print_str → @fputs), the print path no
|
||||||
// print true → "true\n" (bool_to_str + puts)
|
// longer appends an implicit newline. The fixture now emits
|
||||||
// print "hello" → "hello\n" (str_clone + puts)
|
// each value with an explicit `(do io/print_str "\n")` after
|
||||||
// print 3.14 → "3.14\n" (float_to_str / libc %g + puts)
|
// the print, so the raw stdout is "42\ntrue\nhello\n3.14\n"
|
||||||
// puts emits each Str + a trailing newline; trimmed output is
|
// and `.trim()` lands at "42\ntrue\nhello\n3.14".
|
||||||
// "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:?}");
|
assert_eq!(stdout, "42\ntrue\nhello\n3.14", "got: {stdout:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
@.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 @printf(ptr, ...)
|
||||||
declare i32 @puts(ptr)
|
declare i32 @fputs(ptr, ptr)
|
||||||
|
@stdout = external global ptr
|
||||||
declare ptr @ailang_rc_alloc(i64)
|
declare ptr @ailang_rc_alloc(i64)
|
||||||
declare void @ailang_rc_inc(ptr)
|
declare void @ailang_rc_inc(ptr)
|
||||||
declare void @ailang_rc_dec(ptr)
|
declare void @ailang_rc_dec(ptr)
|
||||||
@@ -33,7 +34,8 @@ declare i64 @llvm.fptosi.sat.i64.f64(double)
|
|||||||
define i8 @ail_hello_main() {
|
define i8 @ail_hello_main() {
|
||||||
entry:
|
entry:
|
||||||
%v1 = getelementptr inbounds i8, ptr getelementptr inbounds (<{ i64, [15 x i8] }>, ptr @.str_hello_str_0, i32 0, i32 0), i64 8
|
%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
|
ret i8 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ source_filename = "list.ail"
|
|||||||
target triple = "<NORMALIZED>"
|
target triple = "<NORMALIZED>"
|
||||||
|
|
||||||
declare i32 @printf(ptr, ...)
|
declare i32 @printf(ptr, ...)
|
||||||
declare i32 @puts(ptr)
|
declare i32 @fputs(ptr, ptr)
|
||||||
|
@stdout = external global ptr
|
||||||
declare ptr @ailang_rc_alloc(i64)
|
declare ptr @ailang_rc_alloc(i64)
|
||||||
declare void @ailang_rc_inc(ptr)
|
declare void @ailang_rc_inc(ptr)
|
||||||
declare void @ailang_rc_dec(ptr)
|
declare void @ailang_rc_dec(ptr)
|
||||||
@@ -240,7 +241,8 @@ define i8 @ail_prelude_print__Int(i64 %arg_x) {
|
|||||||
entry:
|
entry:
|
||||||
%v1 = call ptr @ail_prelude_show__Int(i64 %arg_x)
|
%v1 = call ptr @ail_prelude_show__Int(i64 %arg_x)
|
||||||
%v2 = getelementptr inbounds i8, ptr %v1, i64 8
|
%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)
|
call void @ailang_rc_dec(ptr %v1)
|
||||||
ret i8 0
|
ret i8 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ source_filename = "max3.ail"
|
|||||||
target triple = "<NORMALIZED>"
|
target triple = "<NORMALIZED>"
|
||||||
|
|
||||||
declare i32 @printf(ptr, ...)
|
declare i32 @printf(ptr, ...)
|
||||||
declare i32 @puts(ptr)
|
declare i32 @fputs(ptr, ptr)
|
||||||
|
@stdout = external global ptr
|
||||||
declare ptr @ailang_rc_alloc(i64)
|
declare ptr @ailang_rc_alloc(i64)
|
||||||
declare void @ailang_rc_inc(ptr)
|
declare void @ailang_rc_inc(ptr)
|
||||||
declare void @ailang_rc_dec(ptr)
|
declare void @ailang_rc_dec(ptr)
|
||||||
@@ -228,7 +229,8 @@ define i8 @ail_prelude_print__Int(i64 %arg_x) {
|
|||||||
entry:
|
entry:
|
||||||
%v1 = call ptr @ail_prelude_show__Int(i64 %arg_x)
|
%v1 = call ptr @ail_prelude_show__Int(i64 %arg_x)
|
||||||
%v2 = getelementptr inbounds i8, ptr %v1, i64 8
|
%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)
|
call void @ailang_rc_dec(ptr %v1)
|
||||||
ret i8 0
|
ret i8 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ source_filename = "sum.ail"
|
|||||||
target triple = "<NORMALIZED>"
|
target triple = "<NORMALIZED>"
|
||||||
|
|
||||||
declare i32 @printf(ptr, ...)
|
declare i32 @printf(ptr, ...)
|
||||||
declare i32 @puts(ptr)
|
declare i32 @fputs(ptr, ptr)
|
||||||
|
@stdout = external global ptr
|
||||||
declare ptr @ailang_rc_alloc(i64)
|
declare ptr @ailang_rc_alloc(i64)
|
||||||
declare void @ailang_rc_inc(ptr)
|
declare void @ailang_rc_inc(ptr)
|
||||||
declare void @ailang_rc_dec(ptr)
|
declare void @ailang_rc_dec(ptr)
|
||||||
@@ -132,7 +133,8 @@ define i8 @ail_prelude_print__Int(i64 %arg_x) {
|
|||||||
entry:
|
entry:
|
||||||
%v1 = call ptr @ail_prelude_show__Int(i64 %arg_x)
|
%v1 = call ptr @ail_prelude_show__Int(i64 %arg_x)
|
||||||
%v2 = getelementptr inbounds i8, ptr %v1, i64 8
|
%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)
|
call void @ailang_rc_dec(ptr %v1)
|
||||||
ret i8 0
|
ret i8 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ source_filename = "ws_main.ail"
|
|||||||
target triple = "<NORMALIZED>"
|
target triple = "<NORMALIZED>"
|
||||||
|
|
||||||
declare i32 @printf(ptr, ...)
|
declare i32 @printf(ptr, ...)
|
||||||
declare i32 @puts(ptr)
|
declare i32 @fputs(ptr, ptr)
|
||||||
|
@stdout = external global ptr
|
||||||
declare ptr @ailang_rc_alloc(i64)
|
declare ptr @ailang_rc_alloc(i64)
|
||||||
declare void @ailang_rc_inc(ptr)
|
declare void @ailang_rc_inc(ptr)
|
||||||
declare void @ailang_rc_dec(ptr)
|
declare void @ailang_rc_dec(ptr)
|
||||||
@@ -119,7 +120,8 @@ define i8 @ail_prelude_print__Int(i64 %arg_x) {
|
|||||||
entry:
|
entry:
|
||||||
%v1 = call ptr @ail_prelude_show__Int(i64 %arg_x)
|
%v1 = call ptr @ail_prelude_show__Int(i64 %arg_x)
|
||||||
%v2 = getelementptr inbounds i8, ptr %v1, i64 8
|
%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)
|
call void @ailang_rc_dec(ptr %v1)
|
||||||
ret i8 0
|
ret i8 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 @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
|
// The allocator declaration name follows `alloc`. `Rc` declares
|
||||||
// `@ailang_rc_alloc` (canonical); `Bump` declares `@bump_malloc`
|
// `@ailang_rc_alloc` (canonical); `Bump` declares `@bump_malloc`
|
||||||
// (raw-alloc bench-floor), supplied by `runtime/bump.c`.
|
// (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)> {
|
fn lower_effect_op(&mut self, op: &str, args: &[Term], tail: bool) -> Result<(String, String)> {
|
||||||
// `musttail` requires identical caller/callee
|
// `musttail` requires identical caller/callee
|
||||||
// prototypes (same return type, same param types). The MVP's
|
// prototypes (same return type, same param types). The MVP's
|
||||||
// runtime print helpers (`printf`, `puts`) return `i32`, but the
|
// runtime print helpers (`printf`, `fputs`) return `i32`, but
|
||||||
// AILang fn enclosing a `tail-do io/print_*` returns `Unit`
|
// the AILang fn enclosing a `tail-do io/print_*` returns `Unit`
|
||||||
// (`i8`). `musttail` would be rejected by the LLVM verifier.
|
// (`i8`). `musttail` would be rejected by the LLVM verifier.
|
||||||
// We therefore use the `tail` keyword (LLVM IR optimisation
|
// We therefore use the `tail` keyword (LLVM IR optimisation
|
||||||
// hint, NOT a guarantee) for `tail: true` do-ops. The optimiser
|
// 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
|
// `Str` values now flow as a pointer to the
|
||||||
// `len`-field of the packed-struct slab; @puts needs
|
// `len`-field of the packed-struct slab; @fputs needs
|
||||||
// the bytes pointer 8 bytes further on.
|
// 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();
|
let bytes = self.fresh_ssa();
|
||||||
self.body.push_str(&format!(
|
self.body.push_str(&format!(
|
||||||
" {bytes} = getelementptr inbounds i8, ptr {v}, i64 8\n"
|
" {bytes} = getelementptr inbounds i8, ptr {v}, i64 8\n"
|
||||||
));
|
));
|
||||||
self.body
|
let fp = self.fresh_ssa();
|
||||||
.push_str(&format!(" {call_kw} i32 @puts(ptr {bytes})\n"));
|
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 {
|
if tail {
|
||||||
self.body.push_str(" ret i8 0\n");
|
self.body.push_str(" ret i8 0\n");
|
||||||
self.block_terminated = true;
|
self.block_terminated = true;
|
||||||
@@ -4299,10 +4316,14 @@ mod tests {
|
|||||||
|
|
||||||
/// after the layout migration, the `io/print_str`
|
/// after the layout migration, the `io/print_str`
|
||||||
/// path must `getelementptr i8` +8 onto the IR-Str pointer before
|
/// path must `getelementptr i8` +8 onto the IR-Str pointer before
|
||||||
/// passing it to `@puts`, so `@puts` receives the bytes pointer
|
/// passing it to `@fputs`, so `@fputs` receives the bytes pointer
|
||||||
/// (skipping the `len` field) and produces correct output.
|
/// (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]
|
#[test]
|
||||||
fn print_str_calls_puts_with_bytes_pointer() {
|
fn print_str_calls_fputs_with_bytes_pointer_and_stdout() {
|
||||||
let m = Module {
|
let m = Module {
|
||||||
schema: SCHEMA.into(),
|
schema: SCHEMA.into(),
|
||||||
name: "t".into(),
|
name: "t".into(),
|
||||||
@@ -4330,11 +4351,30 @@ mod tests {
|
|||||||
let ir = emit_ir(&m).unwrap();
|
let ir = emit_ir(&m).unwrap();
|
||||||
let body_idx = ir.find("define i8 @ail_t_main").expect("main body");
|
let body_idx = ir.find("define i8 @ail_t_main").expect("main body");
|
||||||
let body = &ir[body_idx..];
|
let body = &ir[body_idx..];
|
||||||
let puts_idx = body.find("@puts(").expect("@puts call present");
|
let fputs_idx = body.find("@fputs(").expect("@fputs call present");
|
||||||
let before_puts = &body[..puts_idx];
|
let before_fputs = &body[..fputs_idx];
|
||||||
assert!(
|
assert!(
|
||||||
before_puts.contains("getelementptr inbounds i8, ptr ") && before_puts.contains(", i64 8"),
|
before_fputs.contains("getelementptr inbounds i8, ptr ") && before_fputs.contains(", i64 8"),
|
||||||
"expected `getelementptr inbounds i8, ptr <v>, i64 8` before @puts call; ir body was:\n{body}"
|
"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}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -245,14 +245,17 @@ 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();
|
||||||
// The hash reflects a corpus migration: `ordering_match.ail`'s
|
// The hash reflects two successive corpus migrations:
|
||||||
// body moved from `(do io/print_int x)` to `(app print x)` when
|
// (1) the per-type-print-retirement that moved the body from
|
||||||
// the per-type print effect-ops were retired in favour of the
|
// `(do io/print_int x)` to `(app print x)`;
|
||||||
// polymorphic `print` helper.
|
// (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!(
|
assert_eq!(
|
||||||
def_hash(main_def),
|
def_hash(main_def),
|
||||||
"b65a7f834703ffb4",
|
"8ed47b4062ce00f5",
|
||||||
"ordering_match::main canonical hash must match captured post-per-type-print-retirement value"
|
"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"))
|
let dup_a_mod = ailang_surface::load_module(&examples.join("test_22b1_dup_a.ail"))
|
||||||
|
|||||||
@@ -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] }>` |
|
| 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)` |
|
| 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
|
`@ail_str_compare`) GEPs `+8` from the Str pointer to reach the
|
||||||
bytes, regardless of realisation. The byte-comparison semantics
|
bytes, regardless of realisation. The byte-comparison semantics
|
||||||
are inherited from libc `strcmp` — locale-independent, NUL-
|
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
|
The heap-Str realisation participates in standard RC (see
|
||||||
[memory model](memory-model.md)): the
|
[memory model](memory-model.md)): the
|
||||||
|
|||||||
@@ -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.")
|
(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)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(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"))))))
|
||||||
|
|||||||
@@ -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).")
|
(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)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(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"))))))
|
||||||
|
|||||||
@@ -60,5 +60,5 @@
|
|||||||
(term-ctor List Cons 3
|
(term-ctor List Cons 3
|
||||||
(term-ctor List Nil))))
|
(term-ctor List Nil))))
|
||||||
(seq
|
(seq
|
||||||
(app print (app list_length xs))
|
(seq (app print (app list_length xs)) (do io/print_str "\n"))
|
||||||
(app print (app sum_list xs)))))))
|
(seq (app print (app sum_list xs)) (do io/print_str "\n")))))))
|
||||||
|
|||||||
@@ -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 (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 LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(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 LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(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 LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(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 LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(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 LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(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 LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(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 LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(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 LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(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 LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(case (pat-ctor EQ) 2)
|
||||||
(case (pat-ctor GT) 3))))))))))))))
|
(case (pat-ctor GT) 3))) (do io/print_str "\n")))))))))))))
|
||||||
|
|||||||
+10
-10
@@ -47,13 +47,13 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (app print (app eq 5 5))
|
(seq (seq (app print (app eq 5 5)) (do io/print_str "\n"))
|
||||||
(seq (app print (app eq 5 6))
|
(seq (seq (app print (app eq 5 6)) (do io/print_str "\n"))
|
||||||
(seq (app print (app eq true false))
|
(seq (seq (app print (app eq true false)) (do io/print_str "\n"))
|
||||||
(seq (app print (app eq true true))
|
(seq (seq (app print (app eq true true)) (do io/print_str "\n"))
|
||||||
(seq (app print (app eq "hi" "hi"))
|
(seq (seq (app print (app eq "hi" "hi")) (do io/print_str "\n"))
|
||||||
(seq (app print (app eq "hi" "ho"))
|
(seq (seq (app print (app eq "hi" "ho")) (do io/print_str "\n"))
|
||||||
(seq (app print (app eq (lit-unit) (lit-unit)))
|
(seq (seq (app print (app eq (lit-unit) (lit-unit))) (do io/print_str "\n"))
|
||||||
(seq (app print (app classify_str "hi"))
|
(seq (seq (app print (app classify_str "hi")) (do io/print_str "\n"))
|
||||||
(seq (app print (app classify_str "ho"))
|
(seq (seq (app print (app classify_str "ho")) (do io/print_str "\n"))
|
||||||
(app print (app classify_str "??"))))))))))))))
|
(seq (app print (app classify_str "??")) (do io/print_str "\n"))))))))))))))
|
||||||
|
|||||||
@@ -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 (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")))))))
|
||||||
|
|||||||
@@ -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 (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"))))))
|
||||||
|
|||||||
@@ -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 (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"))))))))))
|
||||||
|
|||||||
@@ -23,6 +23,6 @@
|
|||||||
(let p1 (term-ctor Point Point 1 2)
|
(let p1 (term-ctor Point Point 1 2)
|
||||||
(let p2 (term-ctor Point Point 1 2)
|
(let p2 (term-ctor Point Point 1 2)
|
||||||
(let p3 (term-ctor Point Point 1 3)
|
(let p3 (term-ctor Point Point 1 3)
|
||||||
(seq (app print (app eq (lit-unit) (lit-unit)))
|
(seq (seq (app print (app eq (lit-unit) (lit-unit))) (do io/print_str "\n"))
|
||||||
(seq (app print (app eq p1 p2))
|
(seq (seq (app print (app eq p1 p2)) (do io/print_str "\n"))
|
||||||
(app print (app eq p1 p3))))))))))
|
(seq (app print (app eq p1 p3)) (do io/print_str "\n"))))))))))
|
||||||
|
|||||||
@@ -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 (app print (app peek 0))
|
(seq (seq (app print (app peek 0)) (do io/print_str "\n"))
|
||||||
(seq (app print (app peek 123))
|
(seq (seq (app print (app peek 123)) (do io/print_str "\n"))
|
||||||
(seq (app print (app count 5))
|
(seq (seq (app print (app count 5)) (do io/print_str "\n"))
|
||||||
(app print (app count 0))))))))
|
(seq (app print (app count 0)) (do io/print_str "\n"))))))))
|
||||||
|
|||||||
@@ -4,6 +4,6 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (app print (app float_eq 1.5 1.5))
|
(seq (seq (app print (app float_eq 1.5 1.5)) (do io/print_str "\n"))
|
||||||
(seq (app print (app float_lt 1.0 2.0))
|
(seq (seq (app print (app float_lt 1.0 2.0)) (do io/print_str "\n"))
|
||||||
(app print (app float_eq 1.0 0.0)))))))
|
(seq (app print (app float_eq 1.0 0.0)) (do io/print_str "\n")))))))
|
||||||
|
|||||||
@@ -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.")
|
(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)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(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
@@ -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 (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")))))))
|
||||||
|
|||||||
@@ -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).")
|
(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)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(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")))))))
|
||||||
|
|||||||
@@ -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).")
|
(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 (app print n)))))
|
(body (let n 7 (seq (app print n) (do io/print_str "\n"))))))
|
||||||
|
|||||||
@@ -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.")
|
(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)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(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"))))))
|
||||||
|
|||||||
@@ -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.")
|
(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)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(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")))))
|
||||||
|
|||||||
@@ -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 (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
|
(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
|
||||||
(app print h)
|
(seq (app print h) (do io/print_str "\n"))
|
||||||
(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 (app print (app classify 0))
|
(seq (seq (app print (app classify 0)) (do io/print_str "\n"))
|
||||||
(seq (app print (app classify 1))
|
(seq (seq (app print (app classify 1)) (do io/print_str "\n"))
|
||||||
(seq (app print (app classify 17))
|
(seq (seq (app print (app classify 17)) (do io/print_str "\n"))
|
||||||
(seq (app print (app categorize_first (term-ctor IntList Nil)))
|
(seq (seq (app print (app categorize_first (term-ctor IntList Nil))) (do io/print_str "\n"))
|
||||||
(seq (app print (app categorize_first (term-ctor IntList Cons 0 (term-ctor IntList Nil))))
|
(seq (seq (app print (app categorize_first (term-ctor IntList Cons 0 (term-ctor IntList Nil)))) (do io/print_str "\n"))
|
||||||
(app print (app categorize_first (term-ctor IntList Cons 7 (term-ctor IntList Nil))))))))))))
|
(seq (app print (app categorize_first (term-ctor IntList Cons 7 (term-ctor IntList Nil)))) (do io/print_str "\n"))))))))))
|
||||||
|
|||||||
@@ -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 (app print (app run_with_base 10))
|
(seq (seq (app print (app run_with_base 10)) (do io/print_str "\n"))
|
||||||
(app print (app run_with_base 100))))))
|
(seq (app print (app run_with_base 100)) (do io/print_str "\n"))))))
|
||||||
|
|||||||
@@ -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 (app print (app sum_below 1))
|
(seq (seq (app print (app sum_below 1)) (do io/print_str "\n"))
|
||||||
(seq (app print (app sum_below 5))
|
(seq (seq (app print (app sum_below 5)) (do io/print_str "\n"))
|
||||||
(app print (app sum_below 10)))))))
|
(seq (app print (app sum_below 10)) (do io/print_str "\n")))))))
|
||||||
|
|||||||
@@ -21,6 +21,6 @@
|
|||||||
1
|
1
|
||||||
(app * n (app fact (app - n 1)))))
|
(app * n (app fact (app - n 1)))))
|
||||||
(in
|
(in
|
||||||
(seq (app print (app fact 1))
|
(seq (seq (app print (app fact 1)) (do io/print_str "\n"))
|
||||||
(seq (app print (app fact 3))
|
(seq (seq (app print (app fact 3)) (do io/print_str "\n"))
|
||||||
(app print (app fact 5)))))))))
|
(seq (app print (app fact 5)) (do io/print_str "\n")))))))))
|
||||||
|
|||||||
@@ -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 (app print (app count_below 0))
|
(seq (seq (app print (app count_below 0)) (do io/print_str "\n"))
|
||||||
(seq (app print (app count_below 5))
|
(seq (seq (app print (app count_below 5)) (do io/print_str "\n"))
|
||||||
(app print (app count_below 15)))))))
|
(seq (app print (app count_below 15)) (do io/print_str "\n")))))))
|
||||||
|
|||||||
@@ -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 (app print (app count_below (term-ctor Pair MkPair 10 0)))
|
(seq (seq (app print (app count_below (term-ctor Pair MkPair 10 0))) (do io/print_str "\n"))
|
||||||
(seq (app print (app count_below (term-ctor Pair MkPair 10 5)))
|
(seq (seq (app print (app count_below (term-ctor Pair MkPair 10 5))) (do io/print_str "\n"))
|
||||||
(app print (app count_below (term-ctor Pair MkPair 10 15))))))))
|
(seq (app print (app count_below (term-ctor Pair MkPair 10 15))) (do io/print_str "\n")))))))
|
||||||
|
|||||||
@@ -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 (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"))))))
|
||||||
|
|||||||
@@ -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 (app print (app nested_sum 1))
|
(seq (seq (app print (app nested_sum 1)) (do io/print_str "\n"))
|
||||||
(seq (app print (app nested_sum 3))
|
(seq (seq (app print (app nested_sum 3)) (do io/print_str "\n"))
|
||||||
(app print (app nested_sum 5)))))))
|
(seq (app print (app nested_sum 5)) (do io/print_str "\n")))))))
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
(doc "Nullary user function — no params, prints a fixed line.")
|
(doc "Nullary user function — no params, prints a fixed line.")
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (do io/print_str "hello")))
|
(body (seq (do io/print_str "hello") (do io/print_str "\n"))))
|
||||||
|
|
||||||
(fn main
|
(fn main
|
||||||
(doc "Calls the nullary `greet` as `(app greet)` — the zero-arg surface form accepted under Gitea #12.")
|
(doc "Calls the nullary `greet` as `(app greet)` — the zero-arg surface form accepted under Gitea #12.")
|
||||||
|
|||||||
@@ -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 (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 LT) 1)
|
||||||
(case (pat-ctor EQ) 2)
|
(case (pat-ctor EQ) 2)
|
||||||
(case (pat-ctor GT) 3))))))
|
(case (pat-ctor GT) 3))) (do io/print_str "\n")))))
|
||||||
|
|||||||
@@ -7,5 +7,6 @@ fn main() -> Unit with IO {
|
|||||||
LT => 1,
|
LT => 1,
|
||||||
EQ => 2,
|
EQ => 2,
|
||||||
GT => 3
|
GT => 3
|
||||||
})
|
});
|
||||||
|
do io/print_str("\n")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 (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"))))))
|
||||||
|
|||||||
@@ -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 (app print (app apply_n_times 5 0 succ))
|
(seq (seq (app print (app apply_n_times 5 0 succ)) (do io/print_str "\n"))
|
||||||
(app print (app apply_n_times 4 false flip))))))
|
(seq (app print (app apply_n_times 4 false flip)) (do io/print_str "\n"))))))
|
||||||
|
|||||||
@@ -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.")
|
(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)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body (app print 2.0))))
|
(body (seq (app print 2.0) (do io/print_str "\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 (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)))))
|
||||||
|
|||||||
@@ -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 (app print (term-ctor Item MkItem 42)))))
|
(body (seq (app print (term-ctor Item MkItem 42)) (do io/print_str "\n")))))
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,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 (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
|
(fn main
|
||||||
(doc "Sort and print [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5].")
|
(doc "Sort and print [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5].")
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
|
|||||||
@@ -18,14 +18,14 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (app print (app std_either.from_right 0 (term-ctor std_either.Either Right 42)))
|
(seq (seq (app print (app std_either.from_right 0 (term-ctor std_either.Either Right 42))) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_either.from_right 99 (term-ctor std_either.Either Left 7)))
|
(seq (seq (app print (app std_either.from_right 99 (term-ctor std_either.Either Left 7))) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_either.is_left (term-ctor std_either.Either Left 7)))
|
(seq (seq (app print (app std_either.is_left (term-ctor std_either.Either Left 7))) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_either.is_right (term-ctor std_either.Either Right 42)))
|
(seq (seq (app print (app std_either.is_right (term-ctor std_either.Either Right 42))) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_either.from_right 0
|
(seq (seq (app print (app std_either.from_right 0
|
||||||
(app std_either.map_right inc
|
(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 (app print (app std_either.either inc inc
|
(seq (seq (app print (app std_either.either inc inc
|
||||||
(term-ctor std_either.Either Left 5)))
|
(term-ctor std_either.Either Left 5))) (do io/print_str "\n"))
|
||||||
(app print (app std_either.either inc inc
|
(seq (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")))))))))))
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(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 (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 (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 (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 (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))))))))))
|
(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"))
|
||||||
(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 (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
@@ -48,14 +48,14 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (app print (app std_list.length xs))
|
(seq (seq (app print (app std_list.length xs)) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_list.is_empty xs))
|
(seq (seq (app print (app std_list.is_empty xs)) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_list.is_empty (term-ctor std_list.List Nil)))
|
(seq (seq (app print (app std_list.is_empty (term-ctor std_list.List Nil))) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_maybe.from_maybe -1 (app std_list.head xs)))
|
(seq (seq (app print (app std_maybe.from_maybe -1 (app std_list.head xs))) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_list.length (app std_maybe.from_maybe xs (app std_list.tail xs))))
|
(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 (app print (app std_list.length (app std_list.append xs xs)))
|
(seq (seq (app print (app std_list.length (app std_list.append xs xs))) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_maybe.from_maybe -1 (app std_list.head (app std_list.reverse xs))))
|
(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 (app print (app std_maybe.from_maybe -1 (app std_list.head (app std_list.map double xs))))
|
(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 (app print (app std_list.length (app std_list.filter is_even xs)))
|
(seq (seq (app print (app std_list.length (app std_list.filter is_even xs))) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_list.fold_left add 0 xs))
|
(seq (seq (app print (app std_list.fold_left add 0 xs)) (do io/print_str "\n"))
|
||||||
(app print (app std_list.fold_right add 0 xs)))))))))))))))
|
(seq (app print (app std_list.fold_right add 0 xs)) (do io/print_str "\n")))))))))))))))
|
||||||
|
|||||||
@@ -24,9 +24,9 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (app print (app std_list.length (app std_list.take 0 xs)))
|
(seq (seq (app print (app std_list.length (app std_list.take 0 xs))) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_list.length (app std_list.take 3 xs)))
|
(seq (seq (app print (app std_list.length (app std_list.take 3 xs))) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_list.length (app std_list.take 100 xs)))
|
(seq (seq (app print (app std_list.length (app std_list.take 100 xs))) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_list.length (app std_list.drop 0 xs)))
|
(seq (seq (app print (app std_list.length (app std_list.drop 0 xs))) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_list.length (app std_list.drop 2 xs)))
|
(seq (seq (app print (app std_list.length (app std_list.drop 2 xs))) (do io/print_str "\n"))
|
||||||
(app print (app std_list.length (app std_list.drop 100 xs)))))))))))
|
(seq (app print (app std_list.length (app std_list.drop 100 xs))) (do io/print_str "\n"))))))))))
|
||||||
|
|||||||
@@ -37,5 +37,5 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (app print (app std_list.fold_left add 0 (app build 1000)))
|
(seq (seq (app print (app std_list.fold_left add 0 (app build 1000))) (do io/print_str "\n"))
|
||||||
(app print (app std_list.fold_right add 0 (app build 1000)))))))
|
(seq (app print (app std_list.fold_right add 0 (app build 1000))) (do io/print_str "\n"))))))
|
||||||
|
|||||||
@@ -23,8 +23,8 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (app print (app std_maybe.from_maybe 99 (term-ctor std_maybe.Maybe Just 7)))
|
(seq (seq (app print (app std_maybe.from_maybe 99 (term-ctor std_maybe.Maybe Just 7))) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_maybe.from_maybe 99 (term-ctor std_maybe.Maybe Nothing)))
|
(seq (seq (app print (app std_maybe.from_maybe 99 (term-ctor std_maybe.Maybe Nothing))) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_maybe.is_some (term-ctor std_maybe.Maybe Just 5)))
|
(seq (seq (app print (app std_maybe.is_some (term-ctor std_maybe.Maybe Just 5))) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_maybe.is_none (term-ctor std_maybe.Maybe Nothing)))
|
(seq (seq (app print (app std_maybe.is_none (term-ctor std_maybe.Maybe Nothing))) (do io/print_str "\n"))
|
||||||
(app print (app std_maybe.from_maybe 0 (app std_maybe.map_maybe inc (term-ctor std_maybe.Maybe Just 41)))))))))))
|
(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")))))))))
|
||||||
|
|||||||
@@ -24,9 +24,9 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (app print (app std_pair.fst (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 (app print (app std_pair.snd (term-ctor std_pair.Pair MkPair 7 9)))
|
(seq (seq (app print (app std_pair.snd (term-ctor std_pair.Pair MkPair 7 9))) (do io/print_str "\n"))
|
||||||
(seq (app print (app std_pair.fst (app std_pair.swap (term-ctor std_pair.Pair MkPair 7 9))))
|
(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 (app print (app std_pair.snd (app std_pair.swap (term-ctor std_pair.Pair MkPair 7 9))))
|
(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 (app print (app std_pair.fst (app std_pair.map_first inc (term-ctor std_pair.Pair MkPair 7 9))))
|
(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"))
|
||||||
(app print (app std_pair.snd (app std_pair.map_second double (term-ctor std_pair.Pair MkPair 7 9))))))))))))
|
(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"))))))))))
|
||||||
|
|||||||
@@ -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.")
|
(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)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(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")))))))))
|
||||||
|
|||||||
@@ -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.")
|
(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)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(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"))))))
|
||||||
|
|||||||
@@ -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 Boxed Box (app int_to_str 42)) (match b
|
(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
|
(fn main
|
||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(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"))))))
|
||||||
|
|||||||
@@ -31,5 +31,5 @@
|
|||||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||||
(params)
|
(params)
|
||||||
(body
|
(body
|
||||||
(seq (app print (app safe_div 8 2))
|
(seq (seq (app print (app safe_div 8 2)) (do io/print_str "\n"))
|
||||||
(app print (app safe_div 15 3))))))
|
(seq (app print (app safe_div 15 3)) (do io/print_str "\n"))))))
|
||||||
|
|||||||
+1
-1
@@ -71,7 +71,7 @@ int ail_str_compare(const char *a, const char *b) {
|
|||||||
* payload-8 payload (returned)
|
* payload-8 payload (returned)
|
||||||
*
|
*
|
||||||
* Calls `ailang_rc_alloc(8 + len + 1)`. The +8 is the len field;
|
* 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
|
* happy under the shared consumer ABI. Writes `len` into the first
|
||||||
* 8 bytes of the payload and returns the payload pointer; the
|
* 8 bytes of the payload and returns the payload pointer; the
|
||||||
* caller is responsible for filling bytes [8 .. 8 + len) and the
|
* caller is responsible for filling bytes [8 .. 8 + len) and the
|
||||||
|
|||||||
Reference in New Issue
Block a user