Extract expression node and expression parser to a separate file

This commit is contained in:
bad 2022-04-23 15:39:37 +02:00
parent ede0ca3993
commit 91f2a945c5
9 changed files with 353 additions and 344 deletions

View File

@ -1,196 +0,0 @@
use crate::lexer::token;
use from_variants::FromVariants;
use match_any::match_any;
use std::fmt::{Debug, Display};
#[derive(FromVariants)]
pub enum ASTNode {
BinaryExpr(BinaryExpr),
GroupingExpr(GroupingExpr),
Literal(Literal),
UnaryExpr(UnaryExpr),
}
macro_rules! all_variants {
($expr:expr, $val_name:ident => $expr_arm:expr) => {
{
use match_any::match_any;
use $crate::ast::astnode::*;
match_any!($expr, ASTNode::BinaryExpr($val_name) | ASTNode::GroupingExpr($val_name) | ASTNode::Literal($val_name) | ASTNode::UnaryExpr($val_name) => $expr_arm)
}
};
}
pub(crate) use all_variants;
impl Debug for ASTNode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
all_variants!(self, n => n.fmt(f))
}
}
pub enum UnaryOperator {
Minus,
Bang,
}
impl TryFrom<token::TokenType> for UnaryOperator {
type Error = EnumConvertError;
fn try_from(value: token::TokenType) -> Result<Self, Self::Error> {
Ok(match value {
token::TokenType::Bang => Self::Bang,
token::TokenType::Minus => Self::Minus,
_ => return Err(EnumConvertError),
})
}
}
impl Display for UnaryOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match *self {
UnaryOperator::Minus => "-",
UnaryOperator::Bang => "!",
}
)
}
}
pub enum Operator {
BangEqual,
Equal,
EqualEqual,
Greater,
GreaterEqual,
Less,
LessEqual,
}
#[derive(Debug)]
pub struct EnumConvertError;
impl std::fmt::Display for EnumConvertError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Couldn't convert between enums")
}
}
impl std::error::Error for EnumConvertError {}
impl TryFrom<token::TokenType> for Operator {
type Error = EnumConvertError;
fn try_from(value: token::TokenType) -> Result<Self, Self::Error> {
Ok(match value {
token::TokenType::BangEqual => Self::BangEqual,
token::TokenType::Equal => Self::Equal,
token::TokenType::EqualEqual => Self::EqualEqual,
token::TokenType::Greater => Self::Greater,
token::TokenType::GreaterEqual => Self::GreaterEqual,
token::TokenType::Less => Self::Less,
token::TokenType::LessEqual => Self::LessEqual,
_ => return Err(EnumConvertError),
})
}
}
impl Display for Operator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match *self {
Operator::Less => "<",
Operator::Equal => "=",
Operator::Greater => ">",
Operator::BangEqual => "!=",
Operator::LessEqual => "<=",
Operator::EqualEqual => "==",
Operator::GreaterEqual => ">=",
}
)
}
}
#[derive(Debug, Clone)]
pub enum Literal {
String(String),
Int(i32),
Float(f32),
Bool(bool),
}
pub struct BinaryExpr {
pub left: Box<ASTNode>,
pub operator: Operator,
pub right: Box<ASTNode>,
}
impl BinaryExpr {
pub fn new(left: Box<ASTNode>, operator: Operator, right: Box<ASTNode>) -> Self {
Self {
left,
operator,
right,
}
}
}
pub struct GroupingExpr(pub Box<ASTNode>);
impl GroupingExpr {
pub(crate) fn new(expr: Box<ASTNode>) -> Self {
Self(expr)
}
}
pub struct UnaryExpr {
pub operator: UnaryOperator,
pub right: Box<ASTNode>,
}
impl UnaryExpr {
pub fn new(operator: UnaryOperator, right: Box<ASTNode>) -> Self {
Self { operator, right }
}
}
impl Debug for BinaryExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({} {:?} {:?})", self.operator, self.left, self.right)
}
}
impl Debug for GroupingExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({:?})", self.0)
}
}
impl Debug for UnaryExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({} {:?})", self.operator, self.right)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ast_printer() {
let ast = ASTNode::BinaryExpr(BinaryExpr {
left: Box::new(ASTNode::UnaryExpr(UnaryExpr {
operator: UnaryOperator::Bang,
right: Box::new(ASTNode::Literal(Literal::Int(1))),
})),
operator: Operator::EqualEqual,
right: Box::new(ASTNode::Literal(Literal::Int(0))),
});
let formated = format!("{:?}", ast);
assert_eq!("(== (! Int(1)) Int(0))", formated);
}
}

View File

@ -0,0 +1,195 @@
use crate::lexer::token;
use from_variants::FromVariants;
use match_any::match_any;
use std::fmt::{Debug, Display};
#[derive(FromVariants)]
pub enum ExpressionNode {
BinaryExpr(BinaryExpr),
GroupingExpr(GroupingExpr),
Literal(Literal),
UnaryExpr(UnaryExpr),
}
macro_rules! all_variants {
($expr:expr, $val_name:ident => $expr_arm:expr) => {
{
use match_any::match_any;
use $crate::ast::expression::expression_node::*;
match_any!($expr, ExpressionNode::BinaryExpr($val_name) | ExpressionNode::GroupingExpr($val_name) | ExpressionNode::Literal($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))
}
}
pub enum UnaryOperator {
Minus,
Bang,
}
impl TryFrom<token::TokenType> for UnaryOperator {
type Error = EnumConvertError;
fn try_from(value: token::TokenType) -> Result<Self, Self::Error> {
Ok(match value {
token::TokenType::Bang => Self::Bang,
token::TokenType::Minus => Self::Minus,
_ => return Err(EnumConvertError),
})
}
}
impl Display for UnaryOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match *self {
UnaryOperator::Minus => "-",
UnaryOperator::Bang => "!",
}
)
}
}
pub enum Operator {
BangEqual,
Equal,
EqualEqual,
Greater,
GreaterEqual,
Less,
LessEqual,
}
#[derive(Debug)]
pub struct EnumConvertError;
impl std::fmt::Display for EnumConvertError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Couldn't convert between enums")
}
}
impl std::error::Error for EnumConvertError {}
impl TryFrom<token::TokenType> for Operator {
type Error = EnumConvertError;
fn try_from(value: token::TokenType) -> Result<Self, Self::Error> {
Ok(match value {
token::TokenType::BangEqual => Self::BangEqual,
token::TokenType::Equal => Self::Equal,
token::TokenType::EqualEqual => Self::EqualEqual,
token::TokenType::Greater => Self::Greater,
token::TokenType::GreaterEqual => Self::GreaterEqual,
token::TokenType::Less => Self::Less,
token::TokenType::LessEqual => Self::LessEqual,
_ => return Err(EnumConvertError),
})
}
}
impl Display for Operator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match *self {
Operator::Less => "<",
Operator::Equal => "=",
Operator::Greater => ">",
Operator::BangEqual => "!=",
Operator::LessEqual => "<=",
Operator::EqualEqual => "==",
Operator::GreaterEqual => ">=",
}
)
}
}
#[derive(Debug, Clone)]
pub enum Literal {
String(String),
Int(i32),
Float(f32),
Bool(bool),
}
pub struct BinaryExpr {
pub left: Box<ExpressionNode>,
pub operator: Operator,
pub right: Box<ExpressionNode>,
}
impl BinaryExpr {
pub fn new(left: Box<ExpressionNode>, operator: Operator, right: Box<ExpressionNode>) -> Self {
Self {
left,
operator,
right,
}
}
}
pub struct GroupingExpr(pub Box<ExpressionNode>);
impl GroupingExpr {
pub(crate) fn new(expr: Box<ExpressionNode>) -> Self {
Self(expr)
}
}
pub struct UnaryExpr {
pub operator: UnaryOperator,
pub right: Box<ExpressionNode>,
}
impl UnaryExpr {
pub fn new(operator: UnaryOperator, right: Box<ExpressionNode>) -> Self {
Self { operator, right }
}
}
impl Debug for BinaryExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({} {:?} {:?})", self.operator, self.left, self.right)
}
}
impl Debug for GroupingExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({:?})", self.0)
}
}
impl Debug for UnaryExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({} {:?})", self.operator, self.right)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[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);
}
}

View File

@ -0,0 +1,124 @@
use crate::lexer::token::{self, TokenType};
use super::super::parser::{InnerASTParsingError, Parser, Result};
use super::expression_node::*;
impl<'a, T: Iterator<Item = token::Token<'a>>> Parser<'a, T> {
pub fn expression(&mut self) -> Result<ExpressionNode> {
self.equality()
}
fn equality(&mut self) -> Result<ExpressionNode> {
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<ExpressionNode> {
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<ExpressionNode> {
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<ExpressionNode> {
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<ExpressionNode> {
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(ExpressionNode::UnaryExpr(UnaryExpr::new(
op.token_type.try_into().unwrap(),
right,
)))
} else {
self.primary()
}
}
fn primary(&mut self) -> Result<ExpressionNode> {
let node = match self.token_iter.next() {
Some(token) => 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::LeftParen => {
let expr = self.expression()?;
let group = 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)
}
}

View File

@ -0,0 +1,2 @@
pub mod expression_node;
mod expression_parser;

View File

@ -1,2 +1,2 @@
pub mod astnode;
pub mod expression;
pub mod parser;

View File

@ -1,5 +1,4 @@
use super::astnode;
use super::astnode::{ASTNode, BinaryExpr};
use super::expression::expression_node;
use crate::error::ErrorLocationWrapper;
use crate::lexer::{token, token::TokenType};
@ -23,10 +22,10 @@ impl std::fmt::Display for InnerASTParsingError {
impl std::error::Error for InnerASTParsingError {}
pub type ASTParsingError = ErrorLocationWrapper<InnerASTParsingError>;
type Result<T> = StdResult<T, ASTParsingError>;
pub(super) type Result<T> = StdResult<T, ASTParsingError>;
pub struct Parser<'a, T: Iterator<Item = token::Token<'a>>> {
token_iter: iter::Peekable<T>,
pub(super) token_iter: iter::Peekable<T>,
}
impl<'a, T: Iterator<Item = token::Token<'a>>> Parser<'a, T> {
@ -35,7 +34,9 @@ impl<'a, T: Iterator<Item = token::Token<'a>>> Parser<'a, T> {
token_iter: iter.peekable(),
}
}
pub fn scan_expressions(&mut self) -> StdResult<Vec<ASTNode>, Vec<ASTParsingError>> {
pub fn parse_all(
&mut self,
) -> StdResult<Vec<expression_node::ExpressionNode>, Vec<ASTParsingError>> {
let mut tokens = Vec::new();
let mut errors = Vec::new();
@ -55,122 +56,4 @@ impl<'a, T: Iterator<Item = token::Token<'a>>> Parser<'a, T> {
Err(errors)
}
}
fn expression(&mut self) -> Result<ASTNode> {
self.equality()
}
fn equality(&mut self) -> Result<ASTNode> {
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<ASTNode> {
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<ASTNode> {
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<ASTNode> {
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<ASTNode> {
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<ASTNode> {
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)
}
}

View File

@ -1,7 +1,7 @@
use std::fmt::Display;
use super::types::Value;
use crate::ast::astnode::{self, UnaryOperator};
use crate::ast::expression::expression_node;
#[derive(Debug)]
pub struct RuntimeError;
@ -17,40 +17,40 @@ pub trait Interpret {
fn interpret(&self) -> Result<Value, RuntimeError>;
}
impl Interpret for astnode::ASTNode {
impl Interpret for expression_node::ExpressionNode {
fn interpret(&self) -> Result<Value, RuntimeError> {
astnode::all_variants!(self, n => n.interpret())
expression_node::all_variants!(self, n => n.interpret())
}
}
impl Interpret for astnode::Literal {
impl Interpret for expression_node::Literal {
fn interpret(&self) -> Result<Value, RuntimeError> {
Ok(self.clone().into())
}
}
impl Interpret for astnode::BinaryExpr {
impl Interpret for expression_node::BinaryExpr {
fn interpret(&self) -> Result<Value, RuntimeError> {
let left_val = self.left.interpret().expect("expected lval");
let right_val = self.right.interpret().expect("expected rval");
match self.operator {
astnode::Operator::BangEqual => Ok((left_val != right_val).into()),
astnode::Operator::Less => Ok((left_val < right_val).into()),
astnode::Operator::LessEqual => Ok((left_val <= right_val).into()),
astnode::Operator::Greater => Ok((left_val > right_val).into()),
astnode::Operator::GreaterEqual => Ok((left_val >= right_val).into()),
astnode::Operator::EqualEqual => Ok((left_val == right_val).into()),
astnode::Operator::Equal => todo!(),
expression_node::Operator::BangEqual => Ok((left_val != right_val).into()),
expression_node::Operator::Less => Ok((left_val < right_val).into()),
expression_node::Operator::LessEqual => Ok((left_val <= right_val).into()),
expression_node::Operator::Greater => Ok((left_val > right_val).into()),
expression_node::Operator::GreaterEqual => Ok((left_val >= right_val).into()),
expression_node::Operator::EqualEqual => Ok((left_val == right_val).into()),
expression_node::Operator::Equal => todo!(),
}
}
}
impl Interpret for astnode::UnaryExpr {
impl Interpret for expression_node::UnaryExpr {
fn interpret(&self) -> Result<Value, RuntimeError> {
let val = self.right.interpret()?;
match self.operator {
UnaryOperator::Bang => Ok(Value::Bool(!val.truthy())),
UnaryOperator::Minus => match val {
expression_node::UnaryOperator::Bang => Ok(Value::Bool(!val.truthy())),
expression_node::UnaryOperator::Minus => match val {
Value::Int(i) => Ok(Value::Int(-i)),
Value::Float(f) => Ok(Value::Float(-f)),
_ => Err(RuntimeError),
@ -59,7 +59,7 @@ impl Interpret for astnode::UnaryExpr {
}
}
impl Interpret for astnode::GroupingExpr {
impl Interpret for expression_node::GroupingExpr {
fn interpret(&self) -> Result<Value, RuntimeError> {
self.0.interpret()
}

View File

@ -1,4 +1,4 @@
use crate::ast::astnode;
use crate::ast::expression::expression_node;
use from_variants::FromVariants;
#[derive(Debug, PartialEq, PartialOrd, FromVariants)]
@ -11,10 +11,10 @@ pub enum Value {
String(String),
}
impl From<astnode::Literal> for Value {
fn from(l: astnode::Literal) -> Self {
impl From<expression_node::Literal> for Value {
fn from(l: expression_node::Literal) -> Self {
match_any::match_any!(l,
astnode::Literal::Int(v) | astnode::Literal::Bool(v) | astnode::Literal::Float(v) | astnode::Literal::String(v) => v.into()
expression_node::Literal::Int(v) | expression_node::Literal::Bool(v) | expression_node::Literal::Float(v) | expression_node::Literal::String(v) => v.into()
)
}
}

View File

@ -3,7 +3,8 @@ pub mod error;
pub mod interpreter;
pub mod lexer;
use ast::{astnode::ASTNode, parser::ASTParsingError};
use ast::expression::expression_node::ExpressionNode;
use ast::parser::ASTParsingError;
use interpreter::ast_walker::{Interpret, RuntimeError};
use interpreter::types::Value;
use lexer::{token::Token, Lexer, LexingError};
@ -16,12 +17,12 @@ pub fn lex<'a, 'b>(
lexer.scan_tokens()
}
pub fn parse(tokens: Vec<Token>) -> Result<Vec<ASTNode>, Vec<ASTParsingError>> {
pub fn parse(tokens: Vec<Token>) -> Result<Vec<ExpressionNode>, Vec<ASTParsingError>> {
let mut parser = crate::ast::parser::Parser::new(tokens.into_iter());
parser.scan_expressions()
parser.parse_all()
}
pub fn exec(nodes: Vec<ASTNode>) -> Result<Value, RuntimeError> {
pub fn exec(nodes: Vec<ExpressionNode>) -> Result<Value, RuntimeError> {
nodes[0].interpret()
}