use std::sync::atomic::{AtomicUsize, Ordering}; use crate::tokenizer::{ Token, TokenType::{self, Identifier}, ZernError, error, }; #[derive(Debug, Clone)] pub struct Param { pub var_type: Token, pub var_name: Token, } #[derive(Debug, Clone)] pub enum Params { Normal(Vec), Variadic, } #[derive(Debug, Clone)] pub enum Stmt { Expression(Expr), Declare { name: Token, var_type: Option, initializer: Expr, }, Assign { left: Expr, op: Token, value: Expr, }, Destructure { targets: Vec, op: Token, value: Expr, }, Const { name: Token, value: Token, neg: bool, }, Block(Vec), If { keyword: Token, condition: Expr, then_branch: Box, else_branch: Box, }, While { keyword: Token, condition: Expr, body: Box, }, For { var: Token, start: Expr, end: Expr, body: Box, }, Function { name: Token, params: Params, return_types: Vec, body: Box, exported: bool, }, Return { keyword: Token, exprs: Vec, }, Break, Continue, Extern(Token), Struct { name: Token, fields: Vec, }, } pub static NEXT_EXPR_ID: AtomicUsize = AtomicUsize::new(0); #[derive(Debug, Clone)] pub struct Expr { pub id: usize, pub kind: ExprKind, } impl Expr { pub fn new(kind: ExprKind) -> Expr { NEXT_EXPR_ID.fetch_add(1, Ordering::SeqCst); Expr { id: NEXT_EXPR_ID.load(Ordering::SeqCst), kind, } } } #[derive(Debug, Clone)] pub enum ExprKind { 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), Call { callee: Box, paren: Token, args: Vec, }, ArrayLiteral(Vec), Index { expr: Box, bracket: Token, index: Box, }, AddrOf { op: Token, expr: Box, }, New { struct_name: Token, use_heap: bool, }, MemberAccess { left: Box, field: Token, }, Cast { expr: Box, type_name: Token, }, MethodCall { expr: Box, method: Token, args: Vec, }, } pub struct Parser { tokens: Vec, current: usize, is_inside_function: bool, depth: usize, } impl Parser { pub fn new(tokens: Vec) -> Parser { Parser { tokens, current: 0, is_inside_function: false, depth: 0, } } 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" ); } 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 is_variadic = false; let mut params = vec![]; if !self.check(&TokenType::RightBracket) { if self.match_token(&[TokenType::DoubleDot]) { is_variadic = true; } else { 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 mut return_types = vec![]; loop { return_types.push(self.consume(TokenType::Identifier, "expected return type")?); if !self.match_token(&[TokenType::Comma]) { break; } } self.is_inside_function = true; let body = Box::new(self.block()?); self.is_inside_function = false; Ok(Stmt::Function { name, params: if is_variadic { Params::Variadic } else { Params::Normal(params) }, return_types, 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 struct fields")?; Ok(Stmt::Struct { name, fields }) } fn const_declaration(&mut self) -> Result { let name = self.consume(TokenType::Identifier, "expected const name")?; self.consume(TokenType::Equal, "expected '=' after const name")?; let neg = self.match_token(&[TokenType::Minus]); let value = self.consume(TokenType::IntLiteral, "expected a number after '='")?; Ok(Stmt::Const { name, value, neg }) } 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.check_ahead(&TokenType::Colon) { let name = self.consume(TokenType::Identifier, "expected variable name")?; self.consume(TokenType::Colon, "expected ':'")?; let var_type = if self.match_token(&[TokenType::Equal]) { None } else { let var_type = self.consume(TokenType::Identifier, "expected variable type")?; self.consume(TokenType::Equal, "expected '=' after varaible type")?; Some(var_type) }; let initializer = self.expression()?; Ok(Stmt::Declare { name, var_type, initializer, }) } else 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]) { let keyword = self.previous().clone(); let mut exprs = vec![]; if !self.check(&TokenType::Dedent) { loop { exprs.push(self.expression()?); if !self.match_token(&[TokenType::Comma]) { break; } } } Ok(Stmt::Return { keyword, exprs }) } else if self.match_token(&[TokenType::KeywordBreak]) { Ok(Stmt::Break) } else if self.match_token(&[TokenType::KeywordContinue]) { Ok(Stmt::Continue) } else if self.match_token(&[TokenType::Tilde]) { let mut targets = vec![]; loop { targets.push(self.consume(Identifier, "expected an identifier")?); if !self.match_token(&[TokenType::Comma]) { break; } } let op = self.consume(TokenType::Colon, "expected ':'")?; self.consume(TokenType::Equal, "expected '=' after ':'")?; let value = self.expression()?; Ok(Stmt::Destructure { targets, op, value }) } else { let expr = self.expression()?; if self.match_token(&[TokenType::Equal]) { let op = self.previous().clone(); let value = self.expression()?; Ok(Stmt::Assign { left: expr, op, value, }) } else if self.match_token(&[TokenType::PlusEqual, TokenType::MinusEqual]) { let op = self.previous().clone(); let right = self.expression()?; let binary_token = Token { token_type: match op.token_type { TokenType::PlusEqual => TokenType::Plus, TokenType::MinusEqual => TokenType::Minus, _ => unreachable!(), }, lexeme: match op.token_type { TokenType::PlusEqual => String::from("+"), TokenType::MinusEqual => String::from("-"), _ => unreachable!(), }, loc: op.loc.clone(), }; Ok(Stmt::Assign { left: expr.clone(), op: Token { token_type: TokenType::Equal, lexeme: String::from("="), loc: op.loc, }, value: Expr::new(ExprKind::Binary { left: Box::new(expr), op: binary_token, right: Box::new(right), }), }) } else { Ok(Stmt::Expression(expr)) } } } fn if_statement(&mut self) -> Result { let keyword = self.previous().clone(); 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 { keyword, condition, then_branch: Box::new(then_branch), else_branch, }) } fn while_statement(&mut self) -> Result { let keyword = self.previous().clone(); let condition = self.expression()?; let body = self.block()?; Ok(Stmt::While { keyword, 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.depth += 1; if self.depth > 200 { return error!(self.previous().loc, "maximum expression depth reached"); } let out = self.or_and(); self.depth -= 1; out } 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::new(ExprKind::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::new(ExprKind::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::new(ExprKind::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::new(ExprKind::Binary { left: Box::new(expr), op, right: Box::new(right), }) } Ok(expr) } fn factor(&mut self) -> Result { let mut expr = self.cast()?; 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::new(ExprKind::Binary { left: Box::new(expr), op, right: Box::new(right), }) } Ok(expr) } fn cast(&mut self) -> Result { let mut expr = self.unary()?; while self.match_token(&[TokenType::KeywordAs]) { let type_name = self.consume(TokenType::Identifier, "expected type after 'as'")?; expr = Expr::new(ExprKind::Cast { expr: Box::new(expr), type_name, }) } 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::new(ExprKind::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::new(ExprKind::Unary { op, right: Box::new(right), })); } self.call() } fn call(&mut self) -> Result { let mut expr = self.primary()?; loop { if self.peek().loc.line != self.previous().loc.line { break; } 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::new(ExprKind::Call { callee: Box::new(expr), paren, args, }) } else if self.match_token(&[TokenType::LeftBracket]) { let index = self.expression()?; let bracket = self.consume(TokenType::RightBracket, "expected ']' after index")?; expr = Expr::new(ExprKind::Index { expr: Box::new(expr), bracket, index: Box::new(index), }) } else if self.match_token(&[TokenType::Arrow]) { if self.check(&TokenType::Identifier) && self.check_ahead(&TokenType::LeftParen) { let method = self.consume(TokenType::Identifier, "expected method name")?; self.consume(TokenType::LeftParen, "expected '('")?; let mut args = vec![]; if !self.check(&TokenType::RightParen) { loop { args.push(self.expression()?); if !self.match_token(&[TokenType::Comma]) { break; } } } self.consume(TokenType::RightParen, "expected ')'")?; expr = Expr::new(ExprKind::MethodCall { expr: Box::new(expr), method, args, }); } else { let field = self.consume(TokenType::Identifier, "expected field name after '->'")?; expr = Expr::new(ExprKind::MemberAccess { left: Box::new(expr), field, }); } } else { break; } } Ok(expr) } fn primary(&mut self) -> Result { if self.match_token(&[ TokenType::IntLiteral, TokenType::FloatLiteral, TokenType::CharLiteral, TokenType::StringLiteral, TokenType::True, TokenType::False, ]) { Ok(Expr::new(ExprKind::Literal(self.previous().clone()))) } else if self.match_token(&[TokenType::LeftParen]) { let expr = self.expression()?; self.consume(TokenType::RightParen, "expected ')' after expression")?; Ok(Expr::new(ExprKind::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::new(ExprKind::ArrayLiteral(xs))) } else if self.match_token(&[TokenType::KeywordNew]) { let use_heap = self.match_token(&[TokenType::Star]); let struct_name = self.consume(TokenType::Identifier, "expected struct name after 'new'")?; Ok(Expr::new(ExprKind::New { struct_name, use_heap, })) } else if self.match_token(&[TokenType::Identifier]) { Ok(Expr::new(ExprKind::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_ahead(&self, token_type: &TokenType) -> bool { if self.current + 1 >= self.tokens.len() { false } else { self.tokens[self.current + 1].token_type == *token_type } } 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 } }