use crate::token::Token; #[derive(Debug)] pub enum BinaryOp { Add, Sub, Mul, Div, Mod } #[derive(Debug)] pub enum UnaryOp { Neg } fn prefix_bp(op: &UnaryOp) -> u8 { match op { UnaryOp::Neg => 5 } } fn infix_bp(op: &BinaryOp) -> (u8, u8) { match op { BinaryOp::Add | BinaryOp::Sub => (1, 2), BinaryOp::Mul | BinaryOp::Div | BinaryOp::Mod => (3, 4) } } #[derive(Debug)] pub enum Expr { Number(i64), Ident(String), EOL, Binary { op: BinaryOp, left: Box, right: Box }, Unary { op: UnaryOp, right: Box } } pub struct Parser { tokens: Vec, pos: usize } impl Parser { pub fn new(tokens: Vec) -> Self { Self { tokens, pos: 0 } } fn advance(&mut self) { self.pos += 1; } fn peek(&self) -> Option<&Token> { self.tokens.get(self.pos) } fn next(&mut self) -> Option { let tok = self.peek().cloned(); self.advance(); tok } fn parse_atom(&mut self) -> Expr { match self.next() { Some(Token::Number(n)) => Expr::Number(n), Some(Token::Ident(id)) => Expr::Ident(id), Some(Token::LParen) => { let expr = self.parse_expr(0); match self.next() { Some(Token::RParen) => expr, _ => panic!("expected ')'") } }, tok => panic!("unknown token: {tok:?}") } } fn parse_prefix(&mut self) -> Expr { match self.peek() { Some(Token::Sub) => { self.advance(); let op = UnaryOp::Neg; let bp = prefix_bp(&op); let rhs = self.parse_expr(bp); Expr::Unary { op, right: Box::new(rhs) } }, _ => self.parse_atom() } } fn parse_expr(&mut self, min_bp: u8) -> Expr { let mut lhs = self.parse_prefix(); loop { let op = match self.peek() { Some(Token::Add) => BinaryOp::Add, Some(Token::Sub) => BinaryOp::Sub, Some(Token::Mul) => BinaryOp::Mul, Some(Token::Div) => BinaryOp::Div, Some(Token::Mod) => BinaryOp::Mod, _ => break }; let (left_bp, right_bp) = infix_bp(&op); if left_bp < min_bp { break; } self.advance(); let rhs = self.parse_expr(right_bp); lhs = Expr::Binary { left: Box::new(lhs), op, right: Box::new(rhs) } } lhs } pub fn parse(&mut self) -> Expr { if self.peek() == None {return Expr::EOL} self.parse_expr(0) } }