Extract expression node and expression parser to a separate file
This commit is contained in:
parent
ede0ca3993
commit
91f2a945c5
9 changed files with 353 additions and 344 deletions
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
195
src/ast/expression/expression_node.rs
Normal file
195
src/ast/expression/expression_node.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
124
src/ast/expression/expression_parser.rs
Normal file
124
src/ast/expression/expression_parser.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
2
src/ast/expression/mod.rs
Normal file
2
src/ast/expression/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod expression_node;
|
||||||
|
mod expression_parser;
|
|
@ -1,2 +1,2 @@
|
||||||
pub mod astnode;
|
pub mod expression;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use super::astnode;
|
use super::expression::expression_node;
|
||||||
use super::astnode::{ASTNode, BinaryExpr};
|
|
||||||
use crate::error::ErrorLocationWrapper;
|
use crate::error::ErrorLocationWrapper;
|
||||||
use crate::lexer::{token, token::TokenType};
|
use crate::lexer::{token, token::TokenType};
|
||||||
|
|
||||||
|
@ -23,10 +22,10 @@ impl std::fmt::Display for InnerASTParsingError {
|
||||||
impl std::error::Error for InnerASTParsingError {}
|
impl std::error::Error for InnerASTParsingError {}
|
||||||
|
|
||||||
pub type ASTParsingError = ErrorLocationWrapper<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>>> {
|
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> {
|
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(),
|
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 tokens = Vec::new();
|
||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
|
|
||||||
|
@ -55,122 +56,4 @@ impl<'a, T: Iterator<Item = token::Token<'a>>> Parser<'a, T> {
|
||||||
Err(errors)
|
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
use super::types::Value;
|
use super::types::Value;
|
||||||
use crate::ast::astnode::{self, UnaryOperator};
|
use crate::ast::expression::expression_node;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RuntimeError;
|
pub struct RuntimeError;
|
||||||
|
@ -17,40 +17,40 @@ pub trait Interpret {
|
||||||
fn interpret(&self) -> Result<Value, RuntimeError>;
|
fn interpret(&self) -> Result<Value, RuntimeError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpret for astnode::ASTNode {
|
impl Interpret for expression_node::ExpressionNode {
|
||||||
fn interpret(&self) -> Result<Value, RuntimeError> {
|
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> {
|
fn interpret(&self) -> Result<Value, RuntimeError> {
|
||||||
Ok(self.clone().into())
|
Ok(self.clone().into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpret for astnode::BinaryExpr {
|
impl Interpret for expression_node::BinaryExpr {
|
||||||
fn interpret(&self) -> Result<Value, RuntimeError> {
|
fn interpret(&self) -> Result<Value, RuntimeError> {
|
||||||
let left_val = self.left.interpret().expect("expected lval");
|
let left_val = self.left.interpret().expect("expected lval");
|
||||||
let right_val = self.right.interpret().expect("expected rval");
|
let right_val = self.right.interpret().expect("expected rval");
|
||||||
match self.operator {
|
match self.operator {
|
||||||
astnode::Operator::BangEqual => Ok((left_val != right_val).into()),
|
expression_node::Operator::BangEqual => Ok((left_val != right_val).into()),
|
||||||
astnode::Operator::Less => Ok((left_val < right_val).into()),
|
expression_node::Operator::Less => Ok((left_val < right_val).into()),
|
||||||
astnode::Operator::LessEqual => Ok((left_val <= right_val).into()),
|
expression_node::Operator::LessEqual => Ok((left_val <= right_val).into()),
|
||||||
astnode::Operator::Greater => Ok((left_val > right_val).into()),
|
expression_node::Operator::Greater => Ok((left_val > right_val).into()),
|
||||||
astnode::Operator::GreaterEqual => Ok((left_val >= right_val).into()),
|
expression_node::Operator::GreaterEqual => Ok((left_val >= right_val).into()),
|
||||||
astnode::Operator::EqualEqual => Ok((left_val == right_val).into()),
|
expression_node::Operator::EqualEqual => Ok((left_val == right_val).into()),
|
||||||
astnode::Operator::Equal => todo!(),
|
expression_node::Operator::Equal => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpret for astnode::UnaryExpr {
|
impl Interpret for expression_node::UnaryExpr {
|
||||||
fn interpret(&self) -> Result<Value, RuntimeError> {
|
fn interpret(&self) -> Result<Value, RuntimeError> {
|
||||||
let val = self.right.interpret()?;
|
let val = self.right.interpret()?;
|
||||||
match self.operator {
|
match self.operator {
|
||||||
UnaryOperator::Bang => Ok(Value::Bool(!val.truthy())),
|
expression_node::UnaryOperator::Bang => Ok(Value::Bool(!val.truthy())),
|
||||||
UnaryOperator::Minus => match val {
|
expression_node::UnaryOperator::Minus => match val {
|
||||||
Value::Int(i) => Ok(Value::Int(-i)),
|
Value::Int(i) => Ok(Value::Int(-i)),
|
||||||
Value::Float(f) => Ok(Value::Float(-f)),
|
Value::Float(f) => Ok(Value::Float(-f)),
|
||||||
_ => Err(RuntimeError),
|
_ => 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> {
|
fn interpret(&self) -> Result<Value, RuntimeError> {
|
||||||
self.0.interpret()
|
self.0.interpret()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::ast::astnode;
|
use crate::ast::expression::expression_node;
|
||||||
use from_variants::FromVariants;
|
use from_variants::FromVariants;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, PartialOrd, FromVariants)]
|
#[derive(Debug, PartialEq, PartialOrd, FromVariants)]
|
||||||
|
@ -11,10 +11,10 @@ pub enum Value {
|
||||||
String(String),
|
String(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<astnode::Literal> for Value {
|
impl From<expression_node::Literal> for Value {
|
||||||
fn from(l: astnode::Literal) -> Self {
|
fn from(l: expression_node::Literal) -> Self {
|
||||||
match_any::match_any!(l,
|
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()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,8 @@ pub mod error;
|
||||||
pub mod interpreter;
|
pub mod interpreter;
|
||||||
pub mod lexer;
|
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::ast_walker::{Interpret, RuntimeError};
|
||||||
use interpreter::types::Value;
|
use interpreter::types::Value;
|
||||||
use lexer::{token::Token, Lexer, LexingError};
|
use lexer::{token::Token, Lexer, LexingError};
|
||||||
|
@ -16,12 +17,12 @@ pub fn lex<'a, 'b>(
|
||||||
lexer.scan_tokens()
|
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());
|
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()
|
nodes[0].interpret()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue