feat(series): ship the kernel-tier Series library extension (#61)
Series a is a bounded ring buffer with financial-style indexing (index 0 = newest), shipped as a PURE AILang library extension over RawBuf — zero Rust codegen, zero intercepts, zero (intrinsic) markers. It is the first kernel-tier module that depends on another kernel-tier module (raw_buf). This turns the committed SMA headline pin (6b7ee45) green and closes the step-1 scope of #61. The module lives at crates/ailang-kernel/src/series/{source.ail, mod.rs} and is auto-injected by the loader exactly like raw_buf (parse_series + injection in ailang-surface/src/loader.rs, re-export in lib.rs). Five real-bodied ops: new / push / at / len / total_count, all built on RawBuf.{new,set,get}. The source is the model-0007 sketch with every defect corrected and each correction verified against the live tool: - param-in narrowed to (a Int Float); Bool deferred per #61. - inner alloc is `(new RawBuf lookback)` with no element type-arg — the element is solved from the `(con RawBuf a)` ctor-field context, which the base-tier mono fix (b11a6d9) carries through to the caller's concrete type. This is the capability that lets Series be pure AILang. - element-typed params/rets are bare `a`, not `(con a)` (a type variable, not a nullary ctor). - op signatures bind `a` via `(forall (vars a) ...)`. - comparison uses the named helper `lt`, not the non-existent `<`. - the at-index formula is `(head - 1 - i + 2*lookback) mod lookback` (0007 had the sign on i wrong, walking the wrong direction). Cross-kernel-module visibility — the flagged risk — needed ZERO mechanism change: the loader derives its implicit-import set from every kernel module, so series's body resolves `RawBuf.*` and `(con RawBuf a)` via the existing kernel auto-visibility. Both CLAUDE.md lockstep pairs stay intact: - INTERCEPTS <-> (intrinsic) markers: unchanged. Series is pure-AILang, adds neither; intercepts_bijection_with_intrinsic_ markers still green. - Term::New typecheck/reject <-> pre_desugar_validation.rs: untouched; the new/Series construction exercises existing paths. Test-surface ripple, all verified: - workspace module-count pins 4 -> 5 (e2e.rs, workspace_pin.rs), with a `series` membership assertion added — the kernel set grew by one deliberate module. - two mono-identity tests (typeclass_22b3.rs) now skip `prelude` and `series`: series is the first auto-imported real-bodied consumer of the prelude polyfns `lt`/`compare` over Int, so mono legitimately materialises `lt__Int`/`compare__Int` into prelude for every workspace. That is a concrete call site, not gratuitous mutation; the tests' real invariant (mono leaves work-free modules untouched) still holds for every other module. - five IR snapshots refreshed; the deltas are strictly additive (zero IR deletions) — the same series-driven Int specialisations. Verified: full `cargo test --workspace` green; SMA binary built via `ail build --alloc=rc` prints `3.0 / 5.33333 / 5.66667 / 5.33333`. refs #61
This commit is contained in:
@@ -942,10 +942,10 @@ fn workspace_lists_imported_modules() {
|
|||||||
|
|
||||||
let modules = v["modules"].as_array().expect("modules must be array");
|
let modules = v["modules"].as_array().expect("modules must be array");
|
||||||
// the loader auto-injects every built-in kernel-tier module
|
// the loader auto-injects every built-in kernel-tier module
|
||||||
// (`prelude` and, since raw-buf.4, the first real-payload kernel
|
// (`prelude`; `raw_buf` since raw-buf.4; and `series`, the first pure
|
||||||
// extension `raw_buf`), so the count is the user's two modules plus
|
// AILang library extension, since feat-series-step1), so the count is
|
||||||
// the two built-ins.
|
// the user's two modules plus the three built-ins.
|
||||||
assert_eq!(modules.len(), 4, "expected 4 modules: {stdout}");
|
assert_eq!(modules.len(), 5, "expected 5 modules: {stdout}");
|
||||||
|
|
||||||
let names: Vec<&str> = modules
|
let names: Vec<&str> = modules
|
||||||
.iter()
|
.iter()
|
||||||
@@ -955,6 +955,7 @@ fn workspace_lists_imported_modules() {
|
|||||||
assert!(names.contains(&"ws_lib"), "ws_lib missing: {names:?}");
|
assert!(names.contains(&"ws_lib"), "ws_lib missing: {names:?}");
|
||||||
assert!(names.contains(&"prelude"), "prelude missing: {names:?}");
|
assert!(names.contains(&"prelude"), "prelude missing: {names:?}");
|
||||||
assert!(names.contains(&"raw_buf"), "raw_buf missing: {names:?}");
|
assert!(names.contains(&"raw_buf"), "raw_buf missing: {names:?}");
|
||||||
|
assert!(names.contains(&"series"), "series missing: {names:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Guards Iter 5b: `ail check examples/ws_main.ail.json --json` must
|
/// Guards Iter 5b: `ail check examples/ws_main.ail.json --json` must
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ declare i64 @llvm.fptosi.sat.i64.f64(double)
|
|||||||
@ail_prelude_float_le_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_le_adapter, ptr null }
|
@ail_prelude_float_le_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_le_adapter, ptr null }
|
||||||
@ail_prelude_float_gt_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_gt_adapter, ptr null }
|
@ail_prelude_float_gt_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_gt_adapter, ptr null }
|
||||||
@ail_prelude_float_ge_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_ge_adapter, ptr null }
|
@ail_prelude_float_ge_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_ge_adapter, ptr null }
|
||||||
|
@ail_prelude_compare__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_compare__Int_adapter, ptr null }
|
||||||
|
@ail_prelude_lt__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_lt__Int_adapter, ptr null }
|
||||||
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
|
||||||
@@ -117,6 +119,45 @@ entry:
|
|||||||
ret i1 %r
|
ret i1 %r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define ptr @ail_prelude_compare__Int(i64 %arg_x, i64 %arg_y) alwaysinline {
|
||||||
|
entry:
|
||||||
|
%v1 = icmp slt i64 %arg_x, %arg_y
|
||||||
|
br i1 %v1, label %cmp_lt_2, label %cmp_after_lt_2
|
||||||
|
cmp_lt_2:
|
||||||
|
%v3 = call ptr @ailang_rc_alloc(i64 8)
|
||||||
|
store i64 0, ptr %v3, align 8
|
||||||
|
ret ptr %v3
|
||||||
|
cmp_after_lt_2:
|
||||||
|
%v4 = icmp eq i64 %arg_x, %arg_y
|
||||||
|
br i1 %v4, label %cmp_eq_2, label %cmp_gt_2
|
||||||
|
cmp_eq_2:
|
||||||
|
%v5 = call ptr @ailang_rc_alloc(i64 8)
|
||||||
|
store i64 1, ptr %v5, align 8
|
||||||
|
ret ptr %v5
|
||||||
|
cmp_gt_2:
|
||||||
|
%v6 = call ptr @ailang_rc_alloc(i64 8)
|
||||||
|
store i64 2, ptr %v6, align 8
|
||||||
|
ret ptr %v6
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @ail_prelude_compare__Int_adapter(ptr %_env, i64 %a0, i64 %a1) {
|
||||||
|
entry:
|
||||||
|
%r = call ptr @ail_prelude_compare__Int(i64 %a0, i64 %a1)
|
||||||
|
ret ptr %r
|
||||||
|
}
|
||||||
|
|
||||||
|
define i1 @ail_prelude_lt__Int(i64 %arg_x, i64 %arg_y) alwaysinline {
|
||||||
|
entry:
|
||||||
|
%v1 = icmp slt i64 %arg_x, %arg_y
|
||||||
|
ret i1 %v1
|
||||||
|
}
|
||||||
|
|
||||||
|
define i1 @ail_prelude_lt__Int_adapter(ptr %_env, i64 %a0, i64 %a1) {
|
||||||
|
entry:
|
||||||
|
%r = call i1 @ail_prelude_lt__Int(i64 %a0, i64 %a1)
|
||||||
|
ret i1 %r
|
||||||
|
}
|
||||||
|
|
||||||
define void @drop_prelude_Ordering(ptr %p) {
|
define void @drop_prelude_Ordering(ptr %p) {
|
||||||
entry:
|
entry:
|
||||||
%is_null = icmp eq ptr %p, null
|
%is_null = icmp eq ptr %p, null
|
||||||
@@ -191,6 +232,58 @@ ret:
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define void @drop_series_Series__6ddcf58f(ptr %p) {
|
||||||
|
entry:
|
||||||
|
%is_null = icmp eq ptr %p, null
|
||||||
|
br i1 %is_null, label %ret, label %live
|
||||||
|
live:
|
||||||
|
%tag = load i64, ptr %p, align 8
|
||||||
|
switch i64 %tag, label %dflt [
|
||||||
|
i64 0, label %arm_0
|
||||||
|
]
|
||||||
|
arm_0:
|
||||||
|
%a0 = getelementptr inbounds i8, ptr %p, i64 8
|
||||||
|
%v1 = load ptr, ptr %a0, align 8
|
||||||
|
call void @drop_raw_buf_RawBuf(ptr %v1)
|
||||||
|
br label %join
|
||||||
|
dflt:
|
||||||
|
unreachable
|
||||||
|
join:
|
||||||
|
call void @ailang_rc_dec(ptr %p)
|
||||||
|
br label %ret
|
||||||
|
ret:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @partial_drop_series_Series__6ddcf58f(ptr %p, i64 %mask) {
|
||||||
|
entry:
|
||||||
|
%is_null = icmp eq ptr %p, null
|
||||||
|
br i1 %is_null, label %ret, label %live
|
||||||
|
live:
|
||||||
|
%tag = load i64, ptr %p, align 8
|
||||||
|
switch i64 %tag, label %dflt [
|
||||||
|
i64 0, label %arm_0
|
||||||
|
]
|
||||||
|
arm_0:
|
||||||
|
%b0 = and i64 %mask, 1
|
||||||
|
%s1 = icmp ne i64 %b0, 0
|
||||||
|
br i1 %s1, label %after_0_0, label %do_0_0
|
||||||
|
do_0_0:
|
||||||
|
%a2 = getelementptr inbounds i8, ptr %p, i64 8
|
||||||
|
%v3 = load ptr, ptr %a2, align 8
|
||||||
|
call void @drop_raw_buf_RawBuf(ptr %v3)
|
||||||
|
br label %after_0_0
|
||||||
|
after_0_0:
|
||||||
|
br label %join
|
||||||
|
dflt:
|
||||||
|
unreachable
|
||||||
|
join:
|
||||||
|
call void @ailang_rc_dec(ptr %p)
|
||||||
|
br label %ret
|
||||||
|
ret:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
define i32 @main() {
|
define i32 @main() {
|
||||||
call i8 @ail_hello_main()
|
call i8 @ail_hello_main()
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ declare i64 @llvm.fptosi.sat.i64.f64(double)
|
|||||||
@ail_prelude_float_ge_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_ge_adapter, ptr null }
|
@ail_prelude_float_ge_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_ge_adapter, ptr null }
|
||||||
@ail_prelude_show__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_show__Int_adapter, ptr null }
|
@ail_prelude_show__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_show__Int_adapter, ptr null }
|
||||||
@ail_prelude_print__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_print__Int_adapter, ptr null }
|
@ail_prelude_print__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_print__Int_adapter, ptr null }
|
||||||
|
@ail_prelude_compare__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_compare__Int_adapter, ptr null }
|
||||||
|
@ail_prelude_lt__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_lt__Int_adapter, ptr null }
|
||||||
define i64 @ail_list_sum_list(ptr %arg_xs) {
|
define i64 @ail_list_sum_list(ptr %arg_xs) {
|
||||||
entry:
|
entry:
|
||||||
%v1 = load i64, ptr %arg_xs, align 8
|
%v1 = load i64, ptr %arg_xs, align 8
|
||||||
@@ -254,6 +256,45 @@ entry:
|
|||||||
ret i8 %r
|
ret i8 %r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define ptr @ail_prelude_compare__Int(i64 %arg_x, i64 %arg_y) alwaysinline {
|
||||||
|
entry:
|
||||||
|
%v1 = icmp slt i64 %arg_x, %arg_y
|
||||||
|
br i1 %v1, label %cmp_lt_2, label %cmp_after_lt_2
|
||||||
|
cmp_lt_2:
|
||||||
|
%v3 = call ptr @ailang_rc_alloc(i64 8)
|
||||||
|
store i64 0, ptr %v3, align 8
|
||||||
|
ret ptr %v3
|
||||||
|
cmp_after_lt_2:
|
||||||
|
%v4 = icmp eq i64 %arg_x, %arg_y
|
||||||
|
br i1 %v4, label %cmp_eq_2, label %cmp_gt_2
|
||||||
|
cmp_eq_2:
|
||||||
|
%v5 = call ptr @ailang_rc_alloc(i64 8)
|
||||||
|
store i64 1, ptr %v5, align 8
|
||||||
|
ret ptr %v5
|
||||||
|
cmp_gt_2:
|
||||||
|
%v6 = call ptr @ailang_rc_alloc(i64 8)
|
||||||
|
store i64 2, ptr %v6, align 8
|
||||||
|
ret ptr %v6
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @ail_prelude_compare__Int_adapter(ptr %_env, i64 %a0, i64 %a1) {
|
||||||
|
entry:
|
||||||
|
%r = call ptr @ail_prelude_compare__Int(i64 %a0, i64 %a1)
|
||||||
|
ret ptr %r
|
||||||
|
}
|
||||||
|
|
||||||
|
define i1 @ail_prelude_lt__Int(i64 %arg_x, i64 %arg_y) alwaysinline {
|
||||||
|
entry:
|
||||||
|
%v1 = icmp slt i64 %arg_x, %arg_y
|
||||||
|
ret i1 %v1
|
||||||
|
}
|
||||||
|
|
||||||
|
define i1 @ail_prelude_lt__Int_adapter(ptr %_env, i64 %a0, i64 %a1) {
|
||||||
|
entry:
|
||||||
|
%r = call i1 @ail_prelude_lt__Int(i64 %a0, i64 %a1)
|
||||||
|
ret i1 %r
|
||||||
|
}
|
||||||
|
|
||||||
define void @drop_prelude_Ordering(ptr %p) {
|
define void @drop_prelude_Ordering(ptr %p) {
|
||||||
entry:
|
entry:
|
||||||
%is_null = icmp eq ptr %p, null
|
%is_null = icmp eq ptr %p, null
|
||||||
@@ -328,6 +369,58 @@ ret:
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define void @drop_series_Series__6ddcf58f(ptr %p) {
|
||||||
|
entry:
|
||||||
|
%is_null = icmp eq ptr %p, null
|
||||||
|
br i1 %is_null, label %ret, label %live
|
||||||
|
live:
|
||||||
|
%tag = load i64, ptr %p, align 8
|
||||||
|
switch i64 %tag, label %dflt [
|
||||||
|
i64 0, label %arm_0
|
||||||
|
]
|
||||||
|
arm_0:
|
||||||
|
%a0 = getelementptr inbounds i8, ptr %p, i64 8
|
||||||
|
%v1 = load ptr, ptr %a0, align 8
|
||||||
|
call void @drop_raw_buf_RawBuf(ptr %v1)
|
||||||
|
br label %join
|
||||||
|
dflt:
|
||||||
|
unreachable
|
||||||
|
join:
|
||||||
|
call void @ailang_rc_dec(ptr %p)
|
||||||
|
br label %ret
|
||||||
|
ret:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @partial_drop_series_Series__6ddcf58f(ptr %p, i64 %mask) {
|
||||||
|
entry:
|
||||||
|
%is_null = icmp eq ptr %p, null
|
||||||
|
br i1 %is_null, label %ret, label %live
|
||||||
|
live:
|
||||||
|
%tag = load i64, ptr %p, align 8
|
||||||
|
switch i64 %tag, label %dflt [
|
||||||
|
i64 0, label %arm_0
|
||||||
|
]
|
||||||
|
arm_0:
|
||||||
|
%b0 = and i64 %mask, 1
|
||||||
|
%s1 = icmp ne i64 %b0, 0
|
||||||
|
br i1 %s1, label %after_0_0, label %do_0_0
|
||||||
|
do_0_0:
|
||||||
|
%a2 = getelementptr inbounds i8, ptr %p, i64 8
|
||||||
|
%v3 = load ptr, ptr %a2, align 8
|
||||||
|
call void @drop_raw_buf_RawBuf(ptr %v3)
|
||||||
|
br label %after_0_0
|
||||||
|
after_0_0:
|
||||||
|
br label %join
|
||||||
|
dflt:
|
||||||
|
unreachable
|
||||||
|
join:
|
||||||
|
call void @ailang_rc_dec(ptr %p)
|
||||||
|
br label %ret
|
||||||
|
ret:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
define i32 @main() {
|
define i32 @main() {
|
||||||
call i8 @ail_list_main()
|
call i8 @ail_list_main()
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ declare i64 @llvm.fptosi.sat.i64.f64(double)
|
|||||||
@ail_prelude_gt__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_gt__Int_adapter, ptr null }
|
@ail_prelude_gt__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_gt__Int_adapter, ptr null }
|
||||||
@ail_prelude_show__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_show__Int_adapter, ptr null }
|
@ail_prelude_show__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_show__Int_adapter, ptr null }
|
||||||
@ail_prelude_print__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_print__Int_adapter, ptr null }
|
@ail_prelude_print__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_print__Int_adapter, ptr null }
|
||||||
|
@ail_prelude_lt__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_lt__Int_adapter, ptr null }
|
||||||
define i64 @ail_max3_max(i64 %arg_a, i64 %arg_b) {
|
define i64 @ail_max3_max(i64 %arg_a, i64 %arg_b) {
|
||||||
entry:
|
entry:
|
||||||
%v1 = call i1 @ail_prelude_gt__Int(i64 %arg_a, i64 %arg_b)
|
%v1 = call i1 @ail_prelude_gt__Int(i64 %arg_a, i64 %arg_b)
|
||||||
@@ -241,6 +242,18 @@ entry:
|
|||||||
ret i8 %r
|
ret i8 %r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define i1 @ail_prelude_lt__Int(i64 %arg_x, i64 %arg_y) alwaysinline {
|
||||||
|
entry:
|
||||||
|
%v1 = icmp slt i64 %arg_x, %arg_y
|
||||||
|
ret i1 %v1
|
||||||
|
}
|
||||||
|
|
||||||
|
define i1 @ail_prelude_lt__Int_adapter(ptr %_env, i64 %a0, i64 %a1) {
|
||||||
|
entry:
|
||||||
|
%r = call i1 @ail_prelude_lt__Int(i64 %a0, i64 %a1)
|
||||||
|
ret i1 %r
|
||||||
|
}
|
||||||
|
|
||||||
define void @drop_prelude_Ordering(ptr %p) {
|
define void @drop_prelude_Ordering(ptr %p) {
|
||||||
entry:
|
entry:
|
||||||
%is_null = icmp eq ptr %p, null
|
%is_null = icmp eq ptr %p, null
|
||||||
@@ -315,6 +328,58 @@ ret:
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define void @drop_series_Series__6ddcf58f(ptr %p) {
|
||||||
|
entry:
|
||||||
|
%is_null = icmp eq ptr %p, null
|
||||||
|
br i1 %is_null, label %ret, label %live
|
||||||
|
live:
|
||||||
|
%tag = load i64, ptr %p, align 8
|
||||||
|
switch i64 %tag, label %dflt [
|
||||||
|
i64 0, label %arm_0
|
||||||
|
]
|
||||||
|
arm_0:
|
||||||
|
%a0 = getelementptr inbounds i8, ptr %p, i64 8
|
||||||
|
%v1 = load ptr, ptr %a0, align 8
|
||||||
|
call void @drop_raw_buf_RawBuf(ptr %v1)
|
||||||
|
br label %join
|
||||||
|
dflt:
|
||||||
|
unreachable
|
||||||
|
join:
|
||||||
|
call void @ailang_rc_dec(ptr %p)
|
||||||
|
br label %ret
|
||||||
|
ret:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @partial_drop_series_Series__6ddcf58f(ptr %p, i64 %mask) {
|
||||||
|
entry:
|
||||||
|
%is_null = icmp eq ptr %p, null
|
||||||
|
br i1 %is_null, label %ret, label %live
|
||||||
|
live:
|
||||||
|
%tag = load i64, ptr %p, align 8
|
||||||
|
switch i64 %tag, label %dflt [
|
||||||
|
i64 0, label %arm_0
|
||||||
|
]
|
||||||
|
arm_0:
|
||||||
|
%b0 = and i64 %mask, 1
|
||||||
|
%s1 = icmp ne i64 %b0, 0
|
||||||
|
br i1 %s1, label %after_0_0, label %do_0_0
|
||||||
|
do_0_0:
|
||||||
|
%a2 = getelementptr inbounds i8, ptr %p, i64 8
|
||||||
|
%v3 = load ptr, ptr %a2, align 8
|
||||||
|
call void @drop_raw_buf_RawBuf(ptr %v3)
|
||||||
|
br label %after_0_0
|
||||||
|
after_0_0:
|
||||||
|
br label %join
|
||||||
|
dflt:
|
||||||
|
unreachable
|
||||||
|
join:
|
||||||
|
call void @ailang_rc_dec(ptr %p)
|
||||||
|
br label %ret
|
||||||
|
ret:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
define i32 @main() {
|
define i32 @main() {
|
||||||
call i8 @ail_max3_main()
|
call i8 @ail_max3_main()
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ declare i64 @llvm.fptosi.sat.i64.f64(double)
|
|||||||
@ail_prelude_float_le_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_le_adapter, ptr null }
|
@ail_prelude_float_le_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_le_adapter, ptr null }
|
||||||
@ail_prelude_float_gt_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_gt_adapter, ptr null }
|
@ail_prelude_float_gt_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_gt_adapter, ptr null }
|
||||||
@ail_prelude_float_ge_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_ge_adapter, ptr null }
|
@ail_prelude_float_ge_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_ge_adapter, ptr null }
|
||||||
|
@ail_prelude_compare__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_compare__Int_adapter, ptr null }
|
||||||
|
@ail_prelude_lt__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_lt__Int_adapter, ptr null }
|
||||||
@ail_prelude_eq__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_eq__Int_adapter, ptr null }
|
@ail_prelude_eq__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_eq__Int_adapter, ptr null }
|
||||||
@ail_prelude_show__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_show__Int_adapter, ptr null }
|
@ail_prelude_show__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_show__Int_adapter, ptr null }
|
||||||
@ail_prelude_print__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_print__Int_adapter, ptr null }
|
@ail_prelude_print__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_print__Int_adapter, ptr null }
|
||||||
@@ -105,6 +107,45 @@ entry:
|
|||||||
ret i1 %r
|
ret i1 %r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define ptr @ail_prelude_compare__Int(i64 %arg_x, i64 %arg_y) alwaysinline {
|
||||||
|
entry:
|
||||||
|
%v1 = icmp slt i64 %arg_x, %arg_y
|
||||||
|
br i1 %v1, label %cmp_lt_2, label %cmp_after_lt_2
|
||||||
|
cmp_lt_2:
|
||||||
|
%v3 = call ptr @ailang_rc_alloc(i64 8)
|
||||||
|
store i64 0, ptr %v3, align 8
|
||||||
|
ret ptr %v3
|
||||||
|
cmp_after_lt_2:
|
||||||
|
%v4 = icmp eq i64 %arg_x, %arg_y
|
||||||
|
br i1 %v4, label %cmp_eq_2, label %cmp_gt_2
|
||||||
|
cmp_eq_2:
|
||||||
|
%v5 = call ptr @ailang_rc_alloc(i64 8)
|
||||||
|
store i64 1, ptr %v5, align 8
|
||||||
|
ret ptr %v5
|
||||||
|
cmp_gt_2:
|
||||||
|
%v6 = call ptr @ailang_rc_alloc(i64 8)
|
||||||
|
store i64 2, ptr %v6, align 8
|
||||||
|
ret ptr %v6
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @ail_prelude_compare__Int_adapter(ptr %_env, i64 %a0, i64 %a1) {
|
||||||
|
entry:
|
||||||
|
%r = call ptr @ail_prelude_compare__Int(i64 %a0, i64 %a1)
|
||||||
|
ret ptr %r
|
||||||
|
}
|
||||||
|
|
||||||
|
define i1 @ail_prelude_lt__Int(i64 %arg_x, i64 %arg_y) alwaysinline {
|
||||||
|
entry:
|
||||||
|
%v1 = icmp slt i64 %arg_x, %arg_y
|
||||||
|
ret i1 %v1
|
||||||
|
}
|
||||||
|
|
||||||
|
define i1 @ail_prelude_lt__Int_adapter(ptr %_env, i64 %a0, i64 %a1) {
|
||||||
|
entry:
|
||||||
|
%r = call i1 @ail_prelude_lt__Int(i64 %a0, i64 %a1)
|
||||||
|
ret i1 %r
|
||||||
|
}
|
||||||
|
|
||||||
define i1 @ail_prelude_eq__Int(i64 %arg_x, i64 %arg_y) alwaysinline {
|
define i1 @ail_prelude_eq__Int(i64 %arg_x, i64 %arg_y) alwaysinline {
|
||||||
entry:
|
entry:
|
||||||
%v1 = icmp eq i64 %arg_x, %arg_y
|
%v1 = icmp eq i64 %arg_x, %arg_y
|
||||||
@@ -219,6 +260,58 @@ ret:
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define void @drop_series_Series__6ddcf58f(ptr %p) {
|
||||||
|
entry:
|
||||||
|
%is_null = icmp eq ptr %p, null
|
||||||
|
br i1 %is_null, label %ret, label %live
|
||||||
|
live:
|
||||||
|
%tag = load i64, ptr %p, align 8
|
||||||
|
switch i64 %tag, label %dflt [
|
||||||
|
i64 0, label %arm_0
|
||||||
|
]
|
||||||
|
arm_0:
|
||||||
|
%a0 = getelementptr inbounds i8, ptr %p, i64 8
|
||||||
|
%v1 = load ptr, ptr %a0, align 8
|
||||||
|
call void @drop_raw_buf_RawBuf(ptr %v1)
|
||||||
|
br label %join
|
||||||
|
dflt:
|
||||||
|
unreachable
|
||||||
|
join:
|
||||||
|
call void @ailang_rc_dec(ptr %p)
|
||||||
|
br label %ret
|
||||||
|
ret:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @partial_drop_series_Series__6ddcf58f(ptr %p, i64 %mask) {
|
||||||
|
entry:
|
||||||
|
%is_null = icmp eq ptr %p, null
|
||||||
|
br i1 %is_null, label %ret, label %live
|
||||||
|
live:
|
||||||
|
%tag = load i64, ptr %p, align 8
|
||||||
|
switch i64 %tag, label %dflt [
|
||||||
|
i64 0, label %arm_0
|
||||||
|
]
|
||||||
|
arm_0:
|
||||||
|
%b0 = and i64 %mask, 1
|
||||||
|
%s1 = icmp ne i64 %b0, 0
|
||||||
|
br i1 %s1, label %after_0_0, label %do_0_0
|
||||||
|
do_0_0:
|
||||||
|
%a2 = getelementptr inbounds i8, ptr %p, i64 8
|
||||||
|
%v3 = load ptr, ptr %a2, align 8
|
||||||
|
call void @drop_raw_buf_RawBuf(ptr %v3)
|
||||||
|
br label %after_0_0
|
||||||
|
after_0_0:
|
||||||
|
br label %join
|
||||||
|
dflt:
|
||||||
|
unreachable
|
||||||
|
join:
|
||||||
|
call void @ailang_rc_dec(ptr %p)
|
||||||
|
br label %ret
|
||||||
|
ret:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
define i64 @ail_sum_sum(i64 %arg_n) {
|
define i64 @ail_sum_sum(i64 %arg_n) {
|
||||||
entry:
|
entry:
|
||||||
%v1 = call i1 @ail_prelude_eq__Int(i64 %arg_n, i64 0)
|
%v1 = call i1 @ail_prelude_eq__Int(i64 %arg_n, i64 0)
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ declare i64 @llvm.fptosi.sat.i64.f64(double)
|
|||||||
@ail_prelude_float_le_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_le_adapter, ptr null }
|
@ail_prelude_float_le_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_le_adapter, ptr null }
|
||||||
@ail_prelude_float_gt_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_gt_adapter, ptr null }
|
@ail_prelude_float_gt_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_gt_adapter, ptr null }
|
||||||
@ail_prelude_float_ge_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_ge_adapter, ptr null }
|
@ail_prelude_float_ge_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_float_ge_adapter, ptr null }
|
||||||
|
@ail_prelude_compare__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_compare__Int_adapter, ptr null }
|
||||||
|
@ail_prelude_lt__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_lt__Int_adapter, ptr null }
|
||||||
@ail_prelude_show__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_show__Int_adapter, ptr null }
|
@ail_prelude_show__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_show__Int_adapter, ptr null }
|
||||||
@ail_prelude_print__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_print__Int_adapter, ptr null }
|
@ail_prelude_print__Int_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_prelude_print__Int_adapter, ptr null }
|
||||||
@ail_ws_lib_add_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_ws_lib_add_adapter, ptr null }
|
@ail_ws_lib_add_clos = private unnamed_addr constant { ptr, ptr } { ptr @ail_ws_lib_add_adapter, ptr null }
|
||||||
@@ -104,6 +106,45 @@ entry:
|
|||||||
ret i1 %r
|
ret i1 %r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define ptr @ail_prelude_compare__Int(i64 %arg_x, i64 %arg_y) alwaysinline {
|
||||||
|
entry:
|
||||||
|
%v1 = icmp slt i64 %arg_x, %arg_y
|
||||||
|
br i1 %v1, label %cmp_lt_2, label %cmp_after_lt_2
|
||||||
|
cmp_lt_2:
|
||||||
|
%v3 = call ptr @ailang_rc_alloc(i64 8)
|
||||||
|
store i64 0, ptr %v3, align 8
|
||||||
|
ret ptr %v3
|
||||||
|
cmp_after_lt_2:
|
||||||
|
%v4 = icmp eq i64 %arg_x, %arg_y
|
||||||
|
br i1 %v4, label %cmp_eq_2, label %cmp_gt_2
|
||||||
|
cmp_eq_2:
|
||||||
|
%v5 = call ptr @ailang_rc_alloc(i64 8)
|
||||||
|
store i64 1, ptr %v5, align 8
|
||||||
|
ret ptr %v5
|
||||||
|
cmp_gt_2:
|
||||||
|
%v6 = call ptr @ailang_rc_alloc(i64 8)
|
||||||
|
store i64 2, ptr %v6, align 8
|
||||||
|
ret ptr %v6
|
||||||
|
}
|
||||||
|
|
||||||
|
define ptr @ail_prelude_compare__Int_adapter(ptr %_env, i64 %a0, i64 %a1) {
|
||||||
|
entry:
|
||||||
|
%r = call ptr @ail_prelude_compare__Int(i64 %a0, i64 %a1)
|
||||||
|
ret ptr %r
|
||||||
|
}
|
||||||
|
|
||||||
|
define i1 @ail_prelude_lt__Int(i64 %arg_x, i64 %arg_y) alwaysinline {
|
||||||
|
entry:
|
||||||
|
%v1 = icmp slt i64 %arg_x, %arg_y
|
||||||
|
ret i1 %v1
|
||||||
|
}
|
||||||
|
|
||||||
|
define i1 @ail_prelude_lt__Int_adapter(ptr %_env, i64 %a0, i64 %a1) {
|
||||||
|
entry:
|
||||||
|
%r = call i1 @ail_prelude_lt__Int(i64 %a0, i64 %a1)
|
||||||
|
ret i1 %r
|
||||||
|
}
|
||||||
|
|
||||||
define ptr @ail_prelude_show__Int(i64 %arg_x) {
|
define ptr @ail_prelude_show__Int(i64 %arg_x) {
|
||||||
entry:
|
entry:
|
||||||
%v1 = call ptr @ailang_int_to_str(i64 %arg_x)
|
%v1 = call ptr @ailang_int_to_str(i64 %arg_x)
|
||||||
@@ -206,6 +247,58 @@ ret:
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define void @drop_series_Series__6ddcf58f(ptr %p) {
|
||||||
|
entry:
|
||||||
|
%is_null = icmp eq ptr %p, null
|
||||||
|
br i1 %is_null, label %ret, label %live
|
||||||
|
live:
|
||||||
|
%tag = load i64, ptr %p, align 8
|
||||||
|
switch i64 %tag, label %dflt [
|
||||||
|
i64 0, label %arm_0
|
||||||
|
]
|
||||||
|
arm_0:
|
||||||
|
%a0 = getelementptr inbounds i8, ptr %p, i64 8
|
||||||
|
%v1 = load ptr, ptr %a0, align 8
|
||||||
|
call void @drop_raw_buf_RawBuf(ptr %v1)
|
||||||
|
br label %join
|
||||||
|
dflt:
|
||||||
|
unreachable
|
||||||
|
join:
|
||||||
|
call void @ailang_rc_dec(ptr %p)
|
||||||
|
br label %ret
|
||||||
|
ret:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @partial_drop_series_Series__6ddcf58f(ptr %p, i64 %mask) {
|
||||||
|
entry:
|
||||||
|
%is_null = icmp eq ptr %p, null
|
||||||
|
br i1 %is_null, label %ret, label %live
|
||||||
|
live:
|
||||||
|
%tag = load i64, ptr %p, align 8
|
||||||
|
switch i64 %tag, label %dflt [
|
||||||
|
i64 0, label %arm_0
|
||||||
|
]
|
||||||
|
arm_0:
|
||||||
|
%b0 = and i64 %mask, 1
|
||||||
|
%s1 = icmp ne i64 %b0, 0
|
||||||
|
br i1 %s1, label %after_0_0, label %do_0_0
|
||||||
|
do_0_0:
|
||||||
|
%a2 = getelementptr inbounds i8, ptr %p, i64 8
|
||||||
|
%v3 = load ptr, ptr %a2, align 8
|
||||||
|
call void @drop_raw_buf_RawBuf(ptr %v3)
|
||||||
|
br label %after_0_0
|
||||||
|
after_0_0:
|
||||||
|
br label %join
|
||||||
|
dflt:
|
||||||
|
unreachable
|
||||||
|
join:
|
||||||
|
call void @ailang_rc_dec(ptr %p)
|
||||||
|
br label %ret
|
||||||
|
ret:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
define i64 @ail_ws_lib_add(i64 %arg_a, i64 %arg_b) {
|
define i64 @ail_ws_lib_add(i64 %arg_a, i64 %arg_b) {
|
||||||
entry:
|
entry:
|
||||||
%v1 = add i64 %arg_a, %arg_b
|
%v1 = add i64 %arg_a, %arg_b
|
||||||
|
|||||||
@@ -30,7 +30,21 @@ fn monomorphise_workspace_is_identity_on_class_free_workspace() {
|
|||||||
"module set must be identical"
|
"module set must be identical"
|
||||||
);
|
);
|
||||||
// Per-module def list unchanged (compare by canonical-JSON hash).
|
// Per-module def list unchanged (compare by canonical-JSON hash).
|
||||||
|
//
|
||||||
|
// Exception: `prelude` is no longer hash-identical through mono for
|
||||||
|
// ANY entry since feat-series-step1. The auto-imported `series`
|
||||||
|
// kernel module is a real-bodied (non-intrinsic) consumer of the
|
||||||
|
// prelude polyfns `lt`/`compare` over `Int`, so the workspace-wide
|
||||||
|
// mono pass now materialises `lt__Int` / `compare__Int` into the
|
||||||
|
// prelude module regardless of the user entry. That is a concrete
|
||||||
|
// call site driven by an auto-imported library module, not gratuitous
|
||||||
|
// mutation — the test's real invariant (mono does not rewrite modules
|
||||||
|
// with no work to do) holds for every other module. `series` itself
|
||||||
|
// is excluded for the same reason: it may gain its own specialisations.
|
||||||
for (mname, m) in &ws.modules {
|
for (mname, m) in &ws.modules {
|
||||||
|
if mname == "prelude" || mname == "series" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let before_m = &before.modules[mname];
|
let before_m = &before.modules[mname];
|
||||||
let h_after = ailang_core::module_hash(m);
|
let h_after = ailang_core::module_hash(m);
|
||||||
let h_before = ailang_core::module_hash(before_m);
|
let h_before = ailang_core::module_hash(before_m);
|
||||||
@@ -72,8 +86,18 @@ fn monomorphise_workspace_is_identity_when_no_concrete_call_sites() {
|
|||||||
"module set must be identical"
|
"module set must be identical"
|
||||||
);
|
);
|
||||||
// Each module hashes byte-identical — no synth fns appended
|
// Each module hashes byte-identical — no synth fns appended
|
||||||
// because no call site triggered a target.
|
// because no class-method call site triggered a target.
|
||||||
|
//
|
||||||
|
// Exception: `prelude` and `series` — see the sibling test
|
||||||
|
// `monomorphise_workspace_is_identity_on_class_free_workspace` for
|
||||||
|
// the rationale. The auto-imported, real-bodied `series` kernel
|
||||||
|
// module pins `lt__Int` / `compare__Int` specialisations into
|
||||||
|
// `prelude` for every workspace; that is a legitimate concrete call
|
||||||
|
// site, orthogonal to this test's typeclass-call-site invariant.
|
||||||
for (mname, m) in &ws_after.modules {
|
for (mname, m) in &ws_after.modules {
|
||||||
|
if mname == "prelude" || mname == "series" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let before_m = &before.modules[mname];
|
let before_m = &before.modules[mname];
|
||||||
let h_after = ailang_core::module_hash(m);
|
let h_after = ailang_core::module_hash(m);
|
||||||
let h_before = ailang_core::module_hash(before_m);
|
let h_before = ailang_core::module_hash(before_m);
|
||||||
|
|||||||
@@ -46,13 +46,15 @@ fn loads_example_workspace_happy_path() {
|
|||||||
assert_eq!(ws.entry, "ws_main");
|
assert_eq!(ws.entry, "ws_main");
|
||||||
assert!(ws.modules.contains_key("ws_main"));
|
assert!(ws.modules.contains_key("ws_main"));
|
||||||
assert!(ws.modules.contains_key("ws_lib"));
|
assert!(ws.modules.contains_key("ws_lib"));
|
||||||
// the loader auto-injects two built-in kernel-tier modules
|
// the loader auto-injects three built-in kernel-tier modules
|
||||||
// (`prelude` and `raw_buf`, the first real-payload kernel
|
// (`prelude`; `raw_buf`, the first real-payload kernel extension,
|
||||||
// extension, raw-buf.4), so the count is the user's two modules
|
// raw-buf.4; and `series`, the first pure-AILang library extension,
|
||||||
// plus those two.
|
// feat-series-step1), so the count is the user's two modules plus
|
||||||
assert_eq!(ws.modules.len(), 4);
|
// those three.
|
||||||
|
assert_eq!(ws.modules.len(), 5);
|
||||||
assert!(ws.modules.contains_key("prelude"));
|
assert!(ws.modules.contains_key("prelude"));
|
||||||
assert!(ws.modules.contains_key("raw_buf"));
|
assert!(ws.modules.contains_key("raw_buf"));
|
||||||
|
assert!(ws.modules.contains_key("series"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -9,5 +9,7 @@
|
|||||||
//! crate carries zero parser code.
|
//! crate carries zero parser code.
|
||||||
|
|
||||||
mod raw_buf;
|
mod raw_buf;
|
||||||
|
mod series;
|
||||||
|
|
||||||
pub use raw_buf::SOURCE as RAW_BUF_AIL;
|
pub use raw_buf::SOURCE as RAW_BUF_AIL;
|
||||||
|
pub use series::SOURCE as SERIES_AIL;
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
//! Series submodule — the Form-A source of the `series` kernel-tier
|
||||||
|
//! library-extension module (Series: a bounded ring buffer over
|
||||||
|
//! RawBuf with financial-style indexing, index 0 = newest). Parsed by
|
||||||
|
//! `ailang_surface::parse_series`.
|
||||||
|
//!
|
||||||
|
//! Unlike `raw_buf`, `series` is a PURE AILang library extension: its
|
||||||
|
//! five ops (new/push/at/len/total_count) carry real `.ail` bodies
|
||||||
|
//! built on the `RawBuf.*` intrinsics, so it adds NO intercept entries
|
||||||
|
//! and NO `(intrinsic)` markers. It is the first kernel-tier module
|
||||||
|
//! that depends on another kernel-tier module (`raw_buf`); cross-
|
||||||
|
//! kernel-module visibility comes from the kernel auto-import set the
|
||||||
|
//! loader derives from every `kernel: true` module.
|
||||||
|
|
||||||
|
/// Source-of-truth Form-A text for the `series` kernel module.
|
||||||
|
/// Declares the `Series` TypeDef (`param-in (a Int Float)`) and the
|
||||||
|
/// five real-bodied ops `new`/`push`/`at`/`len`/`total_count`, all
|
||||||
|
/// implemented over the `raw_buf` kernel module's `RawBuf.*` ops.
|
||||||
|
pub const SOURCE: &str = include_str!("source.ail");
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
(module series
|
||||||
|
(kernel)
|
||||||
|
(data Series (vars a)
|
||||||
|
(doc "Bounded ring buffer with financial-style indexing (index 0 = newest). Pure AILang library extension over RawBuf: the buffer holds the elements, the four Int fields are lookback (capacity), head (next write slot), count (live elements, saturates at lookback), and total (monotone count of all pushes ever). Element type restricted to {Int, Float} via param-in; Bool deferred (#61).")
|
||||||
|
(param-in (a Int Float))
|
||||||
|
(ctor S (con RawBuf a)
|
||||||
|
(con Int)
|
||||||
|
(con Int)
|
||||||
|
(con Int)
|
||||||
|
(con Int)))
|
||||||
|
(fn new
|
||||||
|
(doc "Allocate an empty Series of capacity `lookback`. The inner RawBuf is allocated via `(new RawBuf lookback)` with NO element type-arg — the element type is solved from the expected ctor-field type `(con RawBuf a)`, which the base-tier mono fix (b11a6d9) carries through to the caller's concrete type.")
|
||||||
|
(type (forall (vars a) (fn-type (params (own (con Int))) (ret (own (con Series a))))))
|
||||||
|
(params lookback)
|
||||||
|
(body
|
||||||
|
(term-ctor Series S
|
||||||
|
(new RawBuf lookback) lookback 0 0 0)))
|
||||||
|
(fn push
|
||||||
|
(doc "Append `v`, evicting the oldest element when full. own-in/own-out linear threading: mutates the buffer at head, advances head mod lookback, saturates count at lookback, increments total.")
|
||||||
|
(type (forall (vars a) (fn-type (params (own (con Series a)) (own a)) (ret (own (con Series a))))))
|
||||||
|
(params s v)
|
||||||
|
(body
|
||||||
|
(match s
|
||||||
|
(case (pat-ctor S buf lookback head count total)
|
||||||
|
(term-ctor Series S
|
||||||
|
(app RawBuf.set buf head v)
|
||||||
|
lookback
|
||||||
|
(app % (app + head 1) lookback)
|
||||||
|
(if (app lt count lookback) (app + count 1) count)
|
||||||
|
(app + total 1))))))
|
||||||
|
(fn at
|
||||||
|
(doc "Read the element `i` positions back from newest (i=0 is the most recent push). Financial indexing: slot = (head - 1 - i + 2*lookback) mod lookback. UB if i >= len; caller checks via len/total_count.")
|
||||||
|
(type (forall (vars a) (fn-type (params (borrow (con Series a)) (own (con Int))) (ret (own a)))))
|
||||||
|
(params s i)
|
||||||
|
(body
|
||||||
|
(match s
|
||||||
|
(case (pat-ctor S buf lookback head count total)
|
||||||
|
(app RawBuf.get buf
|
||||||
|
(app % (app + (app - (app - head 1) i) (app * lookback 2)) lookback))))))
|
||||||
|
(fn len
|
||||||
|
(doc "Number of live elements (saturates at lookback).")
|
||||||
|
(type (forall (vars a) (fn-type (params (borrow (con Series a))) (ret (own (con Int))))))
|
||||||
|
(params s)
|
||||||
|
(body (match s (case (pat-ctor S buf lookback head count total) count))))
|
||||||
|
(fn total_count
|
||||||
|
(doc "Monotone count of all pushes ever (does not saturate). Drives the SMA emit gate.")
|
||||||
|
(type (forall (vars a) (fn-type (params (borrow (con Series a))) (ret (own (con Int))))))
|
||||||
|
(params s)
|
||||||
|
(body (match s (case (pat-ctor S buf lookback head count total) total)))))
|
||||||
@@ -37,7 +37,8 @@ pub mod parse;
|
|||||||
pub mod print;
|
pub mod print;
|
||||||
|
|
||||||
pub use loader::{
|
pub use loader::{
|
||||||
load_module, load_workspace, parse_prelude, parse_raw_buf, PRELUDE_AIL,
|
load_module, load_workspace, parse_prelude, parse_raw_buf, parse_series,
|
||||||
|
PRELUDE_AIL,
|
||||||
};
|
};
|
||||||
pub use parse::{parse, parse_term, ParseError};
|
pub use parse::{parse, parse_term, ParseError};
|
||||||
pub use print::{print, term_to_form_a, type_to_form_a};
|
pub use print::{print, term_to_form_a, type_to_form_a};
|
||||||
|
|||||||
@@ -56,6 +56,21 @@ pub fn parse_raw_buf() -> Module {
|
|||||||
.expect("ailang_kernel::RAW_BUF_AIL must parse as a Module")
|
.expect("ailang_kernel::RAW_BUF_AIL must parse as a Module")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// feat-series-step1: parse the embedded `series` kernel-tier library-
|
||||||
|
/// extension module bytes into a `Module`. Mirror of [`parse_raw_buf`].
|
||||||
|
///
|
||||||
|
/// Source-of-truth: `ailang_kernel::SERIES_AIL`. Declares the `Series`
|
||||||
|
/// TypeDef with `param-in (a Int Float)` and the five real-bodied ops
|
||||||
|
/// `new`/`push`/`at`/`len`/`total_count`, built over the `raw_buf`
|
||||||
|
/// kernel module's `RawBuf.*` ops. Unlike raw_buf this is a PURE
|
||||||
|
/// AILang library extension — no intercepts, no `(intrinsic)` markers.
|
||||||
|
///
|
||||||
|
/// Panics on parse failure — build-time-validated by every drift run.
|
||||||
|
pub fn parse_series() -> Module {
|
||||||
|
crate::parse(ailang_kernel::SERIES_AIL)
|
||||||
|
.expect("ailang_kernel::SERIES_AIL must parse as a Module")
|
||||||
|
}
|
||||||
|
|
||||||
fn is_ail_source(path: &Path) -> bool {
|
fn is_ail_source(path: &Path) -> bool {
|
||||||
path.extension().and_then(|s| s.to_str()) == Some("ail")
|
path.extension().and_then(|s| s.to_str()) == Some("ail")
|
||||||
}
|
}
|
||||||
@@ -131,6 +146,18 @@ pub fn load_workspace(entry: &Path) -> Result<Workspace, WorkspaceLoadError> {
|
|||||||
}
|
}
|
||||||
modules.insert("raw_buf".to_string(), parse_raw_buf());
|
modules.insert("raw_buf".to_string(), parse_raw_buf());
|
||||||
|
|
||||||
|
// parse_series() injects the series kernel-tier library-extension
|
||||||
|
// module — Series, a bounded ring buffer over RawBuf. Pure AILang
|
||||||
|
// (no intercepts); its body references the raw_buf kernel module,
|
||||||
|
// which the kernel auto-import set below makes visible. Its source
|
||||||
|
// carries `(kernel)`, so the kernel-flag filter auto-imports it.
|
||||||
|
if modules.contains_key("series") {
|
||||||
|
return Err(WorkspaceLoadError::ReservedModuleName {
|
||||||
|
name: "series".to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
modules.insert("series".to_string(), parse_series());
|
||||||
|
|
||||||
// Derive the implicit-imports list from `kernel: true` modules.
|
// Derive the implicit-imports list from `kernel: true` modules.
|
||||||
// Replaces the previous hardcoded `&["prelude"]` literal: any
|
// Replaces the previous hardcoded `&["prelude"]` literal: any
|
||||||
// workspace-loaded module that carries the kernel flag is now
|
// workspace-loaded module that carries the kernel flag is now
|
||||||
|
|||||||
Reference in New Issue
Block a user