elderheim is designed as a multi-frontend compiler with one shared backend.
- The CLI reads a source file and an explicit dialect flag.
- The selected parser frontend lexes and parses that dialect.
- The parser lowers dialect-specific syntax into
elderheim-ast. - Semantic analysis validates labels, control-flow targets, variables, types, scopes, arrays, and runtime calls.
- The Cranelift backend emits native object code.
- In
0.30.0, the experimental text-output linker stage resolves an absolute host C compiler path on Linux/macOS and links the generated object with a bundled elderheim text runtime source written to a temporary file. - Before the supported stable release path, executable generation should move
toward
elderheim-owned linking/runtime packaging so users do not need Rust,rustc, Cargo, a C compiler, or an external linker where platform constraints allow it.
The long-term user contract is one elderheim binary per supported OS and
architecture. Users should be able to run elderheim program.bas and compile
old source code through elderheim itself.
The supported release path should not require users to install Rust, rustc,
Cargo, a C compiler, or an external linker where platform constraints allow it.
The 0.30.0 host C compiler linker is a temporary implementation bridge for
testing the runtime ABI and executable flow, not the final architecture.
elderheim-ast: shared syntax tree and language-neutral node vocabulary.elderheim-parsers: isolated dialect frontends.elderheim-parsers::semantic: first semantic checks over parsed programs.elderheim-codegen: Cranelift object backend and temporary Linux/macOS text executable linker.elderheim: command-line compiler application.
These are local workspace crates. They are not intended for crates.io publishing
while the compiler architecture is still changing; the workspace manifests keep
publish = false.
Keep files small enough to review. lib.rs files should declare modules and
expose stable crate APIs; they should not accumulate compiler implementation
logic.
Language frontends live under:
crates/elderheim-parsers/src/languages/
For example:
crates/elderheim-parsers/src/languages/basic.rs
crates/elderheim-parsers/src/languages/quickbasic.rs
crates/elderheim-parsers/src/languages/pascal.rs
When a frontend grows too large, split it by compiler phase before it becomes a single hard-to-review file:
languages/basic/
├── ast_lowering.rs
├── lexer.rs
├── mod.rs
└── parser.rs
As a rule of thumb, new feature work should split a module before it crosses a few thousand lines or mixes unrelated responsibilities such as lexing, parsing, semantic lowering, diagnostics, runtime modeling, and compatibility fixtures.
No dialect parser may rely on another dialect's syntax rules. A Commodore BASIC parser, for example, should not inherit QuickBASIC behavior accidentally.
The shared AST is the compatibility layer. Dialect-specific syntax such as
PSET, PLOT, or HPLOT should lower into generic semantic operations once
the feature is supported.
Input source files are untrusted. Parser, codegen, and linker paths must avoid panics, unchecked indexing, shell interpolation, path traversal, and implicit execution of generated artifacts.
The compiler must reject unsupported constructs with explicit diagnostics rather than producing silently wrong binaries.