Milestone 1 — Smallest End-to-End Compiler (specification)
Status: M0 proposal (master prompt §23.L). Starts after OD-1/2/5/6/11 are approved.
1. Language subset ("Nova-M1")
- Types: all fixed-width integers (
i8–i64,u8–u64,isize,usize),bool,void. No floats in M1 (keeps the kernel subset in reach and avoids float formatting). The full static semantics are intype-system.md. - Declarations: one file or a few files in one package.
namespace, top-levelfn(includingpublic/internal),let,var, optional type annotations,constinteger constants. - Statements: blocks,
if/else,while,loop,break,continue,return, expression statements, assignment and compound assignment (+= -= *= /= %=). - Expressions: literals, names, calls (including recursion), unary
- !, binary+ - * / % == != < <= > >= && ||(short-circuit),& | ^ << >>on unsigned types, losslessas,truncate<T>(x), parentheses. - Built-ins:
Console.write(x)/Console.writeLine(x)for integer,booland string literals only.Process.exit(code: i32). - Semantics: overflow, division and shift checks panic (OD-6). Panic = message + abort (OD-5). Definite initialisation of
var(the M2 init analysis restricted to scalars). Strict left-to-right evaluation.main() -> i32ormain() -> void. - Excluded: structs, arrays, references, heap, strings as values, generics, imports across packages.
2. Pipeline delivered
Lexer → Parser (with recovery) → AST → name resolution → type check → HIR → NIR (CFG, with CheckedBinOp and Panic terminators) → LIR → C emitter (labelled blocks) → host C compiler → executable. The full IR stack exists from M1, so M2 adds analyses, not a new pipeline.
Runtime: runtime/include/nova/rt.h (types, checked arithmetic, nova_panic declaration), runtime/hosted/rt_hosted.c (stdio + abort), runtime/cosmoos/user/rt_cosmoos_user.c (write(1, …), abort).
3. Acceptance criteria
- Corpus: ≥ 150 tests in total: ≥ 40 parse-pass/fail (including the full precedence table and recovery cases), ≥ 40 check-fail (types, names, definite init, lossy
as, literal out of range), ≥ 50 run-pass (includinggcd, recursivefib, Collatz, integerisqrt, an FNV-1a hash of constant input, nested loops withbreak/continue), ≥ 15 run-fail (each overflow, division, shift andMIN/-1case with the expected exit status and message). - C quality: all generated C compiles with
-std=c11 -Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wsign-conversion -Wmissing-prototypes -Wstrict-prototypes -Wvla -Wcast-qual -Wundef -Werroron clang and gcc. - Differential: every run-pass test gives identical output under {clang, gcc} × {-O0, -O2} × {no sanitizer, ASan+UBSan} on the macOS (arm64) dev host. Linux x86-64 runs in CI.
- Cross-compile: the corpus compiles for
x86_64-unknown-none-elfandaarch64-unknown-none-elfwith CosmoOSUSER_CFLAGS(compile only; linking is C1). - Determinism: compiling the corpus twice gives byte-identical C. Output is independent of the host path.
- Diagnostics: every check-fail test asserts the error code and primary span.
- Docs:
grammar.md(complete for Nova-M1),intermediate-representation.md(HIR/NIR/LIR as implemented),diagnostics.md,testing.mdupdated. Limitations listed.
C1 then reuses the M1 compiler unchanged: hello.nova prints NOVATEST: PASS inside CosmoOS on both arches (roadmap.md).
4. The exact first implementation increment (1a) — done 2026-10-22
Delivered: Nova.slnx (the .NET 10 solution format) with Nova.Compiler, Nova.Cli (novac) and Nova.Compiler.Tests; docs/grammar.md; docs/diagnostics.md; 151 passing tests (see testing.md §4). Deviation from the plan: the corpus runner lives inside the xUnit project for now. A separate Nova.TestRunner is deferred to 1c, when tests need to invoke C compilers. Trivia (comments) is not retained yet; it is needed only for the M10 formatter.
Original plan:
Nova.slnwithNova.Compiler,Nova.Cli,Nova.Compiler.Tests,Nova.TestRunner.Directory.Build.props: nullable enabled, warnings as errors,<Deterministic>true</Deterministic>.global.jsonpinned to SDK 10.0.401.SourceText,Span,Diagnosticand a text renderer.- Lexer for the full M1 token set: struct tokens, interned identifiers, literal validation, and keyword table with reserved words.
- Parser: recursive descent for declarations and statements, Pratt parsing for expressions, recovery at
;/}/declaration keywords. AST plus a--dump-astprinter. - Corpus runner for
parse-pass/parse-failwith// error: N0xxxannotations. The first ~40 parser tests.
Exit criterion for 1a: parser tests green, AST dumps stable.
Increment 1b — done 2026-10-22. type-system.md (spec first), then:
- the type checker with bidirectional literal typing;
- constant folding with cycle detection (
IntegerSemanticsdefines the exact operator semantics that 1c's C runtime must match); - definite assignment and missing-return analysis on structured HIR;
- the HIR printer and
novac check [--dump-hir].
Semantic analysis runs only on files that parsed cleanly. Two simplifications, both documented: the flow analysis runs on HIR, not NIR (no moves exist yet, so no fixpoint is needed), and all files of a compilation share one item scope.
Increment 1c — done 2026-10-22.
intermediate-representation.md(spec first).- NIR (CFG) and the HIR→NIR lowering, with explicit evaluation order and short-circuit branches.
- The C emitter: labelled blocks, checked helpers, zero-initialised locals, deterministic output.
- The runtime:
nova/rt.h(freestanding helpers),nova_rt_core.c(formatting, panics) andnova_rt_hosted.c(stdio). They are embedded in the compiler and written next to the generated C. novac build [--emit c|exe] [--dump-nir].- Tests: run-pass/run-fail corpora, the runtime agreement harness, determinism, C snapshots and freestanding cross-compiles.
Deviation: no separate LIR yet (intermediate-representation.md §4).
Acceptance status (§3), 2026-10-22:
| # | Criterion | Status |
|---|---|---|
| 1 | Corpus ≥ 40 parse, ≥ 40 check-fail, ≥ 50 run-pass, ≥ 15 run-fail | met: 38 files / 72 cases, 19 files / 99 cases, 51, 19 |
| 2 | Generated C warning-free under the strict set on clang and gcc | met: Apple clang 21 locally, plus clang 18 and GCC 13.3 on Linux CI (run 39792099920: every run test passed under GCC) |
| 3 | Differential: {clang, gcc} × {-O0, -O2} × {plain, ASan+UBSan} agree | met, with one difference: ASan+UBSan runs with clang only. The GCC configurations are -O0, -O2 and portable-overflow |
| 4 | Corpus compiles for both CosmoOS triples with CosmoOS USER_CFLAGS | met, and exceeded: all 70 run programs compile with the exact flags, link against CosmoOS libc, and run correctly inside CosmoOS on x86-64 and AArch64 (cosmoos/c1-report.md) |
| 5 | Determinism | met (byte-identical C, no host paths) |
| 6 | Diagnostics tests assert code and position | met (line, and column where annotated) |
| 7 | Docs | met: grammar, type-system, IR, diagnostics, testing |
Increment 1d — done 2026-10-22.
- C1 on both architectures, plus the whole run corpus inside CosmoOS (
cosmoos/c1-report.md). - Linux CI (
.github/workflows/ci.yml) with GCC 13 and clang 18. - GCC's
-Wclobberedfired on the runtime harness's setjmp use; it is now disabled for that harness only.
Milestone 1 is complete (all criteria in §3 met). 1b (resolution + types + HIR), 1c (NIR + LIR + C + runtime + run tests) and 1d (C1 script) follow.