From 4ea19f238eee2f3a212b85116a44d2cc77177e0e Mon Sep 17 00:00:00 2001 From: Jeff Date: Sun, 17 Mar 2024 07:31:45 -0400 Subject: [PATCH] Fix tests; Refine parsing --- src/abstract_tree/assignment.rs | 46 ++---- src/abstract_tree/block.rs | 36 ++--- src/abstract_tree/function_call.rs | 11 +- src/abstract_tree/if_else.rs | 51 ++++--- src/abstract_tree/index.rs | 8 +- src/abstract_tree/logic.rs | 76 +++++----- src/abstract_tree/loop.rs | 8 +- src/abstract_tree/math.rs | 12 +- src/abstract_tree/mod.rs | 6 +- src/abstract_tree/statement.rs | 12 +- src/abstract_tree/value_node.rs | 20 ++- src/abstract_tree/while.rs | 6 +- src/error.rs | 9 +- src/lib.rs | 13 +- src/parser.rs | 217 ++++++++++++++--------------- src/value.rs | 14 +- tests/functions.rs | 2 +- tests/values.rs | 14 +- tests/variables.rs | 32 +++-- 19 files changed, 291 insertions(+), 302 deletions(-) diff --git a/src/abstract_tree/assignment.rs b/src/abstract_tree/assignment.rs index 8610b4e..74c5eb9 100644 --- a/src/abstract_tree/assignment.rs +++ b/src/abstract_tree/assignment.rs @@ -3,14 +3,14 @@ use crate::{ Context, }; -use super::{AbstractTree, Action, Identifier, Positioned, Statement, Type}; +use super::{AbstractTree, Action, Identifier, Statement, Type, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct Assignment { identifier: Identifier, - r#type: Option>, + r#type: Option>, operator: AssignmentOperator, - statement: Box>, + statement: Box>, } #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] @@ -23,9 +23,9 @@ pub enum AssignmentOperator { impl Assignment { pub fn new( identifier: Identifier, - r#type: Option>, + r#type: Option>, operator: AssignmentOperator, - statement: Positioned, + statement: WithPosition, ) -> Self { Self { identifier, @@ -44,7 +44,7 @@ impl AbstractTree for Assignment { fn validate(&self, context: &Context) -> Result<(), ValidationError> { let statement_type = self.statement.node.expected_type(context)?; - if let Some(Positioned { + if let Some(WithPosition { node: expected_type, position: expected_position, }) = &self.r#type @@ -125,12 +125,8 @@ mod tests { Identifier::new("foobar"), None, AssignmentOperator::Assign, - Positioned { - node: Statement::Expression( - Expression::Value(ValueNode::Integer(42)).positioned((0..1).into()), - ), - position: (0, 0), - }, + Statement::Expression(Expression::Value(ValueNode::Integer(42))) + .with_position((0..0).into()), ) .run(&context) .unwrap(); @@ -153,12 +149,8 @@ mod tests { Identifier::new("foobar"), None, AssignmentOperator::AddAssign, - Positioned { - node: Statement::Expression( - Expression::Value(ValueNode::Integer(41)).positioned((0..1).into()), - ), - position: (0, 0), - }, + Statement::Expression(Expression::Value(ValueNode::Integer(41))) + .with_position((0..0).into()), ) .run(&context) .unwrap(); @@ -181,12 +173,8 @@ mod tests { Identifier::new("foobar"), None, AssignmentOperator::SubAssign, - Positioned { - node: Statement::Expression( - Expression::Value(ValueNode::Integer(1)).positioned((0..1).into()), - ), - position: (0, 0), - }, + Statement::Expression(Expression::Value(ValueNode::Integer(1))) + .with_position((0..0).into()), ) .run(&context) .unwrap(); @@ -201,17 +189,13 @@ mod tests { fn type_check() { let validation = Assignment::new( Identifier::new("foobar"), - Some(Positioned { + Some(WithPosition { node: Type::Boolean, position: (0, 0), }), AssignmentOperator::Assign, - Positioned { - node: Statement::Expression( - Expression::Value(ValueNode::Integer(42)).positioned((0..1).into()), - ), - position: (0, 0), - }, + Statement::Expression(Expression::Value(ValueNode::Integer(42))) + .with_position((0..0).into()), ) .validate(&Context::new()); diff --git a/src/abstract_tree/block.rs b/src/abstract_tree/block.rs index 9104ad6..ebb4d8e 100644 --- a/src/abstract_tree/block.rs +++ b/src/abstract_tree/block.rs @@ -3,15 +3,15 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{AbstractTree, Action, Positioned, Statement, Type}; +use super::{AbstractTree, Action, Statement, Type, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct Block { - statements: Vec>, + statements: Vec>, } impl Block { - pub fn new(statements: Vec>) -> Self { + pub fn new(statements: Vec>) -> Self { Self { statements } } } @@ -61,18 +61,12 @@ mod tests { #[test] fn run_returns_value_of_final_statement() { let block = Block::new(vec![ - Statement::Expression( - Expression::Value(ValueNode::Integer(1)).positioned((0..0).into()), - ) - .positioned((0..0).into()), - Statement::Expression( - Expression::Value(ValueNode::Integer(2)).positioned((0..0).into()), - ) - .positioned((0..0).into()), - Statement::Expression( - Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), - ) - .positioned((0..0).into()), + Statement::Expression(Expression::Value(ValueNode::Integer(1))) + .with_position((0..0).into()), + Statement::Expression(Expression::Value(ValueNode::Integer(2))) + .with_position((0..0).into()), + Statement::Expression(Expression::Value(ValueNode::Integer(42))) + .with_position((0..0).into()), ]); assert_eq!( @@ -84,14 +78,10 @@ mod tests { #[test] fn expected_type_returns_type_of_final_statement() { let block = Block::new(vec![ - Statement::Expression( - Expression::Value(ValueNode::String("42".to_string())).positioned((0..0).into()), - ) - .positioned((0..0).into()), - Statement::Expression( - Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), - ) - .positioned((0..0).into()), + Statement::Expression(Expression::Value(ValueNode::String("42".to_string()))) + .with_position((0..0).into()), + Statement::Expression(Expression::Value(ValueNode::Integer(42))) + .with_position((0..0).into()), ]); assert_eq!(block.expected_type(&Context::new()), Ok(Type::Integer)) diff --git a/src/abstract_tree/function_call.rs b/src/abstract_tree/function_call.rs index c74c3ce..50070fe 100644 --- a/src/abstract_tree/function_call.rs +++ b/src/abstract_tree/function_call.rs @@ -3,16 +3,19 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{AbstractTree, Action, Expression, Positioned, Type}; +use super::{AbstractTree, Action, Expression, Type, WithPosition}; #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct FunctionCall { - function: Box>, - arguments: Vec>, + function: Box>, + arguments: Vec>, } impl FunctionCall { - pub fn new(function: Positioned, arguments: Vec>) -> Self { + pub fn new( + function: WithPosition, + arguments: Vec>, + ) -> Self { FunctionCall { function: Box::new(function), arguments, diff --git a/src/abstract_tree/if_else.rs b/src/abstract_tree/if_else.rs index 00a2ba0..a3e1c94 100644 --- a/src/abstract_tree/if_else.rs +++ b/src/abstract_tree/if_else.rs @@ -3,20 +3,20 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{AbstractTree, Action, Block, Expression, Positioned, Type}; +use super::{AbstractTree, Action, Block, Expression, Type, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct IfElse { - if_expression: Positioned, - if_block: Positioned, - else_block: Option>, + if_expression: WithPosition, + if_block: WithPosition, + else_block: Option>, } impl IfElse { pub fn new( - if_expression: Positioned, - if_block: Positioned, - else_block: Option>, + if_expression: WithPosition, + if_block: WithPosition, + else_block: Option>, ) -> Self { Self { if_expression, @@ -83,13 +83,12 @@ mod tests { fn simple_if() { assert_eq!( IfElse::new( - Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()), - Block::new(vec![Statement::Expression( - Expression::Value(ValueNode::String("foo".to_string())) - .positioned((0..0).into()) - ) - .positioned((0..0).into())]) - .positioned((0..0).into()), + Expression::Value(ValueNode::Boolean(true)).with_position((0..0).into()), + Block::new(vec![Statement::Expression(Expression::Value( + ValueNode::String("foo".to_string()) + )) + .with_position((0..0).into())]) + .with_position((0..0).into()), None ) .run(&Context::new()), @@ -101,20 +100,18 @@ mod tests { fn simple_if_else() { assert_eq!( IfElse::new( - Expression::Value(ValueNode::Boolean(false)).positioned((0..0).into()), - Block::new(vec![Statement::Expression( - Expression::Value(ValueNode::String("foo".to_string())) - .positioned((0..0).into()) - ) - .positioned((0..0).into())]) - .positioned((0..0).into()), + Expression::Value(ValueNode::Boolean(false)).with_position((0..0).into()), + Block::new(vec![Statement::Expression(Expression::Value( + ValueNode::String("foo".to_string()) + )) + .with_position((0..0).into())]) + .with_position((0..0).into()), Some( - Block::new(vec![Statement::Expression( - Expression::Value(ValueNode::String("bar".to_string())) - .positioned((0..0).into()) - ) - .positioned((0..0).into())]) - .positioned((0..0).into()) + Block::new(vec![Statement::Expression(Expression::Value( + ValueNode::String("bar".to_string()) + )) + .with_position((0..0).into())]) + .with_position((0..0).into()) ) ) .run(&Context::new()), diff --git a/src/abstract_tree/index.rs b/src/abstract_tree/index.rs index 842df5d..18daadf 100644 --- a/src/abstract_tree/index.rs +++ b/src/abstract_tree/index.rs @@ -3,16 +3,16 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{AbstractTree, Action, Expression, Positioned, Type, ValueNode}; +use super::{AbstractTree, Action, Expression, Type, ValueNode, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct Index { - left: Positioned, - right: Positioned, + left: WithPosition, + right: WithPosition, } impl Index { - pub fn new(left: Positioned, right: Positioned) -> Self { + pub fn new(left: WithPosition, right: WithPosition) -> Self { Self { left, right } } } diff --git a/src/abstract_tree/logic.rs b/src/abstract_tree/logic.rs index 4e0da20..0faebb1 100644 --- a/src/abstract_tree/logic.rs +++ b/src/abstract_tree/logic.rs @@ -4,19 +4,19 @@ use crate::{ Value, }; -use super::{AbstractTree, Action, Expression, Positioned, Type}; +use super::{AbstractTree, Action, Expression, Type, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum Logic { - Equal(Positioned, Positioned), - NotEqual(Positioned, Positioned), - Greater(Positioned, Positioned), - Less(Positioned, Positioned), - GreaterOrEqual(Positioned, Positioned), - LessOrEqual(Positioned, Positioned), - And(Positioned, Positioned), - Or(Positioned, Positioned), - Not(Positioned), + Equal(WithPosition, WithPosition), + NotEqual(WithPosition, WithPosition), + Greater(WithPosition, WithPosition), + Less(WithPosition, WithPosition), + GreaterOrEqual(WithPosition, WithPosition), + LessOrEqual(WithPosition, WithPosition), + And(WithPosition, WithPosition), + Or(WithPosition, WithPosition), + Not(WithPosition), } impl AbstractTree for Logic { @@ -139,8 +139,8 @@ mod tests { #[test] fn equal() { assert!(Logic::Equal( - Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), - Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), + Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()), + Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -153,8 +153,8 @@ mod tests { #[test] fn not_equal() { assert!(Logic::NotEqual( - Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), - Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()), + Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()), + Expression::Value(ValueNode::Integer(43)).with_position((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -167,8 +167,8 @@ mod tests { #[test] fn greater() { assert!(Logic::Greater( - Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()), - Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), + Expression::Value(ValueNode::Integer(43)).with_position((0..0).into()), + Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -181,8 +181,8 @@ mod tests { #[test] fn less() { assert!(Logic::Less( - Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), - Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()), + Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()), + Expression::Value(ValueNode::Integer(43)).with_position((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -195,8 +195,8 @@ mod tests { #[test] fn greater_or_equal() { assert!(Logic::GreaterOrEqual( - Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), - Expression::Value(ValueNode::Integer(41)).positioned((0..0).into()), + Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()), + Expression::Value(ValueNode::Integer(41)).with_position((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -206,8 +206,8 @@ mod tests { .unwrap()); assert!(Logic::GreaterOrEqual( - Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), - Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), + Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()), + Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -220,8 +220,8 @@ mod tests { #[test] fn less_or_equal() { assert!(Logic::LessOrEqual( - Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), - Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()), + Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()), + Expression::Value(ValueNode::Integer(43)).with_position((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -231,8 +231,8 @@ mod tests { .unwrap()); assert!(Logic::LessOrEqual( - Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), - Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), + Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()), + Expression::Value(ValueNode::Integer(42)).with_position((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -245,8 +245,8 @@ mod tests { #[test] fn and() { assert!(Logic::And( - Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()), - Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()), + Expression::Value(ValueNode::Boolean(true)).with_position((0..0).into()), + Expression::Value(ValueNode::Boolean(true)).with_position((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -259,8 +259,8 @@ mod tests { #[test] fn or() { assert!(Logic::Or( - Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()), - Expression::Value(ValueNode::Boolean(false)).positioned((0..0).into()), + Expression::Value(ValueNode::Boolean(true)).with_position((0..0).into()), + Expression::Value(ValueNode::Boolean(false)).with_position((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -272,14 +272,14 @@ mod tests { #[test] fn not() { - assert!( - Logic::Not(Expression::Value(ValueNode::Boolean(false)).positioned((0..0).into())) - .run(&Context::new()) - .unwrap() - .as_return_value() - .unwrap() - .as_boolean() - .unwrap() + assert!(Logic::Not( + Expression::Value(ValueNode::Boolean(false)).with_position((0..0).into()) ) + .run(&Context::new()) + .unwrap() + .as_return_value() + .unwrap() + .as_boolean() + .unwrap()) } } diff --git a/src/abstract_tree/loop.rs b/src/abstract_tree/loop.rs index 06fb13a..3161a25 100644 --- a/src/abstract_tree/loop.rs +++ b/src/abstract_tree/loop.rs @@ -3,15 +3,15 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{AbstractTree, Action, Positioned, Statement, Type}; +use super::{AbstractTree, Action, Statement, Type, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct Loop { - statements: Vec>, + statements: Vec>, } impl Loop { - pub fn new(statements: Vec>) -> Self { + pub fn new(statements: Vec>) -> Self { Self { statements } } } @@ -58,7 +58,7 @@ mod tests { #[test] fn basic_loop() { let result = Loop { - statements: vec![Statement::Break.positioned((0..0).into())], + statements: vec![Statement::Break.with_position((0..0).into())], } .run(&Context::new()); diff --git a/src/abstract_tree/math.rs b/src/abstract_tree/math.rs index b25bccd..f63ff2e 100644 --- a/src/abstract_tree/math.rs +++ b/src/abstract_tree/math.rs @@ -5,15 +5,15 @@ use crate::{ Value, }; -use super::{AbstractTree, Action, Expression, Positioned, Type}; +use super::{AbstractTree, Action, Expression, Type, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum Math { - Add(Positioned, Positioned), - Subtract(Positioned, Positioned), - Multiply(Positioned, Positioned), - Divide(Positioned, Positioned), - Modulo(Positioned, Positioned), + Add(WithPosition, WithPosition), + Subtract(WithPosition, WithPosition), + Multiply(WithPosition, WithPosition), + Divide(WithPosition, WithPosition), + Modulo(WithPosition, WithPosition), } impl AbstractTree for Math { diff --git a/src/abstract_tree/mod.rs b/src/abstract_tree/mod.rs index be2e874..3cd4f82 100644 --- a/src/abstract_tree/mod.rs +++ b/src/abstract_tree/mod.rs @@ -39,7 +39,7 @@ use crate::{ }; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub struct Positioned { +pub struct WithPosition { pub node: T, pub position: (usize, usize), } @@ -49,8 +49,8 @@ pub trait AbstractTree: Sized { fn validate(&self, context: &Context) -> Result<(), ValidationError>; fn run(self, context: &Context) -> Result; - fn positioned(self, span: SimpleSpan) -> Positioned { - Positioned { + fn with_position(self, span: SimpleSpan) -> WithPosition { + WithPosition { node: self, position: (span.start(), span.end()), } diff --git a/src/abstract_tree/statement.rs b/src/abstract_tree/statement.rs index 8a03245..af8afd6 100644 --- a/src/abstract_tree/statement.rs +++ b/src/abstract_tree/statement.rs @@ -3,16 +3,14 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{ - AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Positioned, Type, While, -}; +use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Type, While}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum Statement { Assignment(Assignment), Block(Block), Break, - Expression(Positioned), + Expression(Expression), IfElse(IfElse), Loop(Loop), While(While), @@ -24,7 +22,7 @@ impl AbstractTree for Statement { Statement::Assignment(assignment) => assignment.expected_type(_context), Statement::Block(block) => block.expected_type(_context), Statement::Break => Ok(Type::None), - Statement::Expression(expression) => expression.node.expected_type(_context), + Statement::Expression(expression) => expression.expected_type(_context), Statement::IfElse(if_else) => if_else.expected_type(_context), Statement::Loop(r#loop) => r#loop.expected_type(_context), Statement::While(r#while) => r#while.expected_type(_context), @@ -36,7 +34,7 @@ impl AbstractTree for Statement { Statement::Assignment(assignment) => assignment.validate(_context), Statement::Block(block) => block.validate(_context), Statement::Break => Ok(()), - Statement::Expression(expression) => expression.node.validate(_context), + Statement::Expression(expression) => expression.validate(_context), Statement::IfElse(if_else) => if_else.validate(_context), Statement::Loop(r#loop) => r#loop.validate(_context), Statement::While(r#while) => r#while.validate(_context), @@ -48,7 +46,7 @@ impl AbstractTree for Statement { Statement::Assignment(assignment) => assignment.run(_context), Statement::Block(block) => block.run(_context), Statement::Break => Ok(Action::Break), - Statement::Expression(expression) => expression.node.run(_context), + Statement::Expression(expression) => expression.run(_context), Statement::IfElse(if_else) => if_else.run(_context), Statement::Loop(r#loop) => r#loop.run(_context), Statement::While(r#while) => r#while.run(_context), diff --git a/src/abstract_tree/value_node.rs b/src/abstract_tree/value_node.rs index 6b16a40..af56ea5 100644 --- a/src/abstract_tree/value_node.rs +++ b/src/abstract_tree/value_node.rs @@ -6,21 +6,27 @@ use crate::{ Value, }; -use super::{AbstractTree, Action, Block, Expression, Identifier, Positioned, Type}; +use super::{AbstractTree, Action, Block, Expression, Identifier, Type, WithPosition}; #[derive(Clone, Debug, PartialEq)] pub enum ValueNode { Boolean(bool), Float(f64), Integer(i64), - List(Vec>), - Map(Vec<(Identifier, Option>, Positioned)>), + List(Vec>), + Map( + Vec<( + Identifier, + Option>, + WithPosition, + )>, + ), Range(Range), String(String), Function { - parameters: Vec<(Identifier, Positioned)>, - return_type: Positioned, - body: Positioned, + parameters: Vec<(Identifier, WithPosition)>, + return_type: WithPosition, + body: WithPosition, }, } @@ -70,7 +76,7 @@ impl AbstractTree for ValueNode { actual_position: expression.position, expected_position: expected_type.position, } - }); + })?; } } } diff --git a/src/abstract_tree/while.rs b/src/abstract_tree/while.rs index 76ca90f..215c399 100644 --- a/src/abstract_tree/while.rs +++ b/src/abstract_tree/while.rs @@ -3,16 +3,16 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{AbstractTree, Action, Block, Expression, Positioned, Type}; +use super::{AbstractTree, Action, Block, Expression, Type, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct While { - expression: Positioned, + expression: WithPosition, block: Block, } impl While { - pub fn new(expression: Positioned, block: Block) -> Self { + pub fn new(expression: WithPosition, block: Block) -> Self { Self { expression, block } } } diff --git a/src/error.rs b/src/error.rs index 1c60601..73d6a0c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -19,7 +19,10 @@ pub enum Error { span: (usize, usize), }, Runtime(RuntimeError), - Validation(ValidationError, (usize, usize)), + Validation { + error: ValidationError, + position: (usize, usize), + }, } impl Error { @@ -46,7 +49,7 @@ impl Error { .finish() } Error::Runtime(_) => todo!(), - Error::Validation(validation_error, position) => { + Error::Validation { error, position } => { let mut report = Report::build( ReportKind::Custom("Validation Error: The code was not run.", Color::White), (), @@ -56,7 +59,7 @@ impl Error { Label::new(position.0..position.1).with_message("Error found in this item."), ); - match validation_error { + match error { ValidationError::ExpectedBoolean => { report = report.with_label(Label::new(0..0).with_message("Expected boolean.")); diff --git a/src/lib.rs b/src/lib.rs index da678f2..0ff6f6a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ pub mod lexer; pub mod parser; pub mod value; -use abstract_tree::{AbstractTree, Action}; +use abstract_tree::{AbstractTree, Action, WithPosition}; use context::Context; use error::Error; use lexer::lex; @@ -33,12 +33,13 @@ impl Interpreter { let statements = parse(&tokens)?; let errors = statements .iter() - .filter_map(|statement| { - statement - .node - .validate(&self.context) + .filter_map(|WithPosition { node, position }| { + node.validate(&self.context) .err() - .map(|validation_error| Error::Validation(validation_error, statement.position)) + .map(|error| Error::Validation { + error, + position: position.clone(), + }) }) .collect::>(); diff --git a/src/parser.rs b/src/parser.rs index ccb5bba..0de6cd8 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -12,7 +12,7 @@ pub type DustParser<'src> = Boxed< 'src, 'src, ParserInput<'src>, - Vec>, + Vec>, extra::Err, SimpleSpan>>, >; @@ -21,7 +21,7 @@ pub type ParserInput<'src> = pub fn parse<'src>( tokens: &'src [(Token<'src>, SimpleSpan)], -) -> Result>, Vec> { +) -> Result>, Vec> { parser() .parse(tokens.spanned((tokens.len()..tokens.len()).into())) .into_result() @@ -53,7 +53,7 @@ pub fn parser<'src>() -> DustParser<'src> { Token::Float(float) => ValueNode::Float(float), Token::String(string) => ValueNode::String(string.to_string()), } - .map_with(|value, state| Expression::Value(value).positioned(state.span())) + .map_with(|value, state| Expression::Value(value).with_position(state.span())) .boxed(); let r#type = recursive(|r#type| { @@ -106,12 +106,12 @@ pub fn parser<'src>() -> DustParser<'src> { .map(|identifier| Type::Custom(identifier)), )) }) - .map_with(|r#type, state| r#type.positioned(state.span())); + .map_with(|r#type, state| r#type.with_position(state.span())); let type_specification = just(Token::Control(Control::Colon)).ignore_then(r#type.clone()); - let statement = recursive(|statement| { - let block = statement + let positioned_statement = recursive(|positioned_statement| { + let block = positioned_statement .clone() .repeated() .collect() @@ -123,11 +123,11 @@ pub fn parser<'src>() -> DustParser<'src> { let positioned_block = block .clone() - .map_with(|block, state| block.positioned(state.span())); + .map_with(|block, state| block.with_position(state.span())); - let expression = recursive(|expression| { + let positioned_expression = recursive(|positioned_expression| { let identifier_expression = identifier.clone().map_with(|identifier, state| { - Expression::Identifier(identifier).positioned(state.span()) + Expression::Identifier(identifier).with_position(state.span()) }); let range = { @@ -140,11 +140,11 @@ pub fn parser<'src>() -> DustParser<'src> { .then_ignore(just(Token::Control(Control::DoubleDot))) .then(raw_integer) .map_with(|(start, end), state| { - Expression::Value(ValueNode::Range(start..end)).positioned(state.span()) + Expression::Value(ValueNode::Range(start..end)).with_position(state.span()) }) }; - let list = expression + let list = positioned_expression .clone() .separated_by(just(Token::Control(Control::Comma))) .allow_trailing() @@ -154,14 +154,14 @@ pub fn parser<'src>() -> DustParser<'src> { just(Token::Control(Control::SquareClose)), ) .map_with(|list, state| { - Expression::Value(ValueNode::List(list)).positioned(state.span()) + Expression::Value(ValueNode::List(list)).with_position(state.span()) }); let map_assignment = identifier .clone() .then(type_specification.clone().or_not()) .then_ignore(just(Token::Operator(Operator::Assign))) - .then(expression.clone()) + .then(positioned_expression.clone()) .map(|((identifier, r#type), expression)| (identifier, r#type, expression)); let map = map_assignment @@ -173,7 +173,8 @@ pub fn parser<'src>() -> DustParser<'src> { just(Token::Control(Control::CurlyClose)), ) .map_with(|map_assigment_list, state| { - Expression::Value(ValueNode::Map(map_assigment_list)).positioned(state.span()) + Expression::Value(ValueNode::Map(map_assigment_list)) + .with_position(state.span()) }); let function = identifier @@ -191,16 +192,16 @@ pub fn parser<'src>() -> DustParser<'src> { Expression::Value(ValueNode::Function { parameters, return_type, - body: body.positioned(state.span()), + body: body.with_position(state.span()), }) - .positioned(state.span()) + .with_position(state.span()) }); let function_expression = choice((identifier_expression.clone(), function.clone())); let function_call = function_expression .then( - expression + positioned_expression .clone() .separated_by(just(Token::Control(Control::Comma))) .collect() @@ -211,7 +212,7 @@ pub fn parser<'src>() -> DustParser<'src> { ) .map_with(|(function, arguments), state| { Expression::FunctionCall(FunctionCall::new(function, arguments)) - .positioned(state.span()) + .with_position(state.span()) }); let atom = choice(( @@ -219,7 +220,7 @@ pub fn parser<'src>() -> DustParser<'src> { identifier_expression.clone(), basic_value.clone(), list.clone(), - expression.clone().delimited_by( + positioned_expression.clone().delimited_by( just(Token::Control(Control::ParenOpen)), just(Token::Control(Control::ParenClose)), ), @@ -229,41 +230,42 @@ pub fn parser<'src>() -> DustParser<'src> { let logic_math_and_index = atom.pratt(( prefix(2, just(Token::Operator(Not)), |_, expression, span| { - Expression::Logic(Box::new(Logic::Not(expression))).positioned(span) + Expression::Logic(Box::new(Logic::Not(expression))).with_position(span) }), infix( left(3), just(Token::Control(Control::Dot)), |left, _, right, span| { - Expression::Index(Box::new(Index::new(left, right))).positioned(span) + Expression::Index(Box::new(Index::new(left, right))).with_position(span) }, ), infix( left(1), just(Token::Operator(Equal)), |left, _, right, span| { - Expression::Logic(Box::new(Logic::Equal(left, right))).positioned(span) + Expression::Logic(Box::new(Logic::Equal(left, right))).with_position(span) }, ), infix( left(1), just(Token::Operator(NotEqual)), |left, _, right, span| { - Expression::Logic(Box::new(Logic::NotEqual(left, right))).positioned(span) + Expression::Logic(Box::new(Logic::NotEqual(left, right))) + .with_position(span) }, ), infix( left(1), just(Token::Operator(Greater)), |left, _, right, span| { - Expression::Logic(Box::new(Logic::Greater(left, right))).positioned(span) + Expression::Logic(Box::new(Logic::Greater(left, right))).with_position(span) }, ), infix( left(1), just(Token::Operator(Less)), |left, _, right, span| { - Expression::Logic(Box::new(Logic::Less(left, right))).positioned(span) + Expression::Logic(Box::new(Logic::Less(left, right))).with_position(span) }, ), infix( @@ -271,7 +273,7 @@ pub fn parser<'src>() -> DustParser<'src> { just(Token::Operator(GreaterOrEqual)), |left, _, right, span| { Expression::Logic(Box::new(Logic::GreaterOrEqual(left, right))) - .positioned(span) + .with_position(span) }, ), infix( @@ -279,56 +281,56 @@ pub fn parser<'src>() -> DustParser<'src> { just(Token::Operator(LessOrEqual)), |left, _, right, span| { Expression::Logic(Box::new(Logic::LessOrEqual(left, right))) - .positioned(span) + .with_position(span) }, ), infix( left(1), just(Token::Operator(And)), |left, _, right, span| { - Expression::Logic(Box::new(Logic::And(left, right))).positioned(span) + Expression::Logic(Box::new(Logic::And(left, right))).with_position(span) }, ), infix( left(1), just(Token::Operator(Or)), |left, _, right, span| { - Expression::Logic(Box::new(Logic::Or(left, right))).positioned(span) + Expression::Logic(Box::new(Logic::Or(left, right))).with_position(span) }, ), infix( left(1), just(Token::Operator(Add)), |left, _, right, span| { - Expression::Math(Box::new(Math::Add(left, right))).positioned(span) + Expression::Math(Box::new(Math::Add(left, right))).with_position(span) }, ), infix( left(1), just(Token::Operator(Subtract)), |left, _, right, span| { - Expression::Math(Box::new(Math::Subtract(left, right))).positioned(span) + Expression::Math(Box::new(Math::Subtract(left, right))).with_position(span) }, ), infix( left(2), just(Token::Operator(Multiply)), |left, _, right, span| { - Expression::Math(Box::new(Math::Multiply(left, right))).positioned(span) + Expression::Math(Box::new(Math::Multiply(left, right))).with_position(span) }, ), infix( left(2), just(Token::Operator(Divide)), |left, _, right, span| { - Expression::Math(Box::new(Math::Divide(left, right))).positioned(span) + Expression::Math(Box::new(Math::Divide(left, right))).with_position(span) }, ), infix( left(1), just(Token::Operator(Modulo)), |left, _, right, span| { - Expression::Math(Box::new(Math::Modulo(left, right))).positioned(span) + Expression::Math(Box::new(Math::Modulo(left, right))).with_position(span) }, ), )); @@ -345,12 +347,15 @@ pub fn parser<'src>() -> DustParser<'src> { )) }); - let expression_statement = expression.clone().map_with(|expression, state| { - Statement::Expression(expression).positioned(state.span()) - }); + let expression_statement = + positioned_expression + .clone() + .map_with(|positioned_expression, state| { + Statement::Expression(positioned_expression.node).with_position(state.span()) + }); let r#break = just(Token::Keyword("break")) - .map_with(|_, state| Statement::Break.positioned(state.span())); + .map_with(|_, state| Statement::Break.with_position(state.span())); let assignment = identifier .clone() @@ -360,17 +365,17 @@ pub fn parser<'src>() -> DustParser<'src> { just(Token::Operator(Operator::AddAssign)).to(AssignmentOperator::AddAssign), just(Token::Operator(Operator::SubAssign)).to(AssignmentOperator::SubAssign), ))) - .then(statement.clone()) + .then(positioned_statement.clone()) .map_with(|(((identifier, r#type), operator), statement), state| { Statement::Assignment(Assignment::new(identifier, r#type, operator, statement)) - .positioned(state.span()) + .with_position(state.span()) }); let block_statement = block .clone() - .map_with(|block, state| Statement::Block(block).positioned(state.span())); + .map_with(|block, state| Statement::Block(block).with_position(state.span())); - let r#loop = statement + let r#loop = positioned_statement .clone() .repeated() .at_least(1) @@ -380,18 +385,18 @@ pub fn parser<'src>() -> DustParser<'src> { just(Token::Control(Control::CurlyClose)), ) .map_with(|statements, state| { - Statement::Loop(Loop::new(statements)).positioned(state.span()) + Statement::Loop(Loop::new(statements)).with_position(state.span()) }); let r#while = just(Token::Keyword("while")) - .ignore_then(expression.clone()) + .ignore_then(positioned_expression.clone()) .then(block.clone()) .map_with(|(expression, block), state| { - Statement::While(While::new(expression, block)).positioned(state.span()) + Statement::While(While::new(expression, block)).with_position(state.span()) }); let if_else = just(Token::Keyword("if")) - .ignore_then(expression.clone()) + .ignore_then(positioned_expression.clone()) .then(positioned_block.clone()) .then( just(Token::Keyword("else")) @@ -400,7 +405,7 @@ pub fn parser<'src>() -> DustParser<'src> { ) .map_with(|((if_expression, if_block), else_block), state| { Statement::IfElse(IfElse::new(if_expression, if_block, else_block)) - .positioned(state.span()) + .with_position(state.span()) }); choice(( @@ -415,7 +420,7 @@ pub fn parser<'src>() -> DustParser<'src> { .then_ignore(just(Token::Control(Control::Semicolon)).or_not()) }); - statement.repeated().collect().boxed() + positioned_statement.repeated().collect().boxed() } #[cfg(test)] @@ -429,19 +434,18 @@ mod tests { assert_eq!( parse(&lex("while true { output('hi') }").unwrap()).unwrap()[0], Statement::While(While::new( - Expression::Value(ValueNode::Boolean(true)).positioned((6..11).into()), - Block::new(vec![Statement::Expression( - Expression::FunctionCall(FunctionCall::new( + Expression::Value(ValueNode::Boolean(true)).with_position((6..11).into()), + Block::new(vec![Statement::Expression(Expression::FunctionCall( + FunctionCall::new( Expression::Identifier(Identifier::new("output")) - .positioned((13..19).into()), + .with_position((13..19).into()), vec![Expression::Value(ValueNode::String("hi".to_string())) - .positioned((20..24).into())] - )) - .positioned((13..26).into()) - ) - .positioned((13..26).into())]) + .with_position((20..24).into())] + ) + )) + .with_position((13..26).into())]) )) - .positioned((0..27).into()) + .with_position((0..27).into()) ) } @@ -451,14 +455,12 @@ mod tests { parse(&lex("foobar : bool = true").unwrap()).unwrap()[0], Statement::Assignment(Assignment::new( Identifier::new("foobar"), - Some(Type::Boolean.positioned((9..14).into())), + Some(Type::Boolean.with_position((9..14).into())), AssignmentOperator::Assign, - Statement::Expression( - Expression::Value(ValueNode::Boolean(true)).positioned((16..20).into()) - ) - .positioned((16..20).into()) + Statement::Expression(Expression::Value(ValueNode::Boolean(true))) + .with_position((16..20).into()) ),) - .positioned((0..20).into()) + .with_position((0..20).into()) ); } @@ -468,18 +470,15 @@ mod tests { parse(&lex("foobar : list(bool) = [true]").unwrap()).unwrap()[0], Statement::Assignment(Assignment::new( Identifier::new("foobar"), - Some(Type::ListOf(Box::new(Type::Boolean)).positioned((9..20).into())), + Some(Type::ListOf(Box::new(Type::Boolean)).with_position((9..20).into())), AssignmentOperator::Assign, - Statement::Expression( - Expression::Value(ValueNode::List(vec![Expression::Value( - ValueNode::Boolean(true) - ) - .positioned((23..27).into())])) - .positioned((22..28).into()) + Statement::Expression(Expression::Value(ValueNode::List(vec![Expression::Value( + ValueNode::Boolean(true) ) - .positioned((22..28).into()) + .with_position((23..27).into())]))) + .with_position((22..28).into()) )) - .positioned((0..28).into()) + .with_position((0..28).into()) ); } @@ -489,19 +488,19 @@ mod tests { parse(&lex("foobar : [bool, str] = [true, '42']").unwrap()).unwrap()[0], Statement::Assignment(Assignment::new( Identifier::new("foobar"), - Some(Type::ListExact(vec![Type::Boolean, Type::String]).positioned((9..21).into())), + Some( + Type::ListExact(vec![Type::Boolean, Type::String]) + .with_position((9..21).into()) + ), AssignmentOperator::Assign, - Statement::Expression( - Expression::Value(ValueNode::List(vec![ - Expression::Value(ValueNode::Boolean(true)).positioned((24..28).into()), - Expression::Value(ValueNode::String("42".to_string())) - .positioned((30..34).into()) - ])) - .positioned((23..35).into()) - ) - .positioned((23..35).into()) + Statement::Expression(Expression::Value(ValueNode::List(vec![ + Expression::Value(ValueNode::Boolean(true)).with_position((24..28).into()), + Expression::Value(ValueNode::String("42".to_string())) + .with_position((30..34).into()) + ]))) + .with_position((23..35).into()) ),) - .positioned((0..35).into()) + .with_position((0..35).into()) ); } @@ -516,40 +515,36 @@ mod tests { parameter_types: vec![], return_type: Box::new(Type::Any) } - .positioned((9..19).into()) + .with_position((9..19).into()) ), AssignmentOperator::Assign, - Statement::Expression( - Expression::Identifier(Identifier::new("some_function")) - .positioned((21..34).into()) - ) - .positioned((21..34).into()) + Statement::Expression(Expression::Identifier(Identifier::new("some_function"))) + .with_position((21..34).into()) ),) - .positioned((0..34).into()) + .with_position((0..34).into()) ); } - // #[test] - // fn function_call() { - // assert_eq!( - // parse(&lex("output()").unwrap()).unwrap()[0], - // Statement::expression( - // Expression::FunctionCall(FunctionCall::new( - // Expression::Identifier(Identifier::new("output")), - // Vec::with_capacity(0), - // )), - // (0..0).into() - // ) - // ) - // } + #[test] + fn function_call() { + assert_eq!( + parse(&lex("output()").unwrap()).unwrap()[0], + Statement::Expression(Expression::FunctionCall(FunctionCall::new( + Expression::Identifier(Identifier::new("output")).with_position((0..6).into()), + Vec::with_capacity(0), + ))) + .with_position((0..8).into()) + ) + } - // #[test] - // fn range() { - // assert_eq!( - // parse(&lex("1..10").unwrap()).unwrap()[0], - // Statement::expression(Expression::Value(ValueNode::Range(1..10)), (0..0).into()) - // ) - // } + #[test] + fn range() { + assert_eq!( + parse(&lex("1..10").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value(ValueNode::Range(1..10))) + .with_position((0..5).into()) + ) + } // #[test] // fn function() { diff --git a/src/value.rs b/src/value.rs index d592a6d..acc5676 100644 --- a/src/value.rs +++ b/src/value.rs @@ -13,7 +13,7 @@ use stanza::{ }; use crate::{ - abstract_tree::{AbstractTree, Action, Block, Identifier, Positioned, Type}, + abstract_tree::{AbstractTree, Action, Block, Identifier, Type, WithPosition}, context::Context, error::{RuntimeError, ValidationError}, }; @@ -55,9 +55,9 @@ impl Value { } pub fn function( - parameters: Vec<(Identifier, Positioned)>, - return_type: Positioned, - body: Positioned, + parameters: Vec<(Identifier, WithPosition)>, + return_type: WithPosition, + body: WithPosition, ) -> Self { Value(Arc::new(ValueInner::Function(Function::Parsed( ParsedFunction { @@ -330,9 +330,9 @@ impl Function { #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct ParsedFunction { - parameters: Vec<(Identifier, Positioned)>, - return_type: Positioned, - body: Positioned, + parameters: Vec<(Identifier, WithPosition)>, + return_type: WithPosition, + body: WithPosition, } #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] diff --git a/tests/functions.rs b/tests/functions.rs index 75e7d46..6b64f73 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -62,7 +62,7 @@ fn function_context_does_not_capture_values() { ), Err(vec![Error::Validation { error: ValidationError::VariableNotFound(Identifier::new("x")), - span: (32, 66) + position: (0, 0) }]) ); diff --git a/tests/values.rs b/tests/values.rs index 73ec94c..a63b012 100644 --- a/tests/values.rs +++ b/tests/values.rs @@ -136,11 +136,15 @@ fn map_type_errors() { assert_eq!( interpret("{ foo : bool = 'bar' }"), Err(vec![Error::Validation { - error: ValidationError::TypeCheck(TypeConflict { - actual: Type::String, - expected: Type::Boolean - }), - span: (0, 22) + error: ValidationError::TypeCheck { + conflict: TypeConflict { + actual: Type::String, + expected: Type::Boolean + }, + actual_position: (0, 0), + expected_position: (0, 0), + }, + position: (0, 22) }]) ); } diff --git a/tests/variables.rs b/tests/variables.rs index f7400e6..f7554d9 100644 --- a/tests/variables.rs +++ b/tests/variables.rs @@ -1,5 +1,5 @@ use dust_lang::{ - abstract_tree::{Block, Expression, Identifier, Statement, Type}, + abstract_tree::{AbstractTree, Block, Expression, Identifier, Statement, Type}, error::{Error, TypeConflict, ValidationError}, *, }; @@ -25,11 +25,15 @@ fn set_variable_with_type_error() { assert_eq!( interpret("foobar: str = true"), Err(vec![Error::Validation { - error: ValidationError::TypeCheck(TypeConflict { - actual: Type::Boolean, - expected: Type::String - }), - span: (0, 18) + error: ValidationError::TypeCheck { + conflict: TypeConflict { + actual: Type::Boolean, + expected: Type::String + }, + actual_position: (0, 0), + expected_position: (0, 0) + }, + position: (0, 18) }]) ); } @@ -39,12 +43,16 @@ fn function_variable() { assert_eq!( interpret("foobar = (x: int): int { x }; foobar"), Ok(Some(Value::function( - vec![(Identifier::new("x"), Type::Integer)], - Type::Integer, - Block::new(vec![Statement::expression( - Expression::Identifier(Identifier::new("x")), - (0..0).into() - )]) + vec![( + Identifier::new("x"), + Type::Integer.with_position((0..0).into()) + )], + Type::Integer.with_position((0..0).into()), + Block::new(vec![Statement::Expression(Expression::Identifier( + Identifier::new("x") + )) + .with_position((0..0).into())]) + .with_position((0..0).into()) ))) ); }