use super::astnode; use super::astnode::{ASTNode, BinaryExpr}; use crate::lexer::{token, token::TokenType}; use std::iter; use std::result::Result as StdResult; type Result = StdResult; #[derive(Debug)] pub enum ASTParsingError { UnmatchedBrace, } impl std::fmt::Display for ASTParsingError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match *self { Self::UnmatchedBrace => write!(f, "Unmatched brace"), } } } impl std::error::Error for ASTParsingError {} pub struct Parser<'a, T: Iterator>> { token_iter: iter::Peekable, } impl<'a, T: Iterator>> Parser<'a, T> { pub fn new(iter: T) -> Parser<'a, T> { Parser { token_iter: iter.peekable(), } } pub fn scan_expressions(&mut self) -> StdResult, Vec> { let mut tokens = Vec::new(); let mut errors = Vec::new(); while self.token_iter.peek().is_some() { match self.expression() { Ok(token) => { if errors.is_empty() { tokens.push(token) } } Err(e) => errors.push(e), } } if errors.is_empty() { Ok(tokens) } else { Err(errors) } } fn expression(&mut self) -> Result { self.equality() } fn equality(&mut self) -> Result { let mut node = self.comparison()?; while let Some(o) = self .token_iter .next_if(|t| matches!(t.token_type, TokenType::EqualEqual | TokenType::BangEqual)) { node = BinaryExpr::new( Box::new(node), o.token_type.try_into().unwrap(), Box::new(self.comparison()?), ) .into(); } Ok(node) } fn comparison(&mut self) -> Result { let mut node = self.term()?; while let Some(o) = self.token_iter.next_if(|t| { matches!( t.token_type, TokenType::Greater | TokenType::GreaterEqual | TokenType::Less | TokenType::LessEqual ) }) { node = BinaryExpr::new( Box::new(node), o.token_type.try_into().unwrap(), Box::new(self.comparison()?), ) .into(); } Ok(node) } fn term(&mut self) -> Result { let mut node = self.factor()?; while let Some(o) = self .token_iter .next_if(|t| matches!(t.token_type, TokenType::Minus | TokenType::Plus)) { node = BinaryExpr::new( Box::new(node), o.token_type.try_into().unwrap(), Box::new(self.comparison()?), ) .into() } Ok(node) } fn factor(&mut self) -> Result { let mut node = self.unary()?; while let Some(o) = self .token_iter .next_if(|t| matches!(t.token_type, TokenType::Star | TokenType::Slash)) { node = BinaryExpr::new( Box::new(node), o.token_type.try_into().unwrap(), Box::new(self.comparison()?), ) .into(); } Ok(node) } fn unary(&mut self) -> Result { if let Some(op) = self .token_iter .next_if(|t| matches!(t.token_type, TokenType::Bang | TokenType::Minus)) { let right = Box::new(self.unary()?); Ok(ASTNode::UnaryExpr(astnode::UnaryExpr::new( op.token_type.try_into().unwrap(), right, ))) } else { self.primary() } } fn primary(&mut self) -> Result { let node = match self.token_iter.next().map(|it| it.token_type) { Some(TokenType::False) => ASTNode::Literal(astnode::Literal::Bool(false)), Some(TokenType::True) => ASTNode::Literal(astnode::Literal::Bool(false)), Some(TokenType::Int(i)) => ASTNode::Literal(astnode::Literal::Int(i)), Some(TokenType::String(i)) => ASTNode::Literal(astnode::Literal::String(i)), Some(TokenType::Float(f)) => ASTNode::Literal(astnode::Literal::Float(f)), Some(TokenType::LeftParen) => { let expr = self.expression()?; let group = astnode::GroupingExpr::new(Box::new(expr)); match self .token_iter .next_if(|v| matches!(v.token_type, TokenType::RightParen)) { Some(_) => return Ok(group.into()), None => return Err(ASTParsingError::UnmatchedBrace), } } Some(a) => panic!("{:#?}", a), None => todo!(), }; Ok(node) } }