pub mod expression_node; pub mod operator; mod binary_expr; mod block_expr; mod grouping_expr; mod literal_expr; mod unary_expr; mod variable_expr; pub use binary_expr::BinaryExpr; pub use block_expr::BlockExpr; pub use grouping_expr::GroupingExpr; pub use literal_expr::Literal; pub use unary_expr::UnaryExpr; pub use variable_expr::VariableExpr; use super::parser::{InnerASTParsingError, Parser, Result}; use crate::lexer::token::{self, TokenType}; use itertools::PeekingNext; use from_variants::FromVariants; use match_any::match_any; use std::fmt::Debug; #[derive(FromVariants)] pub enum ExpressionNode { BinaryExpr(BinaryExpr), GroupingExpr(GroupingExpr), Literal(Literal), Variable(VariableExpr), UnaryExpr(UnaryExpr), BlockExpr(BlockExpr), } macro_rules! all_variants { ($expr:expr, $val_name:ident => $expr_arm:expr) => { { use match_any::match_any; use $crate::ast::expression::*; match_any!($expr, ExpressionNode::BinaryExpr($val_name) | ExpressionNode::GroupingExpr($val_name) | ExpressionNode::Literal($val_name) | ExpressionNode::Variable($val_name) | ExpressionNode::BlockExpr($val_name) | ExpressionNode::UnaryExpr($val_name) => $expr_arm) } }; } pub(crate) use all_variants; impl Debug for ExpressionNode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { all_variants!(self, n => n.fmt(f)) } } impl<'a, T: Iterator>> Parser<'a, T> { pub fn expression(&mut self) -> Result { self.block_expr() } pub(super) fn primary(&mut self) -> Result { let token = self.token_iter.next(); let node = match token.token_type { TokenType::False => ExpressionNode::Literal(Literal::Bool(false)), TokenType::True => ExpressionNode::Literal(Literal::Bool(true)), TokenType::Int(i) => ExpressionNode::Literal(Literal::Int(i)), TokenType::String(i) => ExpressionNode::Literal(Literal::String(i)), TokenType::Float(f) => ExpressionNode::Literal(Literal::Float(f)), TokenType::Nil => ExpressionNode::Literal(Literal::Nil), TokenType::LeftParen => { let expr = self.expression()?; let group = GroupingExpr::new(Box::new(expr)); match self .token_iter .peeking_next(|v| matches!(v.token_type, TokenType::RightParen)) { Some(_) => return Ok(group.into()), None => return Err(token.location.wrap(InnerASTParsingError::UnmatchedBrace)), } } TokenType::Identifier(var_name) => VariableExpr::new(var_name).into(), a => return Err(token.location.wrap(InnerASTParsingError::IncorrectToken(a))), }; Ok(node) } } #[cfg(test)] mod tests { use super::*; use operator::{Operator, UnaryOperator}; #[test] fn expression_node_ast_printer() { let ast = ExpressionNode::BinaryExpr(BinaryExpr { left: Box::new(ExpressionNode::UnaryExpr(UnaryExpr { operator: UnaryOperator::Bang, right: Box::new(ExpressionNode::Literal(Literal::Int(1))), })), operator: Operator::EqualEqual, right: Box::new(ExpressionNode::Literal(Literal::Int(0))), }); let formated = format!("{:?}", ast); assert_eq!("(== (! Int(1)) Int(0))", formated); } }