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:
@@ -37,7 +37,8 @@ pub mod parse;
|
||||
pub mod print;
|
||||
|
||||
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 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")
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
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());
|
||||
|
||||
// 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.
|
||||
// Replaces the previous hardcoded `&["prelude"]` literal: any
|
||||
// workspace-loaded module that carries the kernel flag is now
|
||||
|
||||
Reference in New Issue
Block a user