use crate::tokenizer::{Token, TokenType, ZernError, error}; #[derive(Debug, Clone)] pub struct Param { pub var_type: Token, pub var_name: Token, } #[derive(Debug, Clone)] pub enum Stmt { Expression(Expr), Let { name: Token, var_type: Option, initializer: Expr, }, Const { name: Token, value: Token, }, Block(Vec), If { condition: Expr, then_branch: Box, else_branch: Box, }, While { condition: Expr, body: Box, }, For { var: Token, start: Expr, end: Expr, body: Box, }, Function { name: Token, params: Vec, return_type: Token, body: Box, exported: bool, }, Return(Expr), Break, Continue, Extern(Token), Struct { name: Token, fields: Vec, }, } #[derive(Debug, Clone)] pub enum Expr { Binary { left: Box, op: Token, right: Box, }, Logical { left: Box, op: Token, right: Box, }, Grouping(Box), Literal(Token), Unary { op: Token, right: Box, }, Variable(Token), Assign { left: Box, op: Token, value: Box, }, Call { callee: Box, paren: Token, args: Vec, }, ArrayLiteral(Vec), Index { expr: Box, index: Box, }, AddrOf { op: Token, expr: Box, }, New(Token), MemberAccess { left: Box, field: Token, }, } pub struct Parser { tokens: Vec, current: usize, is_inside_function: bool, } impl Parser { pub fn new(tokens: Vec) -> Parser { Parser { tokens, current: 0, is_inside_function: false, } } pub fn parse(mut self) -> Result, ZernError> { let mut statements = vec![]; while !self.eof() { statements.push(self.declaration()?); } Ok(statements) } fn declaration(&mut self) -> Result { if !self.is_inside_function { if self.match_token(&[TokenType::KeywordFunc]) { return self.func_declaration(false); } if self.match_token(&[TokenType::KeywordExport]) { self.consume(TokenType::KeywordFunc, "expected 'func' after 'export'")?; return self.func_declaration(true); } if self.match_token(&[TokenType::KeywordExtern]) { return self.extern_declaration(); } if self.match_token(&[TokenType::KeywordConst]) { return self.const_declaration(); } if self.match_token(&[TokenType::KeywordStruct]) { return self.struct_declaration(); } return error!( self.peek().loc, "statements not allowed outside function body" ); } if self.match_token(&[TokenType::KeywordLet]) { self.let_declaration() } else { self.statement() } } fn func_declaration(&mut self, exported: bool) -> Result { 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")?; self.consume(TokenType::Colon, "expected ':' after '['")?; let return_type = self.consume(TokenType::Identifier, "expected return type")?; self.is_inside_function = true; let body = Box::new(self.block()?); self.is_inside_function = false; Ok(Stmt::Function { name, params, return_type, body, exported, }) } fn struct_declaration(&mut self) -> Result { let name = self.consume(TokenType::Identifier, "expected struct name")?; self.consume(TokenType::Indent, "expected indent after struct name")?; let mut fields = vec![]; while !self.eof() && !self.check(&TokenType::Dedent) { let var_name = self.consume(TokenType::Identifier, "expected field name")?; self.consume(TokenType::Colon, "expected ':' after field name")?; let var_type = self.consume(TokenType::Identifier, "expected field type")?; fields.push(Param { var_type, var_name }); } self.consume(TokenType::Dedent, "expected dedent after the struct fields")?; Ok(Stmt::Struct { name, fields }) } fn let_declaration(&mut self) -> Result { let name = self.consume(TokenType::Identifier, "expected variable name")?; let var_type = if self.match_token(&[TokenType::Colon]) { let token = self.consume(TokenType::Identifier, "expected variable type")?; Some(token) } else { None }; self.consume(TokenType::Equal, "expected '=' after variable type")?; let initializer = self.expression()?; Ok(Stmt::Let { name, var_type, initializer, }) } fn const_declaration(&mut self) -> Result { let name = self.consume(TokenType::Identifier, "expected const name")?; self.consume(TokenType::Equal, "expected '=' after const name")?; let value = self.consume(TokenType::Number, "expected a number after '='")?; Ok(Stmt::Const { name, value }) } fn extern_declaration(&mut self) -> Result { Ok(Stmt::Extern( self.consume(TokenType::Identifier, "expected extern name")?, )) } fn block(&mut self) -> Result { 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 { 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::KeywordFor]) { self.for_statement() } else if self.match_token(&[TokenType::KeywordReturn]) { Ok(Stmt::Return(self.expression()?)) } else if self.match_token(&[TokenType::KeywordBreak]) { Ok(Stmt::Break) } else if self.match_token(&[TokenType::KeywordContinue]) { Ok(Stmt::Continue) } else { Ok(Stmt::Expression(self.expression()?)) } } fn if_statement(&mut self) -> Result { 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 { let condition = self.expression()?; let body = self.block()?; Ok(Stmt::While { condition, body: Box::new(body), }) } fn for_statement(&mut self) -> Result { let var = self.consume(TokenType::Identifier, "expected variable name after 'for'")?; self.consume(TokenType::KeywordIn, "expected 'in' after variable name")?; let start = self.expression()?; self.consume(TokenType::DoubleDot, "expected '..' after the number")?; let end = self.expression()?; let body = self.block()?; Ok(Stmt::For { var, start, end, body: Box::new(body), }) } fn expression(&mut self) -> Result { self.assignment() } fn assignment(&mut self) -> Result { let expr = self.pipe()?; if self.match_token(&[TokenType::Equal]) { let equals = self.previous().clone(); let value = self.assignment()?; return Ok(Expr::Assign { left: Box::new(expr), op: equals, value: Box::new(value), }); } Ok(expr) } fn pipe(&mut self) -> Result { let mut expr = self.or_and()?; 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 or_and(&mut self) -> Result { let mut expr = self.equality()?; while self.match_token(&[TokenType::LogicalOr, TokenType::LogicalAnd]) { let op = self.previous().clone(); let right = self.equality()?; expr = Expr::Logical { left: Box::new(expr), op, right: Box::new(right), } } Ok(expr) } fn equality(&mut self) -> Result { 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 { 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 { let mut expr = self.factor()?; while self.match_token(&[ TokenType::Plus, TokenType::Minus, TokenType::Xor, TokenType::BitAnd, TokenType::BitOr, ]) { 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 { let mut expr = self.unary()?; while self.match_token(&[ TokenType::Star, TokenType::Slash, TokenType::Mod, TokenType::ShiftLeft, TokenType::ShiftRight, ]) { 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 { if self.match_token(&[TokenType::Xor]) { let op = self.previous().clone(); let right = self.unary()?; return Ok(Expr::AddrOf { op, expr: Box::new(right), }); } 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 { let mut expr = self.primary()?; loop { if 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, }; } else if self.match_token(&[TokenType::LeftBracket]) { let index = self.expression()?; self.consume(TokenType::RightBracket, "expected ']' after index")?; expr = Expr::Index { expr: Box::new(expr), index: Box::new(index), } } else if self.match_token(&[TokenType::Arrow]) { let field = self.consume(TokenType::Identifier, "expected field name after '->'")?; expr = Expr::MemberAccess { left: Box::new(expr), field, }; } else { break; } } Ok(expr) } fn primary(&mut self) -> Result { if self.match_token(&[ TokenType::Number, TokenType::Char, TokenType::String, TokenType::True, TokenType::False, ]) { 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::LeftBracket]) { let mut xs = vec![]; if !self.check(&TokenType::RightBracket) { loop { xs.push(self.expression()?); if !self.match_token(&[TokenType::Comma]) { break; } } } self.consume(TokenType::RightBracket, "expected ']' after values")?; Ok(Expr::ArrayLiteral(xs)) } else if self.match_token(&[TokenType::KeywordNew]) { let struct_name = self.consume(TokenType::Identifier, "expected struct name after 'new'")?; Ok(Expr::New(struct_name)) } else if self.match_token(&[TokenType::Identifier]) { Ok(Expr::Variable(self.previous().clone())) } else { error!( self.peek().loc, format!("expected expression, got '{}'", self.peek().lexeme) ) } } fn consume(&mut self, token_type: TokenType, message: &str) -> Result { if self.check(&token_type) { self.current += 1; Ok(self.previous().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.current += 1; return true; } } false } fn check(&self, token_type: &TokenType) -> bool { if self.eof() { false } else { self.peek().token_type == *token_type } } 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 } }