Skip to content

Contributing — parser and HIR

PathRole
crates/vox-compiler/src/lexerTokenization
crates/vox-compiler/src/parserRecursive descent → ast::decl::Module
crates/vox-compiler/src/hir/lowerAST → HirModule
crates/vox-compiler/src/hir/validate.rsStructural invariants
crates/vox-compiler/src/typeckHIR typechecking

When adding new errors to the parser or HIR:

  • Parse errors: Use ParseError (not miette). This ensures errors are mapped correctly to the LSP offsets for real-time editor feedback.
  • Type/HIR errors: Use the Diagnostic struct with the appropriate DiagnosticCategory (typecheck, hir_invariant, etc.).
  • Codegen errors: Use miette.

Not all AST nodes have been fully lowered to strict HIR representations. The legacy_ast_nodes field is a temporary escape hatch.

  • When contributing a new language construct, try to create a dedicated Hir* representation (e.g., HirExpr, HirDecl).
  • If you must use legacy_ast_nodes, you must update the HIR legacy inventory SSOT and include a documented graduation plan to strict HIR.

The parser and HIR modules are historically dense. Watch out for arch/god_object limits (500 lines). Several files in crates/vox-compiler/src/ast/ and crates/vox-compiler/src/parser/ are on the near-threshold watchlist. If your PR pushes a file over 500 lines, you must refactor it into smaller submodules using mod.rs and pub use.

Terminal window
cargo test -p vox-compiler
cargo test -p vox-compiler --test parser_recovery
# Validate against golden examples
cargo test -p vox-compiler --test golden_vox_examples
  • Parser / HIR changes include tests (unit or tests/*.rs).
  • cargo test -p vox-compiler runs completely green.
  • vox corpus eval --mode ast examples/golden/ passes without new failures.
  • New declaration kinds either get a dedicated Hir* vector or land in legacy_ast_nodes only with an inventory update and a graduation plan.
  • The changed files pass vox stub-check with no god-object violations.