Files
zern/src/parser.rs
2025-05-30 22:20:42 +02:00

434 lines
12 KiB
Rust

use std::error::Error;
use crate::tokenizer::{MotError, Token, TokenType, error};
#[derive(Debug, Clone)]
pub struct Param {
var_type: Token,
var_name: Token,
}
#[derive(Debug, Clone)]
pub enum Stmt {
Expression(Expr),
Var {
name: Token,
var_type: Token,
initializer: Expr,
},
Block(Vec<Stmt>),
If {
condition: Expr,
then_branch: Box<Stmt>,
else_branch: Box<Stmt>,
},
While {
condition: Expr,
body: Box<Stmt>,
},
Function {
name: Token,
params: Vec<Param>,
body: Box<Stmt>,
},
Return(Expr),
}
#[derive(Debug, Clone)]
pub enum Expr {
Binary {
left: Box<Expr>,
op: Token,
right: Box<Expr>,
},
Grouping(Box<Expr>),
Literal(Token),
Unary {
op: Token,
right: Box<Expr>,
},
Variable(Token),
Assign {
name: Token,
value: Box<Expr>,
},
Call {
callee: Box<Expr>,
paren: Token,
args: Vec<Expr>,
},
}
pub struct Parser {
tokens: Vec<Token>,
current: usize,
}
impl Parser {
pub fn new(tokens: Vec<Token>) -> Parser {
Parser { tokens, current: 0 }
}
pub fn parse(mut self) -> Result<Vec<Stmt>, Box<dyn Error>> {
let mut statements = vec![];
while !self.eof() {
statements.push(self.declaration()?);
}
Ok(statements)
}
fn declaration(&mut self) -> Result<Stmt, Box<dyn Error>> {
// TODO: synchronization after parse error
if self.match_token(&[TokenType::KeywordLet]) {
self.let_declaration()
} else if self.match_token(&[TokenType::KeywordFunc]) {
self.func_declaration()
} else {
self.statement()
}
}
// TOOD: parse return type
fn func_declaration(&mut self) -> Result<Stmt, Box<dyn Error>> {
let name = self.consume(TokenType::Identifier, "expected function name")?;
self.consume(TokenType::LeftBracket, "expected '[' after function name")?;
let mut params = vec![];
if !self.check(&TokenType::RightBracket) {
loop {
let var_name = self.consume(TokenType::Identifier, "expected parameter name")?;
self.consume(TokenType::Colon, "expected ':' after parameter name")?;
let var_type = self.consume(TokenType::Identifier, "expected parameter type")?;
params.push(Param { var_type, var_name });
if !self.match_token(&[TokenType::Comma]) {
break;
}
}
}
self.consume(TokenType::RightBracket, "expected ']' after arguments")?;
let body = Box::new(self.block()?);
Ok(Stmt::Function { name, params, body })
}
fn let_declaration(&mut self) -> Result<Stmt, Box<dyn Error>> {
let name = self.consume(TokenType::Identifier, "expected variable name")?;
self.consume(TokenType::Colon, "expected ':' after variable name")?;
let var_type = self.consume(TokenType::Identifier, "expected variable type")?;
self.consume(TokenType::Equal, "expected '=' after variable type")?;
let initializer = self.expression()?;
Ok(Stmt::Var {
name,
var_type,
initializer,
})
}
fn block(&mut self) -> Result<Stmt, Box<dyn Error>> {
self.consume(TokenType::Indent, "expected an indent")?;
let mut statements = vec![];
while !self.eof() && !self.match_token(&[TokenType::Dedent]) {
statements.push(self.declaration()?);
}
Ok(Stmt::Block(statements))
}
fn statement(&mut self) -> Result<Stmt, Box<dyn Error>> {
if self.match_token(&[TokenType::KeywordIf]) {
self.if_statement()
} else if self.match_token(&[TokenType::KeywordWhile]) {
self.while_statement()
} else if self.match_token(&[TokenType::KeywordReturn]) {
self.return_statement()
} else {
Ok(Stmt::Expression(self.expression()?))
}
}
fn return_statement(&mut self) -> Result<Stmt, Box<dyn Error>> {
Ok(Stmt::Return(self.expression()?))
}
fn if_statement(&mut self) -> Result<Stmt, Box<dyn Error>> {
let condition = self.expression()?;
let then_branch = self.block()?;
let else_branch = if self.match_token(&[TokenType::KeywordElse]) {
if self.match_token(&[TokenType::KeywordIf]) {
Box::new(self.if_statement()?)
} else {
Box::new(self.block()?)
}
} else {
Box::new(Stmt::Block(vec![]))
};
Ok(Stmt::If {
condition,
then_branch: Box::new(then_branch),
else_branch,
})
}
fn while_statement(&mut self) -> Result<Stmt, Box<dyn Error>> {
let condition = self.expression()?;
let body = self.block()?;
Ok(Stmt::While {
condition,
body: Box::new(body),
})
}
fn expression(&mut self) -> Result<Expr, Box<dyn Error>> {
self.assignment()
}
fn assignment(&mut self) -> Result<Expr, Box<dyn Error>> {
let expr = self.pipe()?;
if self.match_token(&[TokenType::Equal]) {
let equals = self.previous().clone();
let value = self.assignment()?;
return match expr {
Expr::Variable(name) => Ok(Expr::Assign {
name,
value: Box::new(value),
}),
_ => return error!(equals.loc, "invalid assignment target"),
};
}
Ok(expr)
}
fn pipe(&mut self) -> Result<Expr, Box<dyn Error>> {
let mut expr = self.logical_or()?;
while self.match_token(&[TokenType::Pipe]) {
let pipe = self.previous().clone();
let right = self.equality()?;
match right {
Expr::Call {
callee,
paren,
args,
} => {
let mut new_args = args;
new_args.insert(0, expr);
expr = Expr::Call {
callee,
paren,
args: new_args,
}
}
_ => {
return error!(pipe.loc, "tried to pipe into a non-call expression");
}
};
}
Ok(expr)
}
fn logical_or(&mut self) -> Result<Expr, Box<dyn Error>> {
let mut expr = self.logical_and()?;
while self.match_token(&[TokenType::Or]) {
let op = self.previous().clone();
let right = self.logical_and()?;
expr = Expr::Binary {
left: Box::new(expr),
op,
right: Box::new(right),
}
}
Ok(expr)
}
fn logical_and(&mut self) -> Result<Expr, Box<dyn Error>> {
let mut expr = self.equality()?;
while self.match_token(&[TokenType::And]) {
let op = self.previous().clone();
let right = self.equality()?;
expr = Expr::Binary {
left: Box::new(expr),
op,
right: Box::new(right),
}
}
Ok(expr)
}
fn equality(&mut self) -> Result<Expr, Box<dyn Error>> {
let mut expr = self.comparison()?;
while self.match_token(&[TokenType::DoubleEqual, TokenType::NotEqual]) {
let op = self.previous().clone();
let right = self.comparison()?;
expr = Expr::Binary {
left: Box::new(expr),
op,
right: Box::new(right),
}
}
Ok(expr)
}
fn comparison(&mut self) -> Result<Expr, Box<dyn Error>> {
let mut expr = self.term()?;
while self.match_token(&[
TokenType::Greater,
TokenType::GreaterEqual,
TokenType::LessEqual,
TokenType::Less,
]) {
let op = self.previous().clone();
let right = self.term()?;
expr = Expr::Binary {
left: Box::new(expr),
op,
right: Box::new(right),
}
}
Ok(expr)
}
fn term(&mut self) -> Result<Expr, Box<dyn Error>> {
let mut expr = self.factor()?;
while self.match_token(&[TokenType::Plus, TokenType::Minus, TokenType::Xor]) {
let op = self.previous().clone();
let right = self.factor()?;
expr = Expr::Binary {
left: Box::new(expr),
op,
right: Box::new(right),
}
}
Ok(expr)
}
fn factor(&mut self) -> Result<Expr, Box<dyn Error>> {
let mut expr = self.unary()?;
while self.match_token(&[TokenType::Star, TokenType::Slash, TokenType::Mod]) {
let op = self.previous().clone();
let right = self.unary()?;
expr = Expr::Binary {
left: Box::new(expr),
op,
right: Box::new(right),
}
}
Ok(expr)
}
fn unary(&mut self) -> Result<Expr, Box<dyn Error>> {
if self.match_token(&[TokenType::Bang, TokenType::Minus]) {
let op = self.previous().clone();
let right = self.unary()?;
return Ok(Expr::Unary {
op,
right: Box::new(right),
});
}
self.call()
}
fn call(&mut self) -> Result<Expr, Box<dyn Error>> {
let mut expr = self.primary()?;
while self.match_token(&[TokenType::LeftParen]) {
let mut args = vec![];
if !self.check(&TokenType::RightParen) {
loop {
args.push(self.expression()?);
if !self.match_token(&[TokenType::Comma]) {
break;
}
}
}
let paren = self.consume(TokenType::RightParen, "expected ')' after arguments")?;
expr = Expr::Call {
callee: Box::new(expr),
paren,
args,
};
}
Ok(expr)
}
fn primary(&mut self) -> Result<Expr, Box<dyn Error>> {
if self.match_token(&[TokenType::Number, TokenType::String]) {
Ok(Expr::Literal(self.previous().clone()))
} else if self.match_token(&[TokenType::LeftParen]) {
let expr = self.expression()?;
self.consume(TokenType::RightParen, "expected ')' after expression")?;
Ok(Expr::Grouping(Box::new(expr)))
} else if self.match_token(&[TokenType::Identifier]) {
Ok(Expr::Variable(self.previous().clone()))
} else {
error!(self.peek().loc, "expected expression")
}
}
fn consume(&mut self, token_type: TokenType, message: &str) -> Result<Token, Box<dyn Error>> {
if self.check(&token_type) {
Ok(self.advance().clone())
} else {
error!(self.previous().loc, format!("{}", message))
}
}
fn match_token(&mut self, token_types: &[TokenType]) -> bool {
for x in token_types {
if self.check(x) {
self.advance();
return true;
}
}
false
}
fn check(&self, token_type: &TokenType) -> bool {
if self.eof() {
false
} else {
self.peek().token_type == *token_type
}
}
fn advance(&mut self) -> &Token {
if !self.eof() {
self.current += 1;
}
self.previous()
}
fn peek(&self) -> &Token {
&self.tokens[self.current]
}
fn previous(&self) -> &Token {
&self.tokens[self.current - 1]
}
fn eof(&self) -> bool {
self.peek().token_type == TokenType::Eof
}
}