use crate::{ ast::Expr, token::{LiteralType, Token, TokenType}, }; pub struct Parser<'a> { tokens: &'a Vec, current: usize, } #[derive(Debug)] pub struct ParseError { pub token: Token, pub msg: String, } impl Parser<'_> { pub fn new(tokens: &Vec) -> Parser<'_> { Parser { tokens, current: 0 } } pub fn parse(&mut self) -> Result { self.expression() } fn expression(&mut self) -> Result { self.comma() } // Challenge #1. We're writing comma before equality, because it has the lowest precedence // comma -> equality ("," equality)* ; // expression grammar fn comma(&mut self) -> Result { use TokenType::*; self.left_association_binary(&[Comma], Self::ternary) } // ternary -> equality ("?" expression : ternary)? // expression grammar fn ternary(&mut self) -> Result { use TokenType::*; let expr = self.equality()?; if self.match_token(&[Question]) { let first_op = self.previous().clone(); let second = self.expression()?; let second_op = self.consume(Colon, "Expected : after ternary operator ?")?; let third = self.ternary()?; return Ok(Expr::Ternary { first: Box::new(expr), first_op, second: Box::new(second), second_op, third: Box::new(third), }); } Ok(expr) } fn equality(&mut self) -> Result { use TokenType::*; self.left_association_binary(&[BangEqual, EqualEqual], Self::comparison) } fn comparison(&mut self) -> Result { use TokenType::*; self.left_association_binary(&[Greater, GreaterEqual, Less, LessEqual], Self::term) } fn term(&mut self) -> Result { use TokenType::*; self.left_association_binary(&[Minus, Plus], Self::factor) } fn factor(&mut self) -> Result { use TokenType::*; self.left_association_binary(&[Slash, Star], Self::unary) } fn unary(&mut self) -> Result { use TokenType::*; if self.match_token(&[Bang, Minus]) { let op = self.previous().clone(); let right = self.unary()?; return Ok(Expr::Unary { op, right: Box::new(right), }); } self.primary() } /* error boundaries: ("!=" | "==") equality | (">" | ">=" | "<" | "<=") comparison | ("+") term | ("/" | "*") factor ; */ fn primary(&mut self) -> Result { use LiteralType::*; use TokenType::*; fn create_literal(l_type: Option) -> Expr { Expr::Literal { value: l_type } } if self.match_token(&[False]) { return Ok(create_literal(Some(Bool(false)))); } if self.match_token(&[True]) { return Ok(create_literal(Some(Bool(true)))); } if self.match_token(&[TokenType::Number, TokenType::String]) { return Ok(create_literal(self.previous().literal.clone())); } // i included the enum name bcs of ambiguity of LiteralType and TokenType if self.match_token(&[TokenType::Nil]) { return Ok(create_literal(Some(LiteralType::Nil))); } if self.match_token(&[LeftParen]) { let expr = self.expression()?; self.consume(RightParen, "Expect ')' after expression")?; return Ok(Expr::Grouping { expression: Box::new(expr), }); } if self.match_token(&[Equal, BangEqual]) { let _ = self.equality(); return Err(ParseError { token: self.previous().clone(), msg: "Missing left-hand operand.".to_string(), }); } if self.match_token(&[Greater, GreaterEqual, Less, LessEqual]) { let _ = self.comparison(); return Err(ParseError { token: self.previous().clone(), msg: "Missing left-hand operand.".to_string(), }); } if self.match_token(&[Plus]) { let _ = self.term(); return Err(ParseError { token: self.previous().clone(), msg: "Missing left-hand operand.".to_string(), }); } if self.match_token(&[Star, Slash]) { let _ = self.factor(); return Err(ParseError { token: self.previous().clone(), msg: "Missing left-hand operand.".to_string(), }); } Err(ParseError { token: self.peek().clone(), msg: "Expect expression.".to_string(), }) } fn consume(&mut self, t_type: TokenType, err_msg: &str) -> Result { if self.check(t_type) { return Ok(self.advance().clone()); } Err(ParseError { token: self.peek().clone(), msg: err_msg.to_string(), }) } // will not be used for the time being (per the book) // used for error recovery fn synchronize(&mut self) { use TokenType::*; self.advance(); while !self.is_at_end() { if self.previous().t_type == TokenType::Semicolon { return; } if let Class | Fun | Var | For | If | While | Print | Return = self.peek().t_type { return; } } self.advance(); } fn left_association_binary( &mut self, types: &[TokenType], expr_fn: fn(&mut Self) -> Result, ) -> Result { let mut expr = expr_fn(self)?; while self.match_token(types) { let op = self.previous().clone(); let right = expr_fn(self)?; expr = Expr::Binary { left: Box::new(expr), op, right: Box::new(right), } } Ok(expr) } fn match_token(&mut self, types: &[TokenType]) -> bool { for t_type in types { if self.check(*t_type) { self.advance(); return true; } } false } fn check(&self, t_type: TokenType) -> bool { if self.is_at_end() { return false; } self.peek().t_type == t_type } fn advance(&mut self) -> &Token { if !self.is_at_end() { self.current += 1; } self.previous() } fn is_at_end(&self) -> bool { matches!(self.peek().t_type, TokenType::EOF) } fn peek(&self) -> &Token { &self.tokens[self.current] } fn previous(&self) -> &Token { &self.tokens[self.current - 1] } }