diff --git a/CLAUDE.md b/CLAUDE.md index 6c8222a..f92e2c3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -49,7 +49,7 @@ it measurably improves correctness or removes redundancy. | `crates/ailang-check/` | Type and uniqueness/mode analysis, lints, diagnostics | | `crates/ailang-codegen/` | LLVM-IR codegen — RC, drop, lambda lowering, match lowering, escape, synth, subst | | `crates/ailang-prose/` | Form-A ↔ Form-B prose projection | -| `crates/ailang-kernel-stub/` | Zero-dependency leaf crate carrying only the Form-A source of the `kernel_stub` ratifying-fixture module (`pub const STUB_AIL: &str`). The parse hop (`parse_kernel_stub`) lives in `ailang-surface` to keep the crate-dependency graph acyclic. Injected into every workspace load alongside `prelude`; may be retired when the `raw-buf` milestone lands a real second kernel-tier consumer. | +| `crates/ailang-kernel/` | Family-crate hosting the Form-A source of every kernel-tier `.ail` module, one Rust submodule per module under `src/` (today: `kernel_stub`), each exposing a `pub const SOURCE` re-exported from `src/lib.rs` (`STUB_AIL`). Zero-dependency leaf; parse hops (`parse_kernel_stub`) live in `ailang-surface` to keep the graph acyclic (`ailang-surface → ailang-kernel → ailang-core`). The `kernel_stub` submodule is injected alongside `prelude` and is retired in raw-buf.4 once `raw_buf` becomes the real kernel-tier consumer. | | `runtime/` | C glue around the RC runtime | | `bench/` | Regression harnesses (`check.py`, `compile_check.py`, `cross_lang.py`) and the throughput-and-latency runner (`run.sh`); `bench/reference/` holds the hand-C corpus for cross-language ratios | | `examples/` | AILang fixtures used by tests and benches | @@ -309,7 +309,7 @@ the cross-references column of a file-map. |---|---| | `Pattern::Lit::*` typecheck rejects in `crates/ailang-check/src/lib.rs` ↔ pre-desugar walkers in `crates/ailang-check/src/pre_desugar_validation.rs` | A reject arm placed AFTER `desugar_module` in the call chain is unreachable through the public `check` API if the desugar pass rewrites that pattern shape first (e.g. `desugar::build_eq` rewrites `Pattern::Lit::Float` into `(== scrut lit)` before typecheck runs). New rejects on a `Pattern::Lit::*` shape MUST live in `pre_desugar_validation.rs`, or be paired with a written guarantee that no desugar pass eats the shape. | | `lower_app` arms in `crates/ailang-codegen/src/lib.rs::lower_app` (line ~1749) ↔ name recognition in `crates/ailang-codegen/src/lib.rs::is_static_callee` (line ~2189) | A name lowered by a direct `lower_app` arm but unrecognised by `is_static_callee` falls through to the indirect-call path with `UnknownVar` (`UnknownVar` panic in worst case). Every new builtin lowering arm in `lower_app` must have a matching `is_static_callee` entry. | -| `INTERCEPTS` entries in `crates/ailang-codegen/src/intercepts.rs` ↔ `(intrinsic)` markers (`Term::Intrinsic` bodies) in the kernel-tier sources (`examples/prelude.ail`, `crates/ailang-kernel-stub/src/lib.rs::STUB_AIL`) | A registry entry without a marker is a compiler-supplied body no source declares; a marker without an entry is an `(intrinsic)` fn codegen cannot emit. The bijection (modulo the optimisation-only allowlist — registry entries that intercept the monomorphised `__Int` specialisation of a real-bodied polyfn) is enforced by `intercepts::tests::intercepts_bijection_with_intrinsic_markers`. Every new intrinsic-backed intercept needs both an `INTERCEPTS` entry and an `(intrinsic)` marker; every new optimisation-only intercept needs an `OPTIMISATION_ONLY` allowlist entry. | +| `INTERCEPTS` entries in `crates/ailang-codegen/src/intercepts.rs` ↔ `(intrinsic)` markers (`Term::Intrinsic` bodies) in the kernel-tier sources (`examples/prelude.ail`, `crates/ailang-kernel/src/kernel_stub/source.ail`) | A registry entry without a marker is a compiler-supplied body no source declares; a marker without an entry is an `(intrinsic)` fn codegen cannot emit. The bijection (modulo the optimisation-only allowlist — registry entries that intercept the monomorphised `__Int` specialisation of a real-bodied polyfn) is enforced by `intercepts::tests::intercepts_bijection_with_intrinsic_markers`. Every new intrinsic-backed intercept needs both an `INTERCEPTS` entry and an `(intrinsic)` marker; every new optimisation-only intercept needs an `OPTIMISATION_ONLY` allowlist entry. | Walk procedure: for each milestone-scope commit-range arm landed in these files (use `git diff ..HEAD --` on diff --git a/Cargo.lock b/Cargo.lock index 4cc62ab..d16a435 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,7 +55,7 @@ dependencies = [ ] [[package]] -name = "ailang-kernel-stub" +name = "ailang-kernel" version = "0.0.1" [[package]] @@ -71,7 +71,7 @@ name = "ailang-surface" version = "0.0.1" dependencies = [ "ailang-core", - "ailang-kernel-stub", + "ailang-kernel", "serde_json", "tempfile", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index f26a2ed..4d30772 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ members = [ "crates/ailang-core", "crates/ailang-check", "crates/ailang-codegen", - "crates/ailang-kernel-stub", + "crates/ailang-kernel", "crates/ailang-surface", "crates/ailang-prose", "crates/ail", @@ -34,7 +34,7 @@ tempfile = "3" ailang-core = { path = "crates/ailang-core" } ailang-check = { path = "crates/ailang-check" } ailang-codegen = { path = "crates/ailang-codegen" } -ailang-kernel-stub = { path = "crates/ailang-kernel-stub" } +ailang-kernel = { path = "crates/ailang-kernel" } ailang-surface = { path = "crates/ailang-surface" } ailang-prose = { path = "crates/ailang-prose" } diff --git a/crates/ailang-kernel-stub/src/lib.rs b/crates/ailang-kernel-stub/src/lib.rs deleted file mode 100644 index 514098a..0000000 --- a/crates/ailang-kernel-stub/src/lib.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! Kernel-tier stub module — minimal ratifying fixture for the -//! kernel-extension-mechanics milestone (prep.3). -//! -//! The stub exists solely to exercise the shipped mechanisms -//! end-to-end: `Module.kernel`, `TypeDef.param-in`, and type-scoped -//! resolution (the stub's type is visible to every consumer without -//! an `(import …)` declaration). -//! -//! No domain content. The stub may be retired or repositioned when -//! a real second kernel-tier consumer (the `raw-buf` milestone) lands. -//! -//! This crate carries ONLY the embedded Form-A text and the parsed -//! `Module` value. The parse hop itself lives in `ailang-surface` -//! (see `ailang_surface::parse_kernel_stub`) so the -//! crate-dependency graph stays acyclic: `ailang-surface → -//! ailang-kernel-stub → ailang-core` (no back-edge from -//! `ailang-kernel-stub` to `ailang-surface`). - -/// Source-of-truth Form-A text for the stub kernel module. Parsed -/// by `ailang_surface::parse_kernel_stub` (and round-trip-pinned by -/// `kernel_stub_module_round_trips` in `design_schema_drift.rs`). -/// -/// Ships a `(fn new ...)` def so consumers can spell `(new StubT 42)`, -/// the worked-consumer example from prep.3 of the spec — without it, -/// the stub's `Term::New` end-to-end ratification story is broken -/// (per fieldtest F4, 2026-05-28). -pub const STUB_AIL: &str = r#"(module kernel_stub - (kernel) - (data StubT (vars a) - (ctor Stub a) - (param-in (a Int Float))) - (fn new - (doc "Construct StubT from an Int. Exercises Term::New end-to-end.") - (type (fn-type (params (con Int)) (ret (con StubT (con Int))))) - (params x) - (body (term-ctor StubT Stub x))) - (fn answer - (doc "Ratifies the intrinsic mechanism end-to-end: codegen intercept answer emits ret i64 42.") - (type (fn-type (params) (ret (con Int)))) - (params) - (intrinsic))) -"#; diff --git a/crates/ailang-kernel-stub/Cargo.toml b/crates/ailang-kernel/Cargo.toml similarity index 78% rename from crates/ailang-kernel-stub/Cargo.toml rename to crates/ailang-kernel/Cargo.toml index 599bee4..5915afe 100644 --- a/crates/ailang-kernel-stub/Cargo.toml +++ b/crates/ailang-kernel/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "ailang-kernel-stub" +name = "ailang-kernel" version.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/ailang-kernel/src/kernel_stub/mod.rs b/crates/ailang-kernel/src/kernel_stub/mod.rs new file mode 100644 index 0000000..3e0554e --- /dev/null +++ b/crates/ailang-kernel/src/kernel_stub/mod.rs @@ -0,0 +1,16 @@ +//! Kernel-stub submodule — minimal ratifying fixture for the +//! kernel-extension-mechanics milestone (prep.3). The Form-A text +//! lives in the sibling `source.ail`. +//! +//! No domain content. Retired when the `raw-buf` milestone lands +//! its real kernel-tier consumer (raw-buf.4); until then it stays +//! as the ratifying-fixture anchor. + +/// Source-of-truth Form-A text for the stub kernel module. Parsed +/// by `ailang_surface::parse_kernel_stub` (and round-trip-pinned by +/// `kernel_stub_module_round_trips` in `design_schema_drift.rs`). +/// +/// Ships a `(fn new ...)` def so consumers can spell `(new StubT 42)` +/// (Term::New end-to-end, per prep.3 fieldtest F4) and an `answer` +/// `(intrinsic)` fn whose `INTERCEPTS` entry the bijection test pins. +pub const SOURCE: &str = include_str!("source.ail"); diff --git a/crates/ailang-kernel/src/kernel_stub/source.ail b/crates/ailang-kernel/src/kernel_stub/source.ail new file mode 100644 index 0000000..b565e9d --- /dev/null +++ b/crates/ailang-kernel/src/kernel_stub/source.ail @@ -0,0 +1,15 @@ +(module kernel_stub + (kernel) + (data StubT (vars a) + (ctor Stub a) + (param-in (a Int Float))) + (fn new + (doc "Construct StubT from an Int. Exercises Term::New end-to-end.") + (type (fn-type (params (con Int)) (ret (con StubT (con Int))))) + (params x) + (body (term-ctor StubT Stub x))) + (fn answer + (doc "Ratifies the intrinsic mechanism end-to-end: codegen intercept answer emits ret i64 42.") + (type (fn-type (params) (ret (con Int)))) + (params) + (intrinsic))) diff --git a/crates/ailang-kernel/src/lib.rs b/crates/ailang-kernel/src/lib.rs new file mode 100644 index 0000000..20f5e0b --- /dev/null +++ b/crates/ailang-kernel/src/lib.rs @@ -0,0 +1,13 @@ +//! Kernel-tier modules — family-crate hosting the Form-A source of +//! every kernel-tier `.ail` module the AILang workspace +//! auto-injects. One Cargo crate, one Rust submodule per +//! kernel-tier module, one `pub const SOURCE` per submodule. +//! +//! The acyclic dependency chain is preserved: +//! `ailang-surface → ailang-kernel → ailang-core`. Per-module parse +//! hops live in `ailang-surface` (`parse_kernel_stub`, …) so this +//! crate carries zero parser code. + +mod kernel_stub; + +pub use kernel_stub::SOURCE as STUB_AIL; diff --git a/crates/ailang-surface/Cargo.toml b/crates/ailang-surface/Cargo.toml index edc7277..a6299ae 100644 --- a/crates/ailang-surface/Cargo.toml +++ b/crates/ailang-surface/Cargo.toml @@ -6,7 +6,7 @@ license.workspace = true [dependencies] ailang-core.workspace = true -ailang-kernel-stub.workspace = true +ailang-kernel.workspace = true serde_json.workspace = true thiserror.workspace = true diff --git a/crates/ailang-surface/src/loader.rs b/crates/ailang-surface/src/loader.rs index 5a89f31..09efc03 100644 --- a/crates/ailang-surface/src/loader.rs +++ b/crates/ailang-surface/src/loader.rs @@ -45,15 +45,15 @@ pub fn parse_prelude() -> Module { /// prep.3 (kernel-extension-mechanics): parse the embedded /// kernel-stub bytes into a `Module`. Mirror of [`parse_prelude`]. /// -/// Source-of-truth: `ailang_kernel_stub::STUB_AIL`. The stub +/// Source-of-truth: `ailang_kernel::STUB_AIL`. The stub /// ratifies the end-to-end kernel-tier path: `Module.kernel`, /// `TypeDef.param-in`, and auto-import without `(import …)`. /// /// Panics on parse failure — the stub is build-time-validated by /// every drift test run. pub fn parse_kernel_stub() -> Module { - crate::parse(ailang_kernel_stub::STUB_AIL) - .expect("ailang_kernel_stub::STUB_AIL must parse as a Module") + crate::parse(ailang_kernel::STUB_AIL) + .expect("ailang_kernel::STUB_AIL must parse as a Module") } fn is_ail_source(path: &Path) -> bool { diff --git a/design/INDEX.md b/design/INDEX.md index 328b143..24c2321 100644 --- a/design/INDEX.md +++ b/design/INDEX.md @@ -109,4 +109,4 @@ is the default. | authoring-surface | onboarding / evolves | design/models/0001-authoring-surface.md | | prose-projection | onboarding / evolves | design/models/0006-prose-projection.md | | pipeline | onboarding / evolves | design/models/0003-pipeline.md | -| kernel-extensions | onboarding / evolves (mechanisms milestone closed 2026-05-28; ratified end-to-end by the `ailang-kernel-stub` fixture, planned for retirement when raw-buf lands a real second consumer; raw-buf and series milestones pending) | design/models/0007-kernel-extensions.md | +| kernel-extensions | onboarding / evolves (mechanisms milestone closed 2026-05-28; ratified end-to-end by the `ailang-kernel/src/kernel_stub` fixture, planned for retirement when raw-buf lands a real second consumer; raw-buf and series milestones pending) | design/models/0007-kernel-extensions.md | diff --git a/design/models/0007-kernel-extensions.md b/design/models/0007-kernel-extensions.md index fb344be..36690dd 100644 --- a/design/models/0007-kernel-extensions.md +++ b/design/models/0007-kernel-extensions.md @@ -4,8 +4,8 @@ (`kernel-extension-mechanics`; iterations prep.1, prep.2, prep.3 landed). The four language-level mechanisms — type-scoped namespacing, `Term::New`, kernel-tier modules + auto-import, and -`param-in` — are shipped and ratified by the stub kernel crate -(`crates/ailang-kernel-stub/`). The base-extension and library- +`param-in` — are shipped and ratified by the stub kernel module +(`crates/ailang-kernel/src/kernel_stub/`). The base-extension and library- extension milestones (`raw-buf`, `series`) are pending. This whitepaper describes the design as a coherent whole; the per-milestone specs in `docs/specs/` carry the implementation- @@ -232,7 +232,7 @@ free fns (see `examples/prelude.ail:85-148`) remain callable bare in every consumer module — ratified by `crates/ail/tests/prelude_free_fns.rs` across the code-path migration. The ratifying stub kernel module -(`crates/ailang-kernel-stub/`) and any future kernel-tier +(`crates/ailang-kernel/src/kernel_stub/`) and any future kernel-tier consumers (Series, Matrix) auto-import through the same filter. Class-method dispatch (a separate mechanism — see