← board

Rust frontend — umbrella

North star (2026-07-09): the own-written chess engine

Track R now has a real-world target: [[feature-rust-corpus-chess]] — the user's ~6k-line idiomatic chess engine, with perft as a differential oracle against cargo. The remaining sub-tickets below stay X-tagged, but that ticket orders them by what the engine actually needs (stage plan there); pick work from its ladder, not from spec-completeness.

Motivation

Add a Rust-syntax frontend (4th, after Pascal/Nil-Python/C) lowering to the existing shared IR/backends, same shape as the C frontend's v80 bring-up (clexer.inc/cparser.inc/cpreproc.inc → shared IR). Real-world target used to scope this: ~/nextlevel (chess engine, ~6.1k LOC own code) + its 3 crates.io dependencies (shakmaty 16.2k LOC, shakmaty-syzygy 4.0k LOC, arrayvec) — confirmed via Cargo.lock source = "registry+...", not vendored. Dependency source is ~3.3x the app's own code and exercises harder features (generics+bounds, lifetimes, macro_rules!, dyn Trait, unsafe/MaybeUninit) more than the app itself does.

Explicit non-goals (decided up front, mirrors the borrow-checker precedent)

What already exists to reuse (confirmed by reading the tree, not assumed)

Sub-tickets

Track A (compiler internals — shared AST/IR/symtab/backends):

  1. [[feature-rust-frontend-skeleton]] — rlexer.inc/rparser.inc, entry point, minimal expr/stmt subset. Unlocks everything else.
  2. [[feature-rust-match-enum-payload]] — pattern-bind match + generalized tagged union (beyond tyVariant's 16 bytes).
  3. [[feature-rust-generics-trait-bounds]] — trait-bound checking on top of existing monomorphization.
  4. [[feature-rust-dyn-trait-dispatch]] — vtable dispatch decoupled from class hierarchy (trait-impl-for-any-type).
  5. [[feature-rust-drop-move-tracking]] — scope-exit destructor insertion + move-flag tracking. The correctness-sensitive one: wrong = silent double-free, not a compile error.
  6. [[feature-rust-derive-macros]] — synthesize Clone/Copy/Debug/ Default/PartialEq/Eq bodies from field lists.
  7. [[feature-rust-macro-rules]] — macro_rules! scope cut (builtins as intrinsics first; full token-tree/hygiene engine deferred).
  8. [[feature-rust-borrowed-slice-type]] — &[T]/&str-for-any-T: a non-owning ptr+len view distinct from owning dynarray/AnsiString.
  9. [[feature-rust-misc-semantics]] — integer overflow mode (panic-on-debug/wrap-on-release flag) + {}/{:?} format-string mini-parser (backs println!/format!).

Track B (lib/rtl, lib/pcl):

  1. [[feature-rust-rtl-core-types]] — Option<T>/Result<T,E>/Box<T>/ Vec<T> as thin RTL wrappers over existing tagged-union/heap/dynarray machinery (depends on #2 for the tagged-union half).
  2. [[feature-rust-rtl-concurrency]] — std::thread::spawn/JoinHandle<T>/ mpsc::channel/AtomicBool/AtomicU64 shims over palthreadobj.pas/channel.pas/__pxxatomic_*. Pure API-shape wrapper, no new primitive.
  3. [[feature-rust-rtl-macros-io]] — println!/format!/vec!/assert!/ panic! intrinsics wired to #9's format parser + existing Halt/ exception machinery.

Notes on scale (calibration, not a promise)

The C frontend went from v80 merge to lua-running-libc-free maturity over dozens of incremental sessions (see project_c_lua_bringup* memory chain). A Rust subset of this shape (no async-ecosystem-compat, no full macro_rules! hygiene, no dyn-object-safety edge cases) is comparably sized — no single sub-ticket above is a research problem, but the sum is a multi-week project, not a multi-day one. #1 gates everything; #5 is the one that must be correct on first landing (silent-corruption risk, not a compile-error risk).

Log