Compare commits

...

2 Commits

Author SHA1 Message Date
bad 3a5d81c8fb Statement parsing 2022-04-23 16:27:11 +02:00
bad 91f2a945c5 Extract expression node and expression parser to a separate file 2022-04-23 15:39:37 +02:00
17 changed files with 324 additions and 240 deletions

View File

@ -4,7 +4,7 @@ use match_any::match_any;
use std::fmt::{Debug, Display};
#[derive(FromVariants)]
pub enum ASTNode {
pub enum ExpressionNode {
BinaryExpr(BinaryExpr),
GroupingExpr(GroupingExpr),
Literal(Literal),
@ -15,15 +15,14 @@ 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)
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 ASTNode {
impl Debug for ExpressionNode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
all_variants!(self, n => n.fmt(f))
}
@ -124,13 +123,13 @@ pub enum Literal {
}
pub struct BinaryExpr {
pub left: Box<ASTNode>,
pub left: Box<ExpressionNode>,
pub operator: Operator,
pub right: Box<ASTNode>,
pub right: Box<ExpressionNode>,
}
impl BinaryExpr {
pub fn new(left: Box<ASTNode>, operator: Operator, right: Box<ASTNode>) -> Self {
pub fn new(left: Box<ExpressionNode>, operator: Operator, right: Box<ExpressionNode>) -> Self {
Self {
left,
operator,
@ -139,21 +138,21 @@ impl BinaryExpr {
}
}
pub struct GroupingExpr(pub Box<ASTNode>);
pub struct GroupingExpr(pub Box<ExpressionNode>);
impl GroupingExpr {
pub(crate) fn new(expr: Box<ASTNode>) -> Self {
pub(crate) fn new(expr: Box<ExpressionNode>) -> Self {
Self(expr)
}
}
pub struct UnaryExpr {
pub operator: UnaryOperator,
pub right: Box<ASTNode>,
pub right: Box<ExpressionNode>,
}
impl UnaryExpr {
pub fn new(operator: UnaryOperator, right: Box<ASTNode>) -> Self {
pub fn new(operator: UnaryOperator, right: Box<ExpressionNode>) -> Self {
Self { operator, right }
}
}
@ -181,14 +180,14 @@ mod tests {
use super::*;
#[test]
fn ast_printer() {
let ast = ASTNode::BinaryExpr(BinaryExpr {
left: Box::new(ASTNode::UnaryExpr(UnaryExpr {
fn expression_node_ast_printer() {
let ast = ExpressionNode::BinaryExpr(BinaryExpr {
left: Box::new(ExpressionNode::UnaryExpr(UnaryExpr {
operator: UnaryOperator::Bang,
right: Box::new(ASTNode::Literal(Literal::Int(1))),
right: Box::new(ExpressionNode::Literal(Literal::Int(1))),
})),
operator: Operator::EqualEqual,
right: Box::new(ASTNode::Literal(Literal::Int(0))),
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,3 @@
pub mod astnode;
pub mod expression;
pub mod statement;
pub mod parser;

View File

@ -1,5 +1,5 @@
use super::astnode;
use super::astnode::{ASTNode, BinaryExpr};
use super::expression::expression_node;
use super::statement::statement_node;
use crate::error::ErrorLocationWrapper;
use crate::lexer::{token, token::TokenType};
@ -23,154 +23,36 @@ 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>,
}
pub type ParseAllResult = StdResult<Vec<statement_node::Statement>, Vec<ASTParsingError>>;
impl<'a, T: Iterator<Item = token::Token<'a>>> Parser<'a, T> {
pub fn new(iter: T) -> Parser<'a, T> {
Parser {
token_iter: iter.peekable(),
}
}
pub fn scan_expressions(&mut self) -> StdResult<Vec<ASTNode>, Vec<ASTParsingError>> {
let mut tokens = Vec::new();
let mut errors = Vec::new();
pub fn parse_all(&mut self) -> ParseAllResult {
let mut res = Ok(Vec::new());
while self.token_iter.peek().is_some() {
match self.expression() {
Ok(token) => {
if errors.is_empty() {
tokens.push(token)
while !matches!(self.token_iter.peek().unwrap().token_type, token::TokenType::Eof) {
match self.statement() {
Ok(s) => {
if let Ok(ref mut v) = res {
v.push(s)
}
}
Err(e) => errors.push(e),
Err(e) => match res {
Ok(_) => res = Err(vec![e]),
Err(ref mut v) => v.push(e),
},
}
}
if errors.is_empty() {
Ok(tokens)
} else {
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)
res
}
}

2
src/ast/statement/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod statement_node;
mod statement_parser;

View File

@ -0,0 +1,24 @@
use crate::ast::expression::expression_node::ExpressionNode;
use from_variants::FromVariants;
#[derive(FromVariants, Debug)]
pub enum Statement {
Expression(ExpressionStatement),
Print(PrintStatement),
}
#[derive(Debug)]
pub struct ExpressionStatement(ExpressionNode);
impl ExpressionStatement {
pub fn new(expr: ExpressionNode) -> Self {
Self(expr)
}
}
#[derive(Debug)]
pub struct PrintStatement(ExpressionNode);
impl PrintStatement {
pub fn new(expr: ExpressionNode) -> Self {
Self(expr)
}
}

View File

@ -0,0 +1,37 @@
use super::statement_node::{ExpressionStatement, Statement, PrintStatement};
use crate::{
ast::parser::{ASTParsingError, Parser, Result},
lexer::token,
};
impl<'a, T: Iterator<Item = token::Token<'a>>> Parser<'a, T> {
pub fn statement(&mut self) -> Result<Statement> {
if let Some(_) = self
.token_iter
.next_if(|t| matches!(t.token_type, token::TokenType::Print))
{
self.print_statement()
} else {
self.expression_statement()
}
}
fn print_statement(&mut self) -> Result<Statement> {
let expr = self.expression()?;
if let token::TokenType::Semicolon = self.token_iter.peek().unwrap().token_type {
self.token_iter.next();
Ok(PrintStatement::new(expr).into())
} else {
panic!();
}
}
fn expression_statement(&mut self) -> Result<Statement> {
let expr = self.expression()?;
if let token::TokenType::Semicolon = self.token_iter.peek().unwrap().token_type {
self.token_iter.next();
Ok(ExpressionStatement::new(expr).into())
} else {
panic!();
}
}
}

View File

@ -1,66 +0,0 @@
use std::fmt::Display;
use super::types::Value;
use crate::ast::astnode::{self, UnaryOperator};
#[derive(Debug)]
pub struct RuntimeError;
impl Display for RuntimeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "A runtime error occured")
}
}
impl std::error::Error for RuntimeError {}
pub trait Interpret {
fn interpret(&self) -> Result<Value, RuntimeError>;
}
impl Interpret for astnode::ASTNode {
fn interpret(&self) -> Result<Value, RuntimeError> {
astnode::all_variants!(self, n => n.interpret())
}
}
impl Interpret for astnode::Literal {
fn interpret(&self) -> Result<Value, RuntimeError> {
Ok(self.clone().into())
}
}
impl Interpret for astnode::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!(),
}
}
}
impl Interpret for astnode::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 {
Value::Int(i) => Ok(Value::Int(-i)),
Value::Float(f) => Ok(Value::Float(-f)),
_ => Err(RuntimeError),
},
}
}
}
impl Interpret for astnode::GroupingExpr {
fn interpret(&self) -> Result<Value, RuntimeError> {
self.0.interpret()
}
}

View File

@ -0,0 +1,53 @@
use super::{RuntimeError, types::Value};
use super::Interpret;
use crate::ast::expression::expression_node;
impl Interpret for expression_node::ExpressionNode {
fn interpret(&self) -> Result<Value, RuntimeError> {
expression_node::all_variants!(self, n => n.interpret())
}
}
impl Interpret for expression_node::Literal {
fn interpret(&self) -> Result<Value, RuntimeError> {
Ok(self.clone().into())
}
}
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 {
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 expression_node::UnaryExpr {
fn interpret(&self) -> Result<Value, RuntimeError> {
let val = self.right.interpret()?;
match self.operator {
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),
},
}
}
}
impl Interpret for expression_node::GroupingExpr {
fn interpret(&self) -> Result<Value, RuntimeError> {
self.0.interpret()
}
}

View File

@ -0,0 +1,7 @@
mod expression_interpreter;
pub use super::{error::RuntimeError, types};
use super::types::Value;
pub trait Interpret {
fn interpret(&self) -> Result<Value, RuntimeError>;
}

11
src/interpreter/error.rs Normal file
View File

@ -0,0 +1,11 @@
use std::fmt::Display;
#[derive(Debug)]
pub struct RuntimeError;
impl Display for RuntimeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "A runtime error occured")
}
}
impl std::error::Error for RuntimeError {}

View File

@ -1,2 +1,3 @@
pub mod ast_walker;
pub mod types;
pub mod error;

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

@ -25,26 +25,26 @@ impl<'a, 'b> Lexer<'a, 'b> {
}
pub fn scan_tokens(&mut self) -> Result<Vec<token::Token<'b>>, Vec<LexingError>> {
let mut tokens = Vec::new();
let mut errors = Vec::new();
let mut res = Ok(Vec::new());
while self.source_iter.peek().is_some() {
match self.scan_token() {
Ok(Some(token)) => {
if errors.is_empty() {
tokens.push(token)
}
Ok(Some(token)) => if let Ok(ref mut v) = res {
v.push(token)
}
Ok(None) => (),
Err(e) => errors.push(e),
Err(e) => match res {
Ok(_) => res = Err(vec![e]),
Err(ref mut v) => v.push(e)
}
}
}
if errors.is_empty() {
Ok(tokens)
} else {
Err(errors)
if let Ok(ref mut v) = res {
v.push(self.get_token(token::TokenType::Eof));
}
res
}
fn get_token(&self, token_type: token::TokenType) -> token::Token<'b> {

View File

@ -47,4 +47,5 @@ pub enum TokenType {
True,
Let,
While,
Eof,
}

View File

@ -3,7 +3,8 @@ pub mod error;
pub mod interpreter;
pub mod lexer;
use ast::{astnode::ASTNode, parser::ASTParsingError};
use ast::parser::ParseAllResult;
use ast::statement::statement_node::Statement;
use interpreter::ast_walker::{Interpret, RuntimeError};
use interpreter::types::Value;
use lexer::{token::Token, Lexer, LexingError};
@ -16,13 +17,18 @@ 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>) -> ParseAllResult {
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> {
nodes[0].interpret()
pub fn exec(nodes: Vec<Statement>) -> Result<Value, RuntimeError> {
todo!();
/*
for statement in nodes {
//statement.interpret()?;
}
*/
}
pub fn run(code: &str) -> Result<Value, run::Error> {