crftng-intrprtrs/src/ast/expression/mod.rs
2022-05-02 12:56:52 +02:00

103 lines
3 KiB
Rust

mod binary_expr;
pub mod expression_node;
mod grouping_expr;
mod literal_expr;
pub mod operator;
mod unary_expr;
mod variable_expr;
pub use binary_expr::BinaryExpr;
pub use grouping_expr::GroupingExpr;
use itertools::PeekingNext;
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 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),
}
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::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<Item = token::Token<'a>>> Parser<'a, T> {
pub fn expression(&mut self) -> Result<ExpressionNode> {
self.equality()
}
pub(super) fn primary(&mut self) -> Result<ExpressionNode> {
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);
}
}