use super::astnode; use super::astnode::{ASTNode, BinaryExpr}; use crate::error::ErrorLocationWrapper; use crate::lexer::{token, token::TokenType}; use std::iter; use std::result::Result as StdResult; #[derive(Debug)] pub enum InnerASTParsingError { IncorrectToken(TokenType), UnmatchedBrace, } impl std::fmt::Display for InnerASTParsingError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match *self { Self::UnmatchedBrace => write!(f, "Unmatched brace"), Self::IncorrectToken(ref token) => write!(f, "Incorrect token {:?}", token), } } } impl std::error::Error for InnerASTParsingError {} pub type ASTParsingError = ErrorLocationWrapper; type Result = StdResult; 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() { Some(token) => match token.token_type { TokenType::False => ASTNode::Literal(astnode::Literal::Bool(false)), TokenType::True => ASTNode::Literal(astnode::Literal::Bool(true)), TokenType::Int(i) => ASTNode::Literal(astnode::Literal::Int(i)), TokenType::String(i) => ASTNode::Literal(astnode::Literal::String(i)), TokenType::Float(f) => ASTNode::Literal(astnode::Literal::Float(f)), 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(token.location.wrap(InnerASTParsingError::UnmatchedBrace)) } } } a => return Err(token.location.wrap(InnerASTParsingError::IncorrectToken(a))), }, None => todo!(), }; Ok(node) } }