///| Parser for expr_lang
///|
/// Parser state
pub struct Parser {
tokens : Array[Token]
mut pos : Int
builder : @cst.GreenNodeBuilder
}
///|
pub fn Parser::new(tokens : Array[Token]) -> Parser {
Parser::{ tokens, pos: 0, builder: @cst.GreenNodeBuilder::new() }
}
///|
/// Peek current token
fn Parser::peek(self : Parser) -> Token {
if self.pos >= self.tokens.length() {
Token::new(eof(), "")
} else {
self.tokens[self.pos]
}
}
///|
/// Peek token kind
fn Parser::peek_kind(self : Parser) -> @cst.SyntaxKind {
self.peek().kind()
}
///|
/// Check if at a specific kind
fn Parser::at(self : Parser, kind : @cst.SyntaxKind) -> Bool {
self.peek_kind() == kind
}
///|
/// Advance and emit current token
fn Parser::bump(self : Parser) -> Unit {
let tok = self.peek()
self.builder.token(tok.kind(), tok.text())
self.pos += 1
}
///|
/// Skip whitespace tokens
fn Parser::skip_trivia(self : Parser) -> Unit {
while is_trivia(self.peek_kind()) {
self.bump()
}
}
///|
/// Expect and consume a specific token kind
fn Parser::expect(self : Parser, kind : @cst.SyntaxKind) -> Unit {
self.skip_trivia()
if self.at(kind) {
self.bump()
} else {
// Emit error token
self.builder.token(error_kind(), "")
}
}
///|
/// Parse source file
pub fn Parser::parse(self : Parser) -> @cst.GreenNode {
self.builder.start_node(source_file())
while !self.at(eof()) {
self.skip_trivia()
if self.at(eof()) {
break
}
self.parse_stmt()
}
self.builder.finish_node()
self.builder.finish()
}
///|
/// Parse a statement
fn Parser::parse_stmt(self : Parser) -> Unit {
self.skip_trivia()
match self.peek_kind() {
k if k == let_kw() => self.parse_let_stmt()
k if k == fn_kw() => self.parse_fn_def()
_ => self.parse_expr_stmt()
}
}
///|
/// Parse let statement: let NAME = expr
fn Parser::parse_let_stmt(self : Parser) -> Unit {
self.builder.start_node(let_stmt())
self.bump() // let
self.skip_trivia()
self.expect(name()) // NAME
self.skip_trivia()
self.expect(eq()) // =
self.skip_trivia()
self.parse_expr()
self.builder.finish_node()
}
///|
/// Parse function definition: fn NAME(params) { expr }
fn Parser::parse_fn_def(self : Parser) -> Unit {
self.builder.start_node(fn_def())
self.bump() // fn
self.skip_trivia()
self.expect(name()) // NAME
self.skip_trivia()
self.expect(lparen()) // (
self.parse_params()
self.expect(rparen()) // )
self.skip_trivia()
self.parse_block()
self.builder.finish_node()
}
///|
/// Parse parameter list
fn Parser::parse_params(self : Parser) -> Unit {
self.builder.start_node(param_list())
self.skip_trivia()
if !self.at(rparen()) {
self.expect(name()) // first param
while ({
self.skip_trivia()
self.at(comma())
}) {
self.bump() // ,
self.skip_trivia()
self.expect(name())
}
}
self.builder.finish_node()
}
///|
/// Parse block: { expr }
fn Parser::parse_block(self : Parser) -> Unit {
self.builder.start_node(block())
self.expect(lbrace()) // {
self.skip_trivia()
if !self.at(rbrace()) {
self.parse_expr()
}
self.skip_trivia()
self.expect(rbrace()) // }
self.builder.finish_node()
}
///|
/// Parse expression statement
fn Parser::parse_expr_stmt(self : Parser) -> Unit {
self.builder.start_node(expr_stmt())
self.parse_expr()
self.builder.finish_node()
}
///|
/// Parse expression (entry point)
fn Parser::parse_expr(self : Parser) -> Unit {
self.parse_add_expr()
}
///|
/// Parse additive expression: mul_expr (('+' | '-') mul_expr)*
fn Parser::parse_add_expr(self : Parser) -> Unit {
let checkpoint = self.builder.checkpoint()
self.parse_mul_expr()
while ({
self.skip_trivia()
self.at(plus()) || self.at(minus())
}) {
self.builder.start_node_at(checkpoint, binary_expr())
self.bump() // + or -
self.skip_trivia()
self.parse_mul_expr()
self.builder.finish_node()
}
}
///|
/// Parse multiplicative expression: call_expr (('*' | '/') call_expr)*
fn Parser::parse_mul_expr(self : Parser) -> Unit {
let checkpoint = self.builder.checkpoint()
self.parse_call_expr()
while ({
self.skip_trivia()
self.at(star()) || self.at(slash())
}) {
self.builder.start_node_at(checkpoint, binary_expr())
self.bump() // * or /
self.skip_trivia()
self.parse_call_expr()
self.builder.finish_node()
}
}
///|
/// Parse call expression: primary_expr ('(' args? ')')?
fn Parser::parse_call_expr(self : Parser) -> Unit {
let checkpoint = self.builder.checkpoint()
self.parse_primary_expr()
self.skip_trivia()
if self.at(lparen()) {
self.builder.start_node_at(checkpoint, call_expr())
self.bump() // (
self.parse_args()
self.expect(rparen()) // )
self.builder.finish_node()
}
}
///|
/// Parse argument list
fn Parser::parse_args(self : Parser) -> Unit {
self.builder.start_node(arg_list())
self.skip_trivia()
if !self.at(rparen()) {
self.parse_expr() // first arg
while ({
self.skip_trivia()
self.at(comma())
}) {
self.bump() // ,
self.skip_trivia()
self.parse_expr()
}
}
self.builder.finish_node()
}
///|
/// Parse primary expression: NAME | NUMBER | '(' expr ')'
fn Parser::parse_primary_expr(self : Parser) -> Unit {
self.skip_trivia()
match self.peek_kind() {
k if k == name() => {
self.builder.start_node(name_ref())
self.bump()
self.builder.finish_node()
}
k if k == number() => {
self.builder.start_node(literal())
self.bump()
self.builder.finish_node()
}
k if k == lparen() => {
self.builder.start_node(paren_expr())
self.bump() // (
self.skip_trivia()
self.parse_expr()
self.skip_trivia()
self.expect(rparen()) // )
self.builder.finish_node()
}
_ => {
// Error recovery: emit error token and skip
self.builder.start_node(literal())
self.builder.token(error_kind(), self.peek().text())
if !self.at(eof()) {
self.pos += 1
}
self.builder.finish_node()
}
}
}
///|
/// Parse input string and return CST
pub fn parse(input : String) -> @cst.SyntaxNode {
let tokens = tokenize(input)
let parser = Parser::new(tokens)
let green = parser.parse()
@cst.SyntaxNode::new_root(green)
}