use crate::{ ast::{BinOpType, Expr, FnCall, UnOpType}, token::{Group, Op, Token, TokenStream}, }; #[derive(Debug)] pub struct ParseErr; type PRes = Result; pub struct Parser { tokens: TokenStream, } /* GRAMMAR expr_literal = Literal expr_fn_call = FnCall expr_varibale = Variable expr_value = expr_literal | expr_fn_call | expr_variable expr_term = "-" expr_term | "(" expr_add ")" | expr_literal expr_mul = expr_term (("*"|"/") expr_term)* expr_add = expr_mul (("+"|"-") expr_mul)* */ impl Parser { pub fn new(tokens: TokenStream) -> Self { Self { tokens } } pub fn curr(&self) -> Option<&Token> { self.tokens.curr() } pub fn peek(&self) -> Option<&Token> { self.tokens.peek() } pub fn advance(&mut self) -> Option<&Token> { self.tokens.advance() } pub fn parse(&mut self) -> PRes { self.parse_expr_add() } pub fn parse_expr_add(&mut self) -> PRes { let mut a = self.parse_expr_mul()?; while matches!(self.curr(), Some(Token::Op(Op::Add | Op::Sub))) { // We successfully matched curr against Some already in the while condition, so unwrap is fine let tok_op = self.advance().unwrap().clone(); let b = self.parse_expr_mul()?; let op_type = match tok_op { Token::Op(Op::Add) => BinOpType::Add, Token::Op(Op::Sub) => BinOpType::Sub, _ => unreachable!(), }; a = Expr::BinOp(op_type, a.into(), b.into()); } Ok(a) } pub fn parse_expr_mul(&mut self) -> PRes { let mut a = self.parse_expr_term()?; while matches!(self.curr(), Some(Token::Op(Op::Mul | Op::Div | Op::Mod))) { // We successfully matched curr against Some already in the while condition, so unwrap is fine let tok_op = self.advance().unwrap().clone(); let b = self.parse_expr_term()?; let op_type = match tok_op { Token::Op(Op::Mul) => BinOpType::Mul, Token::Op(Op::Div) => BinOpType::Div, Token::Op(Op::Mod) => BinOpType::Mod, _ => unreachable!(), }; a = Expr::BinOp(op_type, a.into(), b.into()); } Ok(a) } pub fn parse_expr_term(&mut self) -> PRes { let term = match self.curr() { Some(Token::Open(Group::Paren)) => { self.advance(); let a = self.parse_expr_add()?; if !matches!(self.advance(), Some(Token::Close(Group::Paren))) { panic!("Missing closing parentheses"); } a } Some(Token::Op(Op::Sub)) => { self.advance(); Expr::UnOp(UnOpType::Neg, self.parse_expr_term()?.into()) } _ => self.parse_expr_value()?, }; Ok(term) } pub fn parse_expr_value(&mut self) -> PRes { match self.curr() { Some(Token::Literal(_)) => self.parse_expr_literal(), Some(Token::Ident(_)) if matches!(self.peek(), Some(Token::Open(Group::Paren))) => { self.parse_expr_fn_call() } Some(Token::Ident(_)) => self.parse_expr_varibale(), _ => panic!("Expected value (literal, variable or function call)"), } } pub fn parse_expr_fn_call(&mut self) -> PRes { // The first 2 checks are not really necessary for internal calls since parse_expr_value // verifies the tokens already let fn_name = match self.advance() { Some(Token::Ident(ident)) => ident.clone(), _ => panic!("Unexpected token while parsing function call. Expected identifier"), }; if !matches!(self.advance(), Some(Token::Open(Group::Paren))) { panic!("Unexpected token while parsing function call. Expected '('"); } let mut args = Vec::new(); // TODO: This is *suboptimal* code if !matches!(self.curr(), Some(Token::Close(Group::Paren))) { args.push(self.parse_expr_add()?); while matches!(self.curr(), Some(Token::Comma)) { self.advance(); args.push(self.parse_expr_add()?); } } if !matches!(self.advance(), Some(Token::Close(Group::Paren))) { panic!("Unexpected token while parsing function call. Expected '('"); } Ok(Expr::FnCall(FnCall { fn_name, args })) } pub fn parse_expr_varibale(&mut self) -> PRes { match self.advance() { Some(Token::Ident(ident)) => Ok(Expr::Variable(ident.clone())), _ => panic!("Unexpected token while parsing variable. Expected identifier"), } } pub fn parse_expr_literal(&mut self) -> PRes { match self.advance() { Some(Token::Literal(lit)) => Ok(Expr::Literal(lit.clone())), _ => panic!("Unexpected token while parsing literal. Expected literal"), } } } #[cfg(test)] mod tests { use crate::{ ast::{BinOpType, Expr, FnCall, UnOpType}, token::{Group, Literal, Op, Token, TokenStream}, Parser, }; #[test] fn test_groupings_neg() { // let input = "(-(-5+2)*-(2*-sqrt(9))+-(a-6)) % 30"; let fn_name = "sqrt".to_string(); let var_name = "a".to_string(); // (-(-5+2)*-(2*-sqrt(9))+-(a-6)) % 30 let input_toks = vec![ Token::Open(Group::Paren), // ( Token::Op(Op::Sub), // - Token::Open(Group::Paren), // ( Token::Op(Op::Sub), // - Token::Literal(Literal::Int64(5)), // 5 Token::Op(Op::Add), // + Token::Literal(Literal::Int64(2)), // 2 Token::Close(Group::Paren), // ) Token::Op(Op::Mul), // * Token::Op(Op::Sub), // - Token::Open(Group::Paren), // ( Token::Literal(Literal::Int64(2)), // 2 Token::Op(Op::Mul), // * Token::Op(Op::Sub), // - Token::Ident(fn_name.clone()), // sqrt Token::Open(Group::Paren), // ( Token::Literal(Literal::Int64(9)), // 9 Token::Close(Group::Paren), // ) Token::Close(Group::Paren), // ) Token::Op(Op::Add), // + Token::Op(Op::Sub), // - Token::Open(Group::Paren), // ( Token::Ident(var_name.clone()), // a Token::Op(Op::Sub), // - Token::Literal(Literal::Int64(6)), // 6 Token::Close(Group::Paren), // ) Token::Close(Group::Paren), // ) Token::Op(Op::Mod), // % Token::Literal(Literal::Int64(30)), // 30 ]; // -(-5+2) let neg_grp_neg_5_add_2 = Expr::UnOp( UnOpType::Neg, Box::new(Expr::BinOp( BinOpType::Add, Box::new(Expr::UnOp( UnOpType::Neg, Expr::Literal(Literal::Int64(5)).into(), )), Expr::Literal(Literal::Int64(2)).into(), )), ); // -(2*-sqrt(9)) let neg_grp_2_mul_neg_sqrt = Expr::UnOp( UnOpType::Neg, Box::new(Expr::BinOp( BinOpType::Mul, Expr::Literal(Literal::Int64(2)).into(), Box::new(Expr::UnOp( UnOpType::Neg, Expr::FnCall(FnCall { fn_name, args: vec![Expr::Literal(Literal::Int64(9))], }) .into(), )), )), ); // -(-5+2) * -(2*-sqrt(9)) let mul_first = Expr::BinOp( BinOpType::Mul, neg_grp_neg_5_add_2.into(), neg_grp_2_mul_neg_sqrt.into(), ); // -(a-6) let neg_grp_a_sub_6 = Expr::UnOp( UnOpType::Neg, Box::new(Expr::BinOp( BinOpType::Sub, Expr::Variable(var_name).into(), Expr::Literal(Literal::Int64(6)).into(), )), ); // -(-5+2)*-(2*-sqrt(9)) + -(a-6) let left_of_mod = Expr::BinOp(BinOpType::Add, mul_first.into(), neg_grp_a_sub_6.into()); // (-(-5+2) * -(2*-sqrt(9)) + -(a-6)) % 30 let expected = Expr::BinOp( BinOpType::Mod, left_of_mod.into(), Expr::Literal(Literal::Int64(30)).into(), ); // let res = parse_str(input); let mut parser = Parser::new(TokenStream::new(input_toks)); let res = parser.parse_expr_add().unwrap(); assert_eq!(expected, res); } }