Adding a New AST Node
Follow this workflow when adding a new AST node type to the compiler:
Steps
- •
Define the type in
crates/beamtalk-core/src/ast.rs- •Add the new variant to the appropriate enum (e.g.,
ExpressionKind,StatementKind) - •Include a
Spanfield for source location - •Derive required traits:
Debug,Clone,PartialEq
- •Add the new variant to the appropriate enum (e.g.,
- •
Add parsing in
crates/beamtalk-core/src/parse/- •Add token recognition in the lexer if new tokens are needed
- •Implement parsing logic in the parser
- •Handle error recovery gracefully
- •
Add type checking in
analyse.rs(if needed)- •Add type inference rules
- •Add validation for semantic correctness
- •
Add Core Erlang generation in
erlang.rs- •Implement the codegen for the new node
- •Use fully qualified calls:
'erlang':'function' - •Generate unique variable names to avoid shadowing
- •
Add snapshot tests in
test-package-compiler/cases/- •Create a new
.btfile with example usage - •Run
just test-rustto generate snapshots - •Review and accept snapshots with
cargo insta review
- •Create a new
Key Requirements
- •AST nodes MUST carry source location (
Span) - no exceptions - •Parser MUST produce an AST even with syntax errors (error recovery)
- •Never panic on malformed input
- •Use
instafor snapshot testing of parser output and codegen
Example
rust
// In ast.rs
pub enum ExpressionKind {
// ... existing variants ...
NewFeature {
param: Box<Expression>,
body: Box<Expression>,
},
}
// In parser
fn parse_new_feature(&mut self) -> Result<Expression, ParseError> {
let start = self.current_span();
// ... parsing logic ...
Ok(Expression {
kind: ExpressionKind::NewFeature { param, body },
span: start.merge(end),
})
}