diff --git a/dust-lang/src/abstract_tree/assignment.rs b/dust-lang/src/abstract_tree/assignment.rs index 91a812a..57dd729 100644 --- a/dust-lang/src/abstract_tree/assignment.rs +++ b/dust-lang/src/abstract_tree/assignment.rs @@ -1,17 +1,18 @@ use crate::{ error::{RuntimeError, ValidationError}, + identifier::Identifier, value::ValueInner, Context, Value, }; -use super::{AbstractNode, Action, Identifier, Statement, Type, WithPosition}; +use super::{AbstractNode, Action, Statement, Type, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct Assignment { identifier: WithPosition, r#type: Option>, operator: AssignmentOperator, - statement: Box>, + statement: Box, } #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] @@ -26,7 +27,7 @@ impl Assignment { identifier: WithPosition, r#type: Option>, operator: AssignmentOperator, - statement: WithPosition, + statement: Statement, ) -> Self { Self { identifier, @@ -43,7 +44,7 @@ impl AbstractNode for Assignment { } fn validate(&self, context: &Context) -> Result<(), ValidationError> { - let statement_type = self.statement.node.expected_type(context)?; + let statement_type = self.statement.expected_type(context)?; if let Some(WithPosition { node: expected_type, @@ -53,7 +54,7 @@ impl AbstractNode for Assignment { expected_type.check(&statement_type).map_err(|conflict| { ValidationError::TypeCheck { conflict, - actual_position: self.statement.position, + actual_position: self.statement.position(), expected_position: expected_position.clone(), } })?; @@ -63,14 +64,13 @@ impl AbstractNode for Assignment { context.set_type(self.identifier.node.clone(), statement_type)?; } - self.identifier.node.validate(context)?; - self.statement.node.validate(context)?; + self.statement.validate(context)?; Ok(()) } fn run(self, context: &Context) -> Result { - let action = self.statement.node.run(context)?; + let action = self.statement.run(context)?; let right = match action { Action::Return(value) => value, r#break => return Ok(r#break), @@ -112,7 +112,10 @@ impl AbstractNode for Assignment { context.set_value(self.identifier.node, new_value)?; } else { return Err(RuntimeError::ValidationFailure( - ValidationError::VariableNotFound(self.identifier.node), + ValidationError::VariableNotFound { + identifier: self.identifier.node, + position: self.identifier.position, + }, )); } } @@ -148,7 +151,10 @@ impl AbstractNode for Assignment { context.set_value(self.identifier.node, new_value)?; } else { return Err(RuntimeError::ValidationFailure( - ValidationError::VariableNotFound(self.identifier.node), + ValidationError::VariableNotFound { + identifier: self.identifier.node, + position: self.identifier.position, + }, )); } } @@ -175,7 +181,9 @@ mod tests { Identifier::new("foobar").with_position((0, 0)), None, AssignmentOperator::Assign, - Statement::Expression(Expression::Value(ValueNode::Integer(42))).with_position((0, 0)), + Statement::Expression(Expression::Value( + ValueNode::Integer(42).with_position((0, 0)), + )), ) .run(&context) .unwrap(); @@ -198,7 +206,9 @@ mod tests { Identifier::new("foobar").with_position((0, 0)), None, AssignmentOperator::AddAssign, - Statement::Expression(Expression::Value(ValueNode::Integer(41))).with_position((0, 0)), + Statement::Expression(Expression::Value( + ValueNode::Integer(41).with_position((0, 0)), + )), ) .run(&context) .unwrap(); @@ -221,7 +231,9 @@ mod tests { Identifier::new("foobar").with_position((0, 0)), None, AssignmentOperator::SubAssign, - Statement::Expression(Expression::Value(ValueNode::Integer(1))).with_position((0, 0)), + Statement::Expression(Expression::Value( + ValueNode::Integer(1).with_position((0, 0)), + )), ) .run(&context) .unwrap(); @@ -241,7 +253,9 @@ mod tests { position: (0, 0).into(), }), AssignmentOperator::Assign, - Statement::Expression(Expression::Value(ValueNode::Integer(42))).with_position((0, 0)), + Statement::Expression(Expression::Value( + ValueNode::Integer(42).with_position((0, 0)), + )), ) .validate(&Context::new()); diff --git a/dust-lang/src/abstract_tree/async_block.rs b/dust-lang/src/abstract_tree/async_block.rs index d869543..99516b2 100644 --- a/dust-lang/src/abstract_tree/async_block.rs +++ b/dust-lang/src/abstract_tree/async_block.rs @@ -7,27 +7,27 @@ use crate::{ error::{RuntimeError, RwLockPoisonError, ValidationError}, }; -use super::{AbstractNode, Action, Statement, Type, WithPosition}; +use super::{AbstractNode, Action, Statement, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct AsyncBlock { - statements: Vec>, + statements: Vec, } impl AsyncBlock { - pub fn new(statements: Vec>) -> Self { + pub fn new(statements: Vec) -> Self { Self { statements } } } impl AbstractNode for AsyncBlock { fn expected_type(&self, _context: &Context) -> Result { - self.statements.last().unwrap().node.expected_type(_context) + self.statements.last().unwrap().expected_type(_context) } fn validate(&self, _context: &Context) -> Result<(), ValidationError> { for statement in &self.statements { - statement.node.validate(_context)?; + statement.validate(_context)?; } Ok(()) @@ -41,7 +41,7 @@ impl AbstractNode for AsyncBlock { .into_par_iter() .enumerate() .find_map_first(|(index, statement)| { - let result = statement.node.run(_context); + let result = statement.run(_context); if index == statement_count - 1 { let get_write_lock = final_result.write(); diff --git a/dust-lang/src/abstract_tree/block.rs b/dust-lang/src/abstract_tree/block.rs index 8ef0b10..c9e0cc3 100644 --- a/dust-lang/src/abstract_tree/block.rs +++ b/dust-lang/src/abstract_tree/block.rs @@ -3,19 +3,19 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{AbstractNode, Action, Statement, Type, WithPosition}; +use super::{AbstractNode, Action, Statement, Type}; #[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 } } - pub fn last_statement(&self) -> &WithPosition { + pub fn last_statement(&self) -> &Statement { self.statements.last().unwrap() } } @@ -23,7 +23,7 @@ impl Block { impl AbstractNode for Block { fn expected_type(&self, _context: &Context) -> Result { if let Some(statement) = self.statements.last() { - statement.node.expected_type(_context) + statement.expected_type(_context) } else { Ok(Type::None) } @@ -31,7 +31,7 @@ impl AbstractNode for Block { fn validate(&self, _context: &Context) -> Result<(), ValidationError> { for statement in &self.statements { - statement.node.validate(_context)?; + statement.validate(_context)?; } Ok(()) @@ -41,7 +41,7 @@ impl AbstractNode for Block { let mut previous = Action::None; for statement in self.statements { - previous = statement.node.run(_context)?; + previous = statement.run(_context)?; } Ok(previous) @@ -60,9 +60,15 @@ mod tests { #[test] fn run_returns_value_of_final_statement() { let block = Block::new(vec![ - Statement::Expression(Expression::Value(ValueNode::Integer(1))).with_position((0, 0)), - Statement::Expression(Expression::Value(ValueNode::Integer(2))).with_position((0, 0)), - Statement::Expression(Expression::Value(ValueNode::Integer(42))).with_position((0, 0)), + Statement::Expression(Expression::Value( + ValueNode::Integer(1).with_position((0, 0)), + )), + Statement::Expression(Expression::Value( + ValueNode::Integer(2).with_position((0, 0)), + )), + Statement::Expression(Expression::Value( + ValueNode::Integer(42).with_position((0, 0)), + )), ]); assert_eq!( @@ -74,9 +80,12 @@ 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()))) - .with_position((0, 0)), - Statement::Expression(Expression::Value(ValueNode::Integer(42))).with_position((0, 0)), + Statement::Expression(Expression::Value( + ValueNode::String("42".to_string()).with_position((0, 0)), + )), + Statement::Expression(Expression::Value( + ValueNode::Integer(42).with_position((0, 0)), + )), ]); assert_eq!(block.expected_type(&Context::new()), Ok(Type::Integer)) diff --git a/dust-lang/src/abstract_tree/expression.rs b/dust-lang/src/abstract_tree/expression.rs index fe74c47..37f0015 100644 --- a/dust-lang/src/abstract_tree/expression.rs +++ b/dust-lang/src/abstract_tree/expression.rs @@ -1,58 +1,102 @@ use crate::{ context::Context, error::{RuntimeError, ValidationError}, + identifier::Identifier, }; use super::{ - AbstractNode, Action, FunctionCall, Identifier, ListIndex, Logic, MapIndex, Math, Type, - ValueNode, + AbstractNode, Action, FunctionCall, ListIndex, Logic, MapIndex, Math, SourcePosition, Type, + ValueNode, WithPosition, }; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum Expression { - FunctionCall(FunctionCall), - Identifier(Identifier), - MapIndex(Box), - ListIndex(Box), - Logic(Box), - Math(Box), - Value(ValueNode), + FunctionCall(WithPosition), + Identifier(WithPosition), + MapIndex(WithPosition>), + ListIndex(WithPosition>), + Logic(WithPosition>), + Math(WithPosition>), + Value(WithPosition), +} + +impl Expression { + pub fn position(&self) -> SourcePosition { + match self { + Expression::FunctionCall(inner) => inner.position, + Expression::Identifier(inner) => inner.position, + Expression::MapIndex(inner) => inner.position, + Expression::ListIndex(inner) => inner.position, + Expression::Logic(inner) => inner.position, + Expression::Math(inner) => inner.position, + Expression::Value(inner) => inner.position, + } + } } impl AbstractNode for Expression { fn expected_type(&self, _context: &Context) -> Result { match self { - Expression::FunctionCall(function_call) => function_call.expected_type(_context), - Expression::Identifier(identifier) => identifier.expected_type(_context), - Expression::MapIndex(map_index) => map_index.expected_type(_context), - Expression::ListIndex(list_index) => list_index.expected_type(_context), - Expression::Logic(logic) => logic.expected_type(_context), - Expression::Math(math) => math.expected_type(_context), - Expression::Value(value_node) => value_node.expected_type(_context), + Expression::FunctionCall(function_call) => function_call.node.expected_type(_context), + Expression::Identifier(identifier) => { + if let Some(r#type) = _context.get_type(&identifier.node)? { + Ok(r#type) + } else { + Err(ValidationError::VariableNotFound { + identifier: identifier.node.clone(), + position: identifier.position, + }) + } + } + Expression::MapIndex(map_index) => map_index.node.expected_type(_context), + Expression::ListIndex(list_index) => list_index.node.expected_type(_context), + Expression::Logic(logic) => logic.node.expected_type(_context), + Expression::Math(math) => math.node.expected_type(_context), + Expression::Value(value_node) => value_node.node.expected_type(_context), } } - fn validate(&self, _context: &Context) -> Result<(), ValidationError> { + fn validate(&self, context: &Context) -> Result<(), ValidationError> { match self { - Expression::FunctionCall(function_call) => function_call.validate(_context), - Expression::Identifier(identifier) => identifier.validate(_context), - Expression::MapIndex(map_index) => map_index.validate(_context), - Expression::ListIndex(list_index) => list_index.validate(_context), - Expression::Logic(logic) => logic.validate(_context), - Expression::Math(math) => math.validate(_context), - Expression::Value(value_node) => value_node.validate(_context), + Expression::FunctionCall(function_call) => function_call.node.validate(context), + Expression::Identifier(identifier) => { + if context.contains(&identifier.node)? { + Ok(()) + } else { + Err(ValidationError::VariableNotFound { + identifier: identifier.node.clone(), + position: identifier.position, + }) + } + } + Expression::MapIndex(map_index) => map_index.node.validate(context), + Expression::ListIndex(list_index) => list_index.node.validate(context), + Expression::Logic(logic) => logic.node.validate(context), + Expression::Math(math) => math.node.validate(context), + Expression::Value(value_node) => value_node.node.validate(context), } } fn run(self, _context: &Context) -> Result { match self { - Expression::FunctionCall(function_call) => function_call.run(_context), - Expression::Identifier(identifier) => identifier.run(_context), - Expression::MapIndex(map_index) => map_index.run(_context), - Expression::ListIndex(list_index) => list_index.run(_context), - Expression::Logic(logic) => logic.run(_context), - Expression::Math(math) => math.run(_context), - Expression::Value(value_node) => value_node.run(_context), + Expression::FunctionCall(function_call) => function_call.node.run(_context), + Expression::Identifier(identifier) => { + if let Some(value) = _context.get_value(&identifier.node)? { + Ok(Action::Return(value)) + } else { + Err(RuntimeError::ValidationFailure( + ValidationError::VariableNotFound { + identifier: identifier.node.clone(), + position: identifier.position, + }, + )) + } + } + Expression::MapIndex(map_index) => map_index.node.run(_context), + Expression::ListIndex(list_index) => list_index.node.run(_context), + Expression::Logic(logic) => logic.node.run(_context), + Expression::Math(math) => math.node.run(_context), + Expression::Value(value_node) => value_node.node.run(_context), } } } diff --git a/dust-lang/src/abstract_tree/function_call.rs b/dust-lang/src/abstract_tree/function_call.rs index dacf206..45b2fa2 100644 --- a/dust-lang/src/abstract_tree/function_call.rs +++ b/dust-lang/src/abstract_tree/function_call.rs @@ -8,16 +8,16 @@ use super::{AbstractNode, Action, Expression, Type, WithPosition}; #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct FunctionCall { - function: Box>, + function: Box, type_arguments: Vec>, - arguments: Vec>, + arguments: Vec, } impl FunctionCall { pub fn new( - function: WithPosition, + function: Expression, type_arguments: Vec>, - arguments: Vec>, + arguments: Vec, ) -> Self { FunctionCall { function: Box::new(function), @@ -29,24 +29,24 @@ impl FunctionCall { impl AbstractNode for FunctionCall { fn expected_type(&self, _context: &Context) -> Result { - let function_node_type = self.function.node.expected_type(_context)?; + let function_node_type = self.function.expected_type(_context)?; if let Type::Function { return_type, .. } = function_node_type { Ok(return_type.node) } else { Err(ValidationError::ExpectedFunction { actual: function_node_type, - position: self.function.position, + position: self.function.position(), }) } } fn validate(&self, context: &Context) -> Result<(), ValidationError> { for expression in &self.arguments { - expression.node.validate(context)?; + expression.validate(context)?; } - let function_node_type = self.function.node.expected_type(context)?; + let function_node_type = self.function.expected_type(context)?; if let Type::Function { parameter_types, @@ -67,12 +67,12 @@ impl AbstractNode for FunctionCall { } for (type_parameter, expression) in parameter_types.iter().zip(self.arguments.iter()) { - let actual = expression.node.expected_type(context)?; + let actual = expression.expected_type(context)?; type_parameter.node.check(&actual).map_err(|conflict| { ValidationError::TypeCheck { conflict, - actual_position: expression.position, + actual_position: expression.position(), expected_position: type_parameter.position, } })?; @@ -82,18 +82,19 @@ impl AbstractNode for FunctionCall { } else { Err(ValidationError::ExpectedFunction { actual: function_node_type, - position: self.function.position, + position: self.function.position(), }) } } fn run(self, context: &Context) -> Result { - let action = self.function.node.run(context)?; + let function_position = self.function.position(); + let action = self.function.run(context)?; let value = if let Action::Return(value) = action { value } else { return Err(RuntimeError::ValidationFailure( - ValidationError::InterpreterExpectedReturn(self.function.position), + ValidationError::InterpreterExpectedReturn(function_position), )); }; let function = if let ValueInner::Function(function) = value.inner().as_ref() { @@ -102,19 +103,20 @@ impl AbstractNode for FunctionCall { return Err(RuntimeError::ValidationFailure( ValidationError::ExpectedFunction { actual: value.r#type(context)?, - position: self.function.position, + position: function_position, }, )); }; let mut arguments = Vec::with_capacity(self.arguments.len()); for expression in self.arguments { - let action = expression.node.run(context)?; + let expression_position = expression.position(); + let action = expression.run(context)?; let value = if let Action::Return(value) = action { value } else { return Err(RuntimeError::ValidationFailure( - ValidationError::InterpreterExpectedReturn(expression.position), + ValidationError::InterpreterExpectedReturn(expression_position), )); }; diff --git a/dust-lang/src/abstract_tree/identifier.rs b/dust-lang/src/abstract_tree/identifier.rs deleted file mode 100644 index cdfc647..0000000 --- a/dust-lang/src/abstract_tree/identifier.rs +++ /dev/null @@ -1,60 +0,0 @@ -use std::{ - fmt::{self, Display, Formatter}, - sync::Arc, -}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, -}; - -use super::{AbstractNode, Action, Type}; - -#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] -pub struct Identifier(Arc); - -impl Identifier { - pub fn new(string: T) -> Self { - Identifier(Arc::new(string.to_string())) - } - - pub fn as_str(&self) -> &str { - self.0.as_str() - } -} - -impl AbstractNode for Identifier { - fn expected_type(&self, context: &Context) -> Result { - if let Some(r#type) = context.get_type(self)? { - Ok(r#type) - } else { - Err(ValidationError::VariableNotFound(self.clone())) - } - } - - fn validate(&self, context: &Context) -> Result<(), ValidationError> { - if context.contains(self)? { - Ok(()) - } else { - Err(ValidationError::VariableNotFound(self.clone())) - } - } - - fn run(self, context: &Context) -> Result { - let return_action = context.get_value(&self)?.map(|value| Action::Return(value)); - - if let Some(action) = return_action { - Ok(action) - } else { - Err(RuntimeError::ValidationFailure( - ValidationError::VariableNotFound(self.clone()), - )) - } - } -} - -impl Display for Identifier { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}", self.0) - } -} diff --git a/dust-lang/src/abstract_tree/if_else.rs b/dust-lang/src/abstract_tree/if_else.rs index 279104b..63064a5 100644 --- a/dust-lang/src/abstract_tree/if_else.rs +++ b/dust-lang/src/abstract_tree/if_else.rs @@ -4,24 +4,27 @@ use crate::{ value::ValueInner, }; -use super::{AbstractNode, Action, Block, Expression, Type, WithPosition}; +use super::{AbstractNode, Action, Block, Expression, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct IfElse { - if_expression: WithPosition, + if_expression: Expression, if_block: Block, + else_ifs: Option>, else_block: Option, } impl IfElse { pub fn new( - if_expression: WithPosition, + if_expression: Expression, if_block: Block, + else_ifs: Option>, else_block: Option, ) -> Self { Self { if_expression, if_block, + else_ifs, else_block, } } @@ -33,10 +36,10 @@ impl AbstractNode for IfElse { } fn validate(&self, context: &Context) -> Result<(), ValidationError> { - self.if_expression.node.validate(context)?; + self.if_expression.validate(context)?; self.if_block.validate(context)?; - let if_expression_type = self.if_expression.node.expected_type(context)?; + let if_expression_type = self.if_expression.expected_type(context)?; if let Type::Boolean = if_expression_type { if let Some(else_block) = &self.else_block { @@ -49,8 +52,8 @@ impl AbstractNode for IfElse { .check(&actual) .map_err(|conflict| ValidationError::TypeCheck { conflict, - actual_position: self.if_block.last_statement().position, - expected_position: self.if_expression.position, + actual_position: self.if_block.last_statement().position(), + expected_position: self.if_expression.position(), })?; } @@ -58,18 +61,19 @@ impl AbstractNode for IfElse { } else { Err(ValidationError::ExpectedBoolean { actual: if_expression_type, - position: self.if_expression.position, + position: self.if_expression.position(), }) } } fn run(self, context: &Context) -> Result { - let action = self.if_expression.node.run(context)?; + let if_position = self.if_expression.position(); + let action = self.if_expression.run(context)?; let value = if let Action::Return(value) = action { value } else { return Err(RuntimeError::ValidationFailure( - ValidationError::InterpreterExpectedReturn(self.if_expression.position), + ValidationError::InterpreterExpectedReturn(if_position), )); }; @@ -85,7 +89,7 @@ impl AbstractNode for IfElse { Err(RuntimeError::ValidationFailure( ValidationError::ExpectedBoolean { actual: value.r#type(context)?, - position: self.if_expression.position, + position: if_position, }, )) } @@ -105,11 +109,11 @@ mod tests { fn simple_if() { assert_eq!( IfElse::new( - Expression::Value(ValueNode::Boolean(true)).with_position((0, 0)), + Expression::Value(ValueNode::Boolean(true).with_position((0, 0))), Block::new(vec![Statement::Expression(Expression::Value( - ValueNode::String("foo".to_string()) - )) - .with_position((0, 0))]), + ValueNode::String("foo".to_string()).with_position((0, 0)) + ))]), + None, None ) .run(&Context::new()) @@ -117,24 +121,4 @@ mod tests { Action::Return(Value::string("foo".to_string())) ) } - - #[test] - fn simple_if_else() { - assert_eq!( - IfElse::new( - Expression::Value(ValueNode::Boolean(false)).with_position((0, 0)), - Block::new(vec![Statement::Expression(Expression::Value( - ValueNode::String("foo".to_string()) - )) - .with_position((0, 0))]), - Some(Block::new(vec![Statement::Expression(Expression::Value( - ValueNode::String("bar".to_string()) - )) - .with_position((0, 0))])) - ) - .run(&Context::new()) - .unwrap(), - Action::Return(Value::string("bar".to_string())) - ) - } } diff --git a/dust-lang/src/abstract_tree/list_index.rs b/dust-lang/src/abstract_tree/list_index.rs index f99bc7b..236d079 100644 --- a/dust-lang/src/abstract_tree/list_index.rs +++ b/dust-lang/src/abstract_tree/list_index.rs @@ -7,24 +7,30 @@ use super::{AbstractNode, Action, Expression, Type, ValueNode, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct ListIndex { - left: WithPosition, - right: WithPosition, + left: Expression, + right: Expression, } impl ListIndex { - pub fn new(left: WithPosition, right: WithPosition) -> Self { + pub fn new(left: Expression, right: Expression) -> Self { Self { left, right } } } impl AbstractNode for ListIndex { fn expected_type(&self, _context: &Context) -> Result { - let left_type = self.left.node.expected_type(_context)?; + let left_type = self.left.expected_type(_context)?; if let ( - Expression::Value(ValueNode::List(expression_list)), - Expression::Value(ValueNode::Integer(index)), - ) = (&self.left.node, &self.right.node) + Expression::Value(WithPosition { + node: ValueNode::List(expression_list), + .. + }), + Expression::Value(WithPosition { + node: ValueNode::Integer(index), + .. + }), + ) = (&self.left, &self.right) { let expression = if let Some(expression) = expression_list.get(*index as usize) { expression @@ -32,57 +38,59 @@ impl AbstractNode for ListIndex { return Ok(Type::None); }; - expression.node.expected_type(_context) + expression.expected_type(_context) } else { Err(ValidationError::CannotIndex { r#type: left_type, - position: self.left.position, + position: self.left.position(), }) } } fn validate(&self, context: &Context) -> Result<(), ValidationError> { - let left_type = self.left.node.expected_type(context)?; + let left_type = self.left.expected_type(context)?; match left_type { Type::List => todo!(), Type::ListOf(_) => todo!(), Type::ListExact(_) => { - let right_type = self.right.node.expected_type(context)?; + let right_type = self.right.expected_type(context)?; if let Type::Integer = right_type { Ok(()) } else { Err(ValidationError::CannotIndexWith { collection_type: left_type, - collection_position: self.left.position, + collection_position: self.left.position(), index_type: right_type, - index_position: self.right.position, + index_position: self.right.position(), }) } } _ => Err(ValidationError::CannotIndex { r#type: left_type, - position: self.left.position, + position: self.left.position(), }), } } fn run(self, context: &Context) -> Result { - let left_action = self.left.node.run(context)?; + let left_position = self.left.position(); + let left_action = self.left.run(context)?; let left_value = if let Action::Return(value) = left_action { value } else { return Err(RuntimeError::ValidationFailure( - ValidationError::InterpreterExpectedReturn(self.left.position), + ValidationError::InterpreterExpectedReturn(left_position), )); }; - let right_action = self.right.node.run(context)?; + let right_position = self.right.position(); + let right_action = self.right.run(context)?; let right_value = if let Action::Return(value) = right_action { value } else { return Err(RuntimeError::ValidationFailure( - ValidationError::InterpreterExpectedReturn(self.left.position), + ValidationError::InterpreterExpectedReturn(right_position), )); }; @@ -98,9 +106,9 @@ impl AbstractNode for ListIndex { Err(RuntimeError::ValidationFailure( ValidationError::CannotIndexWith { collection_type: left_value.r#type(context)?, - collection_position: self.left.position, + collection_position: left_position, index_type: right_value.r#type(context)?, - index_position: self.right.position, + index_position: right_position, }, )) } diff --git a/dust-lang/src/abstract_tree/logic.rs b/dust-lang/src/abstract_tree/logic.rs index 78995e2..137e284 100644 --- a/dust-lang/src/abstract_tree/logic.rs +++ b/dust-lang/src/abstract_tree/logic.rs @@ -5,19 +5,19 @@ use crate::{ Value, }; -use super::{AbstractNode, Action, Expression, Type, WithPosition}; +use super::{AbstractNode, Action, Expression, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum Logic { - 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), + Equal(Expression, Expression), + NotEqual(Expression, Expression), + Greater(Expression, Expression), + Less(Expression, Expression), + GreaterOrEqual(Expression, Expression), + LessOrEqual(Expression, Expression), + And(Expression, Expression), + Or(Expression, Expression), + Not(Expression), } impl AbstractNode for Logic { @@ -33,28 +33,28 @@ impl AbstractNode for Logic { | Logic::Less(left, right) | Logic::GreaterOrEqual(left, right) | Logic::LessOrEqual(left, right) => { - let left_type = left.node.expected_type(context)?; - let right_type = right.node.expected_type(context)?; + let left_type = left.expected_type(context)?; + let right_type = right.expected_type(context)?; left_type .check(&right_type) .map_err(|conflict| ValidationError::TypeCheck { conflict, - actual_position: left.position, - expected_position: right.position, + actual_position: left.position(), + expected_position: right.position(), })?; Ok(()) } Logic::And(left, right) | Logic::Or(left, right) => { - let left_type = left.node.expected_type(context)?; - let right_type = right.node.expected_type(context)?; + let left_type = left.expected_type(context)?; + let right_type = right.expected_type(context)?; if let Type::Boolean = left_type { } else { return Err(ValidationError::ExpectedBoolean { actual: left_type, - position: left.position, + position: left.position(), }); } @@ -62,21 +62,21 @@ impl AbstractNode for Logic { } else { return Err(ValidationError::ExpectedBoolean { actual: right_type, - position: right.position, + position: right.position(), }); } Ok(()) } Logic::Not(expression) => { - let expression_type = expression.node.expected_type(context)?; + let expression_type = expression.expected_type(context)?; if let Type::Boolean = expression_type { Ok(()) } else { Err(ValidationError::ExpectedBoolean { actual: expression_type, - position: expression.position, + position: expression.position(), }) } } @@ -84,43 +84,43 @@ impl AbstractNode for Logic { } fn run(self, context: &Context) -> Result { - let run_and_expect_value = - |expression: WithPosition| -> Result { - let action = expression.node.run(context)?; - let value = if let Action::Return(value) = action { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::InterpreterExpectedReturn(expression.position), - )); - }; - - Ok(value) + let run_and_expect_value = |expression: Expression| -> Result { + let expression_position = expression.position(); + let action = expression.run(context)?; + let value = if let Action::Return(value) = action { + value + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::InterpreterExpectedReturn(expression_position), + )); }; - let run_and_expect_boolean = - |expression: WithPosition| -> Result { - let action = expression.node.run(context)?; - let value = if let Action::Return(value) = action { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::InterpreterExpectedReturn(expression.position), - )); - }; + Ok(value) + }; - if let ValueInner::Boolean(boolean) = value.inner().as_ref() { - Ok(*boolean) - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedBoolean { - actual: value.r#type(context)?, - position: expression.position, - }, - )); - } + let run_and_expect_boolean = |expression: Expression| -> Result { + let expression_position = expression.position(); + let action = expression.run(context)?; + let value = if let Action::Return(value) = action { + value + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::InterpreterExpectedReturn(expression_position), + )); }; + if let ValueInner::Boolean(boolean) = value.inner().as_ref() { + Ok(*boolean) + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedBoolean { + actual: value.r#type(context)?, + position: expression_position, + }, + )); + } + }; + let boolean = match self { Logic::Equal(left, right) => { let (left_value, right_value) = @@ -195,8 +195,8 @@ mod tests { fn equal() { assert_eq!( Logic::Equal( - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), + Expression::Value(ValueNode::Integer(42).with_position((0, 0))), + Expression::Value(ValueNode::Integer(42).with_position((0, 0))) ) .run(&Context::new()), Ok(Action::Return(Value::boolean(true))) @@ -207,8 +207,8 @@ mod tests { fn not_equal() { assert_eq!( Logic::NotEqual( - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), - Expression::Value(ValueNode::Integer(43)).with_position((0, 0)), + Expression::Value(ValueNode::Integer(42).with_position((0, 0))), + Expression::Value(ValueNode::Integer(43).with_position((0, 0))) ) .run(&Context::new()), Ok(Action::Return(Value::boolean(true))) @@ -219,8 +219,8 @@ mod tests { fn greater() { assert_eq!( Logic::Greater( - Expression::Value(ValueNode::Integer(43)).with_position((0, 0)), - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), + Expression::Value(ValueNode::Integer(43).with_position((0, 0))), + Expression::Value(ValueNode::Integer(42).with_position((0, 0))) ) .run(&Context::new()), Ok(Action::Return(Value::boolean(true))) @@ -231,8 +231,8 @@ mod tests { fn less() { assert_eq!( Logic::Less( - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), - Expression::Value(ValueNode::Integer(43)).with_position((0, 0)), + Expression::Value(ValueNode::Integer(42).with_position((0, 0))), + Expression::Value(ValueNode::Integer(43).with_position((0, 0))) ) .run(&Context::new()), Ok(Action::Return(Value::boolean(true))) @@ -243,8 +243,8 @@ mod tests { fn greater_or_equal() { assert_eq!( Logic::GreaterOrEqual( - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), - Expression::Value(ValueNode::Integer(41)).with_position((0, 0)), + Expression::Value(ValueNode::Integer(42).with_position((0, 0))), + Expression::Value(ValueNode::Integer(41).with_position((0, 0))) ) .run(&Context::new()), Ok(Action::Return(Value::boolean(true))) @@ -252,8 +252,8 @@ mod tests { assert_eq!( Logic::GreaterOrEqual( - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), + Expression::Value(ValueNode::Integer(42).with_position((0, 0))), + Expression::Value(ValueNode::Integer(42).with_position((0, 0))), ) .run(&Context::new()), Ok(Action::Return(Value::boolean(true))) @@ -264,8 +264,8 @@ mod tests { fn less_or_equal() { assert_eq!( Logic::LessOrEqual( - Expression::Value(ValueNode::Integer(41)).with_position((0, 0)), - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), + Expression::Value(ValueNode::Integer(41).with_position((0, 0))), + Expression::Value(ValueNode::Integer(42).with_position((0, 0))), ) .run(&Context::new()), Ok(Action::Return(Value::boolean(true))) @@ -273,8 +273,8 @@ mod tests { assert_eq!( Logic::LessOrEqual( - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), + Expression::Value(ValueNode::Integer(42).with_position((0, 0))), + Expression::Value(ValueNode::Integer(42).with_position((0, 0))), ) .run(&Context::new()), Ok(Action::Return(Value::boolean(true))) @@ -285,8 +285,8 @@ mod tests { fn and() { assert_eq!( Logic::And( - Expression::Value(ValueNode::Boolean(true)).with_position((0, 0)), - Expression::Value(ValueNode::Boolean(true)).with_position((0, 0)), + Expression::Value(ValueNode::Boolean(true).with_position((0, 0))), + Expression::Value(ValueNode::Boolean(true).with_position((0, 0))), ) .run(&Context::new()), Ok(Action::Return(Value::boolean(true))) @@ -297,8 +297,8 @@ mod tests { fn or() { assert_eq!( Logic::Or( - Expression::Value(ValueNode::Boolean(true)).with_position((0, 0)), - Expression::Value(ValueNode::Boolean(false)).with_position((0, 0)), + Expression::Value(ValueNode::Boolean(true).with_position((0, 0))), + Expression::Value(ValueNode::Boolean(false).with_position((0, 0))), ) .run(&Context::new()), Ok(Action::Return(Value::boolean(true))) @@ -308,8 +308,10 @@ mod tests { #[test] fn not() { assert_eq!( - Logic::Not(Expression::Value(ValueNode::Boolean(false)).with_position((0, 0)),) - .run(&Context::new()), + Logic::Not(Expression::Value( + ValueNode::Boolean(false).with_position((0, 0)) + )) + .run(&Context::new()), Ok(Action::Return(Value::boolean(true))) ) } diff --git a/dust-lang/src/abstract_tree/loop.rs b/dust-lang/src/abstract_tree/loop.rs index a0e36fa..065253c 100644 --- a/dust-lang/src/abstract_tree/loop.rs +++ b/dust-lang/src/abstract_tree/loop.rs @@ -5,15 +5,15 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{AbstractNode, Action, Statement, Type, WithPosition}; +use super::{AbstractNode, Action, Statement, Type}; #[derive(Clone, Debug)] pub struct Loop { - statements: Vec>, + statements: Vec, } impl Loop { - pub fn new(statements: Vec>) -> Self { + pub fn new(statements: Vec) -> Self { Self { statements } } } @@ -25,7 +25,7 @@ impl AbstractNode for Loop { fn validate(&self, _context: &Context) -> Result<(), ValidationError> { for statement in &self.statements { - statement.node.validate(_context)?; + statement.validate(_context)?; } Ok(()) @@ -34,7 +34,7 @@ impl AbstractNode for Loop { fn run(self, _context: &Context) -> Result { loop { for statement in &self.statements { - let action = statement.node.clone().run(_context)?; + let action = statement.clone().run(_context)?; match action { Action::Return(_) => {} @@ -70,9 +70,9 @@ impl Ord for Loop { mod tests { use crate::{ abstract_tree::{ - Assignment, AssignmentOperator, Block, Expression, Identifier, IfElse, Logic, - ValueNode, WithPos, + Assignment, AssignmentOperator, Block, Expression, IfElse, Logic, ValueNode, WithPos, }, + identifier::Identifier, Value, }; @@ -80,7 +80,7 @@ mod tests { #[test] fn basic_loop() { - let action = Loop::new(vec![Statement::Break.with_position((0, 0))]) + let action = Loop::new(vec![Statement::Break(().with_position((0, 0)))]) .run(&Context::new()) .unwrap(); @@ -90,34 +90,48 @@ mod tests { #[test] fn complex_loop() { let action = Block::new(vec![ - Statement::Assignment(Assignment::new( - Identifier::new("i").with_position((0, 0)), - None, - AssignmentOperator::Assign, - Statement::Expression(Expression::Value(ValueNode::Integer(1))) - .with_position((0, 0)), - )) - .with_position((0, 0)), - Statement::Loop(Loop::new(vec![Statement::IfElse(IfElse::new( - Expression::Logic(Box::new(Logic::Greater( - Expression::Identifier(Identifier::new("i")).with_position((0, 0)), - Expression::Value(ValueNode::Integer(2)).with_position((0, 0)), - ))) - .with_position((0, 0)), - Block::new(vec![Statement::Break.with_position((0, 0))]), - Some(Block::new(vec![Statement::Assignment(Assignment::new( + Statement::Assignment( + Assignment::new( Identifier::new("i").with_position((0, 0)), None, - AssignmentOperator::AddAssign, - Statement::Expression(Expression::Value(ValueNode::Integer(1))) - .with_position((0, 0)), - )) - .with_position((0, 0))])), - )) - .with_position((0, 0))])) - .with_position((0, 0)), - Statement::Expression(Expression::Identifier(Identifier::new("i"))) + AssignmentOperator::Assign, + Statement::Expression(Expression::Value( + ValueNode::Integer(1).with_position((0, 0)), + )), + ) .with_position((0, 0)), + ), + Statement::Loop( + Loop::new(vec![Statement::IfElse( + IfElse::new( + Expression::Logic( + Box::new(Logic::Greater( + Expression::Identifier(Identifier::new("i").with_position((0, 0))), + Expression::Value(ValueNode::Integer(2).with_position((0, 0))), + )) + .with_position((0, 0)), + ), + Block::new(vec![Statement::Break(().with_position((0, 0)))]), + None, + Some(Block::new(vec![Statement::Assignment( + Assignment::new( + Identifier::new("i").with_position((0, 0)), + None, + AssignmentOperator::AddAssign, + Statement::Expression(Expression::Value( + ValueNode::Integer(1).with_position((0, 0)), + )), + ) + .with_position((0, 0)), + )])), + ) + .with_position((0, 0)), + )]) + .with_position((0, 0)), + ), + Statement::Expression(Expression::Identifier( + Identifier::new("i").with_position((0, 0)), + )), ]) .run(&Context::new()) .unwrap(); diff --git a/dust-lang/src/abstract_tree/map_index.rs b/dust-lang/src/abstract_tree/map_index.rs index 21ff265..fcc6c90 100644 --- a/dust-lang/src/abstract_tree/map_index.rs +++ b/dust-lang/src/abstract_tree/map_index.rs @@ -8,12 +8,12 @@ use super::{AbstractNode, Action, Expression, Type, ValueNode, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct MapIndex { - left: WithPosition, - right: WithPosition, + left: Expression, + right: Expression, } impl MapIndex { - pub fn new(left: WithPosition, right: WithPosition) -> Self { + pub fn new(left: Expression, right: Expression) -> Self { Self { left, right } } } @@ -23,40 +23,47 @@ impl AbstractNode for MapIndex { if let ( Expression::Identifier(collection_identifier), Expression::Identifier(index_identifier), - ) = (&self.left.node, &self.right.node) + ) = (&self.left, &self.right) { - let collection = if let Some(collection) = context.get_value(collection_identifier)? { - collection - } else { - return Err(ValidationError::VariableNotFound( - collection_identifier.clone(), - )); - }; + let collection = + if let Some(collection) = context.get_value(&collection_identifier.node)? { + collection + } else { + return Err(ValidationError::VariableNotFound { + identifier: collection_identifier.node.clone(), + position: collection_identifier.position, + }); + }; if let ValueInner::Map(map) = collection.inner().as_ref() { - return if let Some(value) = map.get(index_identifier) { + return if let Some(value) = map.get(&index_identifier.node) { Ok(value.r#type(context)?) } else { Err(ValidationError::PropertyNotFound { - identifier: index_identifier.clone(), - position: self.right.position, + identifier: index_identifier.node.clone(), + position: self.right.position(), }) }; }; } - if let (Expression::Value(ValueNode::Map(properties)), Expression::Identifier(identifier)) = - (&self.left.node, &self.right.node) + if let ( + Expression::Value(WithPosition { + node: ValueNode::Map(properties), + .. + }), + Expression::Identifier(identifier), + ) = (&self.left, &self.right) { return if let Some(type_result) = properties .iter() .find_map(|(property, type_option, expression)| { - if property == identifier { + if property == &identifier.node { if let Some(r#type) = type_option { Some(r#type.node.expected_type(context)) } else { - Some(expression.node.expected_type(context)) + Some(expression.expected_type(context)) } } else { None @@ -70,13 +77,16 @@ impl AbstractNode for MapIndex { } if let ( - Expression::Value(ValueNode::Structure { fields, .. }), + Expression::Value(WithPosition { + node: ValueNode::Structure { fields, .. }, + .. + }), Expression::Identifier(identifier), - ) = (&self.left.node, &self.right.node) + ) = (&self.left, &self.right) { return if let Some(type_result) = fields.iter().find_map(|(property, expression)| { - if property == identifier { - Some(expression.node.expected_type(context)) + if property == &identifier.node { + Some(expression.expected_type(context)) } else { None } @@ -88,49 +98,55 @@ impl AbstractNode for MapIndex { } Err(ValidationError::CannotIndexWith { - collection_type: self.left.node.expected_type(context)?, - collection_position: self.left.position, - index_type: self.right.node.expected_type(context)?, - index_position: self.right.position, + collection_type: self.left.expected_type(context)?, + collection_position: self.left.position(), + index_type: self.right.expected_type(context)?, + index_position: self.right.position(), }) } fn validate(&self, context: &Context) -> Result<(), ValidationError> { - let left_type = self.left.node.expected_type(context)?; + let left_type = self.left.expected_type(context)?; - if let (Expression::Value(ValueNode::Map(_)), Expression::Identifier(_)) = - (&self.left.node, &self.right.node) + if let ( + Expression::Value(WithPosition { + node: ValueNode::Map(_), + .. + }), + Expression::Identifier(_), + ) = (&self.left, &self.right) { Ok(()) } else if let (Expression::Identifier(_), Expression::Identifier(_)) = - (&self.left.node, &self.right.node) + (&self.left, &self.right) { Ok(()) } else { Err(ValidationError::CannotIndexWith { collection_type: left_type, - collection_position: self.left.position, - index_type: self.right.node.expected_type(context)?, - index_position: self.right.position, + collection_position: self.left.position(), + index_type: self.right.expected_type(context)?, + index_position: self.right.position(), }) } } fn run(self, context: &Context) -> Result { - let action = self.left.node.run(context)?; + let collection_position = self.left.position(); + let action = self.left.run(context)?; let collection = if let Action::Return(value) = action { value } else { return Err(RuntimeError::ValidationFailure( - ValidationError::InterpreterExpectedReturn(self.left.position), + ValidationError::InterpreterExpectedReturn(collection_position), )); }; if let (ValueInner::Map(map), Expression::Identifier(identifier)) = - (collection.inner().as_ref(), &self.right.node) + (collection.inner().as_ref(), &self.right) { let action = map - .get(identifier) + .get(&identifier.node) .map(|value| Action::Return(value.clone())) .unwrap_or(Action::None); @@ -139,9 +155,9 @@ impl AbstractNode for MapIndex { Err(RuntimeError::ValidationFailure( ValidationError::CannotIndexWith { collection_type: collection.r#type(context)?, - collection_position: self.left.position, - index_type: self.right.node.expected_type(context)?, - index_position: self.right.position, + collection_position, + index_type: self.right.expected_type(context)?, + index_position: self.right.position(), }, )) } diff --git a/dust-lang/src/abstract_tree/math.rs b/dust-lang/src/abstract_tree/math.rs index 211662c..b40f6a6 100644 --- a/dust-lang/src/abstract_tree/math.rs +++ b/dust-lang/src/abstract_tree/math.rs @@ -5,15 +5,15 @@ use crate::{ Value, }; -use super::{AbstractNode, Action, Expression, SourcePosition, Type, WithPosition}; +use super::{AbstractNode, Action, Expression, SourcePosition, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum Math { - Add(WithPosition, WithPosition), - Subtract(WithPosition, WithPosition), - Multiply(WithPosition, WithPosition), - Divide(WithPosition, WithPosition), - Modulo(WithPosition, WithPosition), + Add(Expression, Expression), + Subtract(Expression, Expression), + Multiply(Expression, Expression), + Divide(Expression, Expression), + Modulo(Expression, Expression), } impl AbstractNode for Math { @@ -24,8 +24,8 @@ impl AbstractNode for Math { | Math::Multiply(left, right) | Math::Divide(left, right) | Math::Modulo(left, right) => { - let left_type = left.node.expected_type(_context)?; - let right_type = right.node.expected_type(_context)?; + let left_type = left.expected_type(_context)?; + let right_type = right.expected_type(_context)?; if let Type::Float = left_type { return Ok(Type::Float); @@ -43,22 +43,25 @@ impl AbstractNode for Math { fn validate(&self, context: &Context) -> Result<(), ValidationError> { match self { Math::Add(left, right) => { - let left_type = left.node.expected_type(context)?; - let right_type = right.node.expected_type(context)?; + let left_position = left.position(); + let left_type = left.expected_type(context)?; if let Type::Integer | Type::Float | Type::String = left_type { + let right_position = right.position(); + let right_type = right.expected_type(context)?; + if let Type::Integer | Type::Float | Type::String = right_type { Ok(()) } else { Err(ValidationError::ExpectedIntegerFloatOrString { actual: right_type, - position: right.position, + position: right_position, }) } } else { Err(ValidationError::ExpectedIntegerFloatOrString { actual: left_type, - position: left.position, + position: left_position, }) } } @@ -66,17 +69,20 @@ impl AbstractNode for Math { | Math::Multiply(left, right) | Math::Divide(left, right) | Math::Modulo(left, right) => { - let left_type = left.node.expected_type(context)?; - let right_type = right.node.expected_type(context)?; + let left_position = left.position(); + let left_type = left.expected_type(context)?; if let Type::Integer | Type::Float = left_type { + let right_position = right.position(); + let right_type = right.expected_type(context)?; + if let Type::Integer | Type::Float = right_type { Ok(()) } else { - Err(ValidationError::ExpectedIntegerOrFloat(right.position)) + Err(ValidationError::ExpectedIntegerOrFloat(right_position)) } } else { - Err(ValidationError::ExpectedIntegerOrFloat(left.position)) + Err(ValidationError::ExpectedIntegerOrFloat(left_position)) } } } @@ -84,7 +90,7 @@ impl AbstractNode for Math { fn run(self, _context: &Context) -> Result { let run_and_expect_value = - |expression: Expression, position: SourcePosition| -> Result { + |position: SourcePosition, expression: Expression| -> Result { let action = expression.run(_context)?; let value = if let Action::Return(value) = action { value @@ -99,8 +105,10 @@ impl AbstractNode for Math { let value = match self { Math::Add(left, right) => { - let left_value = run_and_expect_value(left.node, left.position)?; - let right_value = run_and_expect_value(right.node, right.position)?; + let left_position = left.position(); + let left_value = run_and_expect_value(left_position, left)?; + let right_position = right.position(); + let right_value = run_and_expect_value(right_position, right)?; match (left_value.inner().as_ref(), right_value.inner().as_ref()) { (ValueInner::Integer(left), ValueInner::Integer(right)) => { @@ -132,19 +140,21 @@ impl AbstractNode for Math { } (ValueInner::Integer(_) | ValueInner::Float(_), _) => { return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(right.position), + ValidationError::ExpectedIntegerOrFloat(right_position), )) } _ => { return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(left.position), + ValidationError::ExpectedIntegerOrFloat(left_position), )) } } } Math::Subtract(left, right) => { - let left_value = run_and_expect_value(left.node, left.position)?; - let right_value = run_and_expect_value(right.node, right.position)?; + let left_position = left.position(); + let left_value = run_and_expect_value(left_position, left)?; + let right_position = right.position(); + let right_value = run_and_expect_value(right_position, right)?; match (left_value.inner().as_ref(), right_value.inner().as_ref()) { (ValueInner::Integer(left), ValueInner::Integer(right)) => { @@ -169,19 +179,21 @@ impl AbstractNode for Math { } (ValueInner::Integer(_) | ValueInner::Float(_), _) => { return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(right.position), + ValidationError::ExpectedIntegerOrFloat(right_position), )) } _ => { return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(left.position), + ValidationError::ExpectedIntegerOrFloat(left_position), )) } } } Math::Multiply(left, right) => { - let left_value = run_and_expect_value(left.node, left.position)?; - let right_value = run_and_expect_value(right.node, right.position)?; + let left_position = left.position(); + let left_value = run_and_expect_value(left_position, left)?; + let right_position = right.position(); + let right_value = run_and_expect_value(right_position, right)?; match (left_value.inner().as_ref(), right_value.inner().as_ref()) { (ValueInner::Integer(left), ValueInner::Integer(right)) => { @@ -206,19 +218,21 @@ impl AbstractNode for Math { } (ValueInner::Integer(_) | ValueInner::Float(_), _) => { return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(right.position).into(), + ValidationError::ExpectedIntegerOrFloat(right_position).into(), )) } _ => { return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(left.position), + ValidationError::ExpectedIntegerOrFloat(left_position), )) } } } Math::Divide(left, right) => { - let left_value = run_and_expect_value(left.node, left.position)?; - let right_value = run_and_expect_value(right.node, right.position)?; + let left_position = left.position(); + let left_value = run_and_expect_value(left_position, left)?; + let right_position = right.position(); + let right_value = run_and_expect_value(right_position, right)?; match (left_value.inner().as_ref(), right_value.inner().as_ref()) { (ValueInner::Integer(left), ValueInner::Integer(right)) => { @@ -243,19 +257,21 @@ impl AbstractNode for Math { } (ValueInner::Integer(_) | ValueInner::Float(_), _) => { return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(right.position).into(), + ValidationError::ExpectedIntegerOrFloat(right_position).into(), )) } _ => { return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(left.position), + ValidationError::ExpectedIntegerOrFloat(left_position), )) } } } Math::Modulo(left, right) => { - let left_value = run_and_expect_value(left.node, left.position)?; - let right_value = run_and_expect_value(right.node, right.position)?; + let left_position = left.position(); + let left_value = run_and_expect_value(left_position, left)?; + let right_position = right.position(); + let right_value = run_and_expect_value(right_position, right)?; match (left_value.inner().as_ref(), right_value.inner().as_ref()) { (ValueInner::Integer(left), ValueInner::Integer(right)) => { @@ -280,12 +296,12 @@ impl AbstractNode for Math { } (ValueInner::Integer(_) | ValueInner::Float(_), _) => { return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(right.position).into(), + ValidationError::ExpectedIntegerOrFloat(right_position).into(), )) } _ => { return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(left.position), + ValidationError::ExpectedIntegerOrFloat(left_position), )) } } diff --git a/dust-lang/src/abstract_tree/mod.rs b/dust-lang/src/abstract_tree/mod.rs index 3e6c2a7..6951b5c 100644 --- a/dust-lang/src/abstract_tree/mod.rs +++ b/dust-lang/src/abstract_tree/mod.rs @@ -3,7 +3,6 @@ pub mod async_block; pub mod block; pub mod expression; pub mod function_call; -pub mod identifier; pub mod if_else; pub mod list_index; pub mod logic; @@ -26,7 +25,6 @@ pub use self::{ block::Block, expression::Expression, function_call::FunctionCall, - identifier::Identifier, if_else::IfElse, list_index::ListIndex, logic::Logic, @@ -85,11 +83,11 @@ pub enum Action { None, } -pub struct AbstractTree(Vec>); +pub struct AbstractTree(Vec); impl AbstractTree { - pub fn new(mut statements: Vec>) -> Self { - statements.sort_by(|left, right| match (&left.node, &right.node) { + pub fn new(mut statements: Vec) -> Self { + statements.sort_by(|left, right| match (&left, &right) { (Statement::StructureDefinition(_), _) => Ordering::Less, (_, Statement::StructureDefinition(_)) => Ordering::Greater, (_, _) => Ordering::Equal, @@ -103,7 +101,8 @@ impl AbstractTree { let mut previous_value = None; for statement in valid_statements { - let run = statement.node.run(context); + let position = statement.position(); + let run = statement.run(context); match run { Ok(action) => match action { @@ -113,7 +112,7 @@ impl AbstractTree { Err(runtime_error) => { return Err(vec![Error::Runtime { error: runtime_error, - position: statement.position, + position, }]); } } @@ -122,29 +121,27 @@ impl AbstractTree { Ok(previous_value) } - fn run_type_definitions( - self, - context: &Context, - ) -> Result>, Vec> { + fn run_type_definitions(self, context: &Context) -> Result, Vec> { let mut errors = Vec::new(); let mut valid_statements = Vec::new(); for statement in self.0 { - let validation = statement.node.validate(context); + let validation = statement.validate(context); if let Err(validation_error) = validation { errors.push(Error::Validation { error: validation_error, - position: statement.position, + position: statement.position(), }) } else if errors.is_empty() { - if let Statement::StructureDefinition(_) = statement.node { - let run = statement.node.run(context); + if let Statement::StructureDefinition(_) = statement { + let position = statement.position(); + let run = statement.run(context); if let Err(runtime_error) = run { errors.push(Error::Runtime { error: runtime_error, - position: statement.position, + position, }); return Err(errors); @@ -164,7 +161,7 @@ impl AbstractTree { } impl Index for AbstractTree { - type Output = WithPosition; + type Output = Statement; fn index(&self, index: usize) -> &Self::Output { &self.0[index] diff --git a/dust-lang/src/abstract_tree/statement.rs b/dust-lang/src/abstract_tree/statement.rs index d873569..fc5c5b4 100644 --- a/dust-lang/src/abstract_tree/statement.rs +++ b/dust-lang/src/abstract_tree/statement.rs @@ -4,28 +4,35 @@ use crate::{ }; use super::{ - AbstractNode, Action, Assignment, AsyncBlock, Block, Expression, IfElse, Loop, - StructureDefinition, Type, While, + AbstractNode, Action, Assignment, AsyncBlock, Block, Expression, IfElse, Loop, SourcePosition, + StructureDefinition, Type, While, WithPosition, }; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum Statement { - Assignment(Assignment), - AsyncBlock(AsyncBlock), - Block(Block), - Break, + Assignment(WithPosition), + AsyncBlock(WithPosition), + Block(WithPosition), + Break(WithPosition<()>), Expression(Expression), - IfElse(IfElse), - Loop(Loop), - StructureDefinition(StructureDefinition), - While(While), + IfElse(WithPosition), + Loop(WithPosition), + StructureDefinition(WithPosition), + While(WithPosition), } impl Statement { - pub fn kind(&self) -> u8 { + pub fn position(&self) -> SourcePosition { match self { - Statement::StructureDefinition(_) => 0, - _ => 1, + Statement::Assignment(inner) => inner.position, + Statement::AsyncBlock(inner) => inner.position, + Statement::Block(inner) => inner.position, + Statement::Break(inner) => inner.position, + Statement::Expression(expression) => expression.position(), + Statement::IfElse(inner) => inner.position, + Statement::Loop(inner) => inner.position, + Statement::StructureDefinition(inner) => inner.position, + Statement::While(inner) => inner.position, } } } @@ -33,48 +40,48 @@ impl Statement { impl AbstractNode for Statement { fn expected_type(&self, _context: &Context) -> Result { match self { - Statement::Assignment(assignment) => assignment.expected_type(_context), - Statement::AsyncBlock(async_block) => async_block.expected_type(_context), - Statement::Block(block) => block.expected_type(_context), - Statement::Break => Ok(Type::None), + Statement::Assignment(assignment) => assignment.node.expected_type(_context), + Statement::AsyncBlock(async_block) => async_block.node.expected_type(_context), + Statement::Block(block) => block.node.expected_type(_context), + Statement::Break(_) => Ok(Type::None), 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), + Statement::IfElse(if_else) => if_else.node.expected_type(_context), + Statement::Loop(r#loop) => r#loop.node.expected_type(_context), + Statement::While(r#while) => r#while.node.expected_type(_context), Statement::StructureDefinition(structure_definition) => { - structure_definition.expected_type(_context) + structure_definition.node.expected_type(_context) } } } fn validate(&self, _context: &Context) -> Result<(), ValidationError> { match self { - Statement::Assignment(assignment) => assignment.validate(_context), - Statement::AsyncBlock(async_block) => async_block.validate(_context), - Statement::Block(block) => block.validate(_context), - Statement::Break => Ok(()), + Statement::Assignment(assignment) => assignment.node.validate(_context), + Statement::AsyncBlock(async_block) => async_block.node.validate(_context), + Statement::Block(block) => block.node.validate(_context), + Statement::Break(_) => Ok(()), 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), + Statement::IfElse(if_else) => if_else.node.validate(_context), + Statement::Loop(r#loop) => r#loop.node.validate(_context), + Statement::While(r#while) => r#while.node.validate(_context), Statement::StructureDefinition(structure_definition) => { - structure_definition.validate(_context) + structure_definition.node.validate(_context) } } } fn run(self, _context: &Context) -> Result { match self { - Statement::Assignment(assignment) => assignment.run(_context), - Statement::AsyncBlock(async_block) => async_block.run(_context), - Statement::Block(block) => block.run(_context), - Statement::Break => Ok(Action::Break), + Statement::Assignment(assignment) => assignment.node.run(_context), + Statement::AsyncBlock(async_block) => async_block.node.run(_context), + Statement::Block(block) => block.node.run(_context), + Statement::Break(_) => Ok(Action::Break), 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), + Statement::IfElse(if_else) => if_else.node.run(_context), + Statement::Loop(r#loop) => r#loop.node.run(_context), + Statement::While(r#while) => r#while.node.run(_context), Statement::StructureDefinition(structure_definition) => { - structure_definition.run(_context) + structure_definition.node.run(_context) } } } diff --git a/dust-lang/src/abstract_tree/structure_definition.rs b/dust-lang/src/abstract_tree/structure_definition.rs index 0fc9947..91f0a25 100644 --- a/dust-lang/src/abstract_tree/structure_definition.rs +++ b/dust-lang/src/abstract_tree/structure_definition.rs @@ -1,9 +1,10 @@ use crate::{ context::Context, error::{RuntimeError, ValidationError}, + identifier::Identifier, }; -use super::{AbstractNode, Action, Identifier, Type, WithPosition}; +use super::{AbstractNode, Action, Type, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct StructureDefinition { diff --git a/dust-lang/src/abstract_tree/type.rs b/dust-lang/src/abstract_tree/type.rs index b110ce5..fb60a3c 100644 --- a/dust-lang/src/abstract_tree/type.rs +++ b/dust-lang/src/abstract_tree/type.rs @@ -3,9 +3,9 @@ use std::fmt::{self, Display, Formatter}; use clap::error::Result; use crate::{ - abstract_tree::Identifier, context::Context, error::{RuntimeError, TypeConflict, ValidationError}, + identifier::Identifier, }; use super::{AbstractNode, Action, WithPosition}; diff --git a/dust-lang/src/abstract_tree/value_node.rs b/dust-lang/src/abstract_tree/value_node.rs index bd7e6fd..81af621 100644 --- a/dust-lang/src/abstract_tree/value_node.rs +++ b/dust-lang/src/abstract_tree/value_node.rs @@ -4,10 +4,11 @@ use crate::{ built_in_functions::BuiltInFunction, context::Context, error::{RuntimeError, ValidationError}, + identifier::Identifier, Value, }; -use super::{AbstractNode, Action, Block, Expression, Identifier, Type, WithPos, WithPosition}; +use super::{AbstractNode, Action, Block, Expression, Type, WithPos, WithPosition}; #[derive(Clone, Debug, PartialEq)] pub enum ValueNode { @@ -15,19 +16,13 @@ pub enum ValueNode { BuiltInFunction(BuiltInFunction), Float(f64), Integer(i64), - List(Vec>), - Map( - Vec<( - Identifier, - Option>, - WithPosition, - )>, - ), + List(Vec), + Map(Vec<(Identifier, Option>, Expression)>), Range(Range), String(String), Structure { - name: Identifier, - fields: Vec<(Identifier, WithPosition)>, + name: WithPosition, + fields: Vec<(Identifier, Expression)>, }, ParsedFunction { type_arguments: Vec>, @@ -49,9 +44,8 @@ impl AbstractNode for ValueNode { for expression in items { item_types.push( expression - .node .expected_type(context)? - .with_position(expression.position), + .with_position(expression.position()), ); } @@ -78,19 +72,19 @@ impl AbstractNode for ValueNode { let mut types = Vec::with_capacity(expressions.len()); for (identifier, expression) in expressions { - let r#type = expression.node.expected_type(context)?; + let r#type = expression.expected_type(context)?; types.push(( identifier.clone(), WithPosition { node: r#type, - position: expression.position, + position: expression.position(), }, )); } Type::Structure { - name: name.clone(), + name: name.node.clone(), fields: types, } } @@ -104,12 +98,12 @@ impl AbstractNode for ValueNode { if let ValueNode::Map(map_assignments) = self { for (_identifier, r#type, expression) in map_assignments { if let Some(expected_type) = r#type { - let actual_type = expression.node.expected_type(context)?; + let actual_type = expression.expected_type(context)?; expected_type.node.check(&actual_type).map_err(|conflict| { ValidationError::TypeCheck { conflict, - actual_position: expression.position, + actual_position: expression.position(), expected_position: expected_type.position, } })?; @@ -161,18 +155,18 @@ impl AbstractNode for ValueNode { fields: expressions, } = self { - if let Type::Structure { + if let Some(Type::Structure { name: _, fields: types, - } = name.expected_type(context)? + }) = context.get_type(&name.node)? { for ((_, expression), (_, expected_type)) in expressions.iter().zip(types.iter()) { - let actual_type = expression.node.expected_type(context)?; + let actual_type = expression.expected_type(context)?; expected_type.node.check(&actual_type).map_err(|conflict| { ValidationError::TypeCheck { conflict, - actual_position: expression.position, + actual_position: expression.position(), expected_position: expected_type.position, } })? @@ -192,15 +186,16 @@ impl AbstractNode for ValueNode { let mut value_list = Vec::with_capacity(expression_list.len()); for expression in expression_list { - let action = expression.node.run(_context)?; + let expression_position = expression.position(); + let action = expression.run(_context)?; let value = if let Action::Return(value) = action { WithPosition { node: value, - position: expression.position, + position: expression_position, } } else { return Err(RuntimeError::ValidationFailure( - ValidationError::InterpreterExpectedReturn(expression.position), + ValidationError::InterpreterExpectedReturn(expression_position), )); }; @@ -213,12 +208,13 @@ impl AbstractNode for ValueNode { let mut property_map = BTreeMap::new(); for (identifier, _type, expression) in property_list { - let action = expression.node.run(_context)?; + let expression_position = expression.position(); + let action = expression.run(_context)?; let value = if let Action::Return(value) = action { value } else { return Err(RuntimeError::ValidationFailure( - ValidationError::InterpreterExpectedReturn(expression.position), + ValidationError::InterpreterExpectedReturn(expression_position), )); }; @@ -242,12 +238,13 @@ impl AbstractNode for ValueNode { let mut fields = Vec::with_capacity(expressions.len()); for (identifier, expression) in expressions { - let action = expression.node.run(_context)?; + let expression_position = expression.position(); + let action = expression.run(_context)?; let value = if let Action::Return(value) = action { value } else { return Err(RuntimeError::ValidationFailure( - ValidationError::InterpreterExpectedReturn(expression.position), + ValidationError::InterpreterExpectedReturn(expression_position), )); }; diff --git a/dust-lang/src/abstract_tree/while.rs b/dust-lang/src/abstract_tree/while.rs index 057750a..8783531 100644 --- a/dust-lang/src/abstract_tree/while.rs +++ b/dust-lang/src/abstract_tree/while.rs @@ -5,19 +5,16 @@ use crate::{ Value, }; -use super::{AbstractNode, Action, Expression, Statement, Type, WithPosition}; +use super::{AbstractNode, Action, Expression, Statement, Type}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct While { - expression: WithPosition, - statements: Vec>, + expression: Expression, + statements: Vec, } impl While { - pub fn new( - expression: WithPosition, - statements: Vec>, - ) -> Self { + pub fn new(expression: Expression, statements: Vec) -> Self { Self { expression, statements, @@ -31,10 +28,10 @@ impl AbstractNode for While { } fn validate(&self, _context: &Context) -> Result<(), ValidationError> { - self.expression.node.validate(_context)?; + self.expression.validate(_context)?; for statement in &self.statements { - statement.node.validate(_context)?; + statement.validate(_context)?; } Ok(()) @@ -42,13 +39,14 @@ impl AbstractNode for While { fn run(self, _context: &Context) -> Result { let get_boolean = || -> Result { - let action = self.expression.node.run(_context)?; + let expression_position = self.expression.position(); + let action = self.expression.run(_context)?; if let Action::Return(value) = action { Ok(value) } else { Err(RuntimeError::ValidationFailure( - ValidationError::InterpreterExpectedReturn(self.expression.position), + ValidationError::InterpreterExpectedReturn(expression_position), )) } }; @@ -56,7 +54,7 @@ impl AbstractNode for While { if let ValueInner::Boolean(boolean) = get_boolean()?.inner().as_ref() { while *boolean { for statement in &self.statements { - let action = statement.node.clone().run(_context)?; + let action = statement.clone().run(_context)?; match action { Action::Return(_) => {} @@ -73,42 +71,57 @@ impl AbstractNode for While { #[cfg(test)] mod tests { - use crate::abstract_tree::{ - Assignment, AssignmentOperator, Block, Identifier, Logic, ValueNode, WithPos, + use crate::{ + abstract_tree::{Assignment, AssignmentOperator, Block, Logic, ValueNode, WithPos}, + identifier::Identifier, }; use super::*; #[test] fn simple_while_loop() { - let action = Statement::Block(Block::new(vec![ - Statement::Assignment(Assignment::new( - Identifier::new("i").with_position((0, 0)), - None, - AssignmentOperator::Assign, - Statement::Expression(Expression::Value(ValueNode::Integer(3))) + let action = Statement::Block( + Block::new(vec![ + Statement::Assignment( + Assignment::new( + Identifier::new("i").with_position((0, 0)), + None, + AssignmentOperator::Assign, + Statement::Expression(Expression::Value( + ValueNode::Integer(3).with_position((0, 0)), + )), + ) .with_position((0, 0)), - )) - .with_position((0, 0)), - Statement::While(While { - expression: Expression::Logic(Box::new(Logic::Less( - Expression::Identifier(Identifier::new("i")).with_position((0, 0)), - Expression::Value(ValueNode::Integer(3)).with_position((0, 0)), - ))) - .with_position((0, 0)), - statements: vec![Statement::Assignment(Assignment::new( + ), + Statement::While( + While::new( + Expression::Logic( + Box::new(Logic::Less( + Expression::Identifier(Identifier::new("i").with_position((0, 0))), + Expression::Value(ValueNode::Integer(3).with_position((0, 0))), + )) + .with_position((0, 0)), + ), + vec![Statement::Assignment( + Assignment::new( + Identifier::new("i").with_position((0, 0)), + None, + AssignmentOperator::AddAssign, + Statement::Expression(Expression::Value( + ValueNode::Integer(1).with_position((0, 0)), + )), + ) + .with_position((0, 0)), + )], + ) + .with_position((0, 0)), + ), + Statement::Expression(Expression::Identifier( Identifier::new("i").with_position((0, 0)), - None, - AssignmentOperator::AddAssign, - Statement::Expression(Expression::Value(ValueNode::Integer(1))) - .with_position((0, 0)), - )) - .with_position((0, 0))], - }) + )), + ]) .with_position((0, 0)), - Statement::Expression(Expression::Identifier(Identifier::new("i"))) - .with_position((0, 0)), - ])) + ) .run(&Context::new()) .unwrap(); diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index 6da6d85..c3d01bd 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -4,8 +4,9 @@ use std::{ }; use crate::{ - abstract_tree::{Identifier, Type}, + abstract_tree::Type, error::{RwLockPoisonError, ValidationError}, + identifier::Identifier, Value, }; diff --git a/dust-lang/src/error.rs b/dust-lang/src/error.rs index e13e085..9bb0824 100644 --- a/dust-lang/src/error.rs +++ b/dust-lang/src/error.rs @@ -3,7 +3,8 @@ use std::{io, sync::PoisonError}; use chumsky::{prelude::Rich, span::Span}; use crate::{ - abstract_tree::{Identifier, SourcePosition, Type}, + abstract_tree::{SourcePosition, Type}, + identifier::Identifier, lexer::Token, }; @@ -135,7 +136,10 @@ pub enum ValidationError { expected: Vec, actual: Vec, }, - VariableNotFound(Identifier), + VariableNotFound { + identifier: Identifier, + position: SourcePosition, + }, PropertyNotFound { identifier: Identifier, position: SourcePosition, diff --git a/dust-lang/src/identifier.rs b/dust-lang/src/identifier.rs new file mode 100644 index 0000000..fbd52f4 --- /dev/null +++ b/dust-lang/src/identifier.rs @@ -0,0 +1,23 @@ +use std::{ + fmt::{self, Display, Formatter}, + sync::Arc, +}; + +#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] +pub struct Identifier(Arc); + +impl Identifier { + pub fn new(string: T) -> Self { + Identifier(Arc::new(string.to_string())) + } + + pub fn as_str(&self) -> &str { + self.0.as_str() + } +} + +impl Display for Identifier { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index aafd428..a60a2d1 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -2,6 +2,7 @@ pub mod abstract_tree; pub mod built_in_functions; pub mod context; pub mod error; +pub mod identifier; pub mod lexer; pub mod parser; pub mod value; @@ -120,7 +121,7 @@ impl InterpreterError { let mut reports = Vec::new(); for error in self.errors { - let (mut builder, validation_error, error_position) = match error { + let (mut builder, validation_error) = match error { Error::Lex { expected, span, @@ -145,7 +146,6 @@ impl InterpreterError { .with_color(Color::Red), ), None, - span.into(), ) } Error::Parse { @@ -172,7 +172,6 @@ impl InterpreterError { .with_color(Color::Red), ), None, - span.into(), ) } Error::Validation { error, position } => ( @@ -184,7 +183,6 @@ impl InterpreterError { .with_message("The syntax is valid but this code would cause an error.") .with_note("This error was detected by the interpreter before running the code."), Some(error), - position, ), Error::Runtime { error, position } => ( Report::build( @@ -207,7 +205,6 @@ impl InterpreterError { } else { None }, - position, ), }; @@ -260,12 +257,16 @@ impl InterpreterError { .with_message(format!("Got type {} here.", actual.fg(type_color))), ]); } - ValidationError::VariableNotFound(identifier) => builder.add_label( - Label::new((self.source_id.clone(), error_position.0..error_position.1)) - .with_message(format!( + ValidationError::VariableNotFound { + identifier, + position, + } => builder.add_label( + Label::new((self.source_id.clone(), position.0..position.1)).with_message( + format!( "Variable {} does not exist in this context.", identifier.fg(identifier_color) - )), + ), + ), ), ValidationError::CannotIndex { r#type, position } => builder.add_label( Label::new((self.source_id.clone(), position.0..position.1)).with_message( diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 230e8fb..ec1f289 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -5,6 +5,7 @@ use chumsky::{input::SpannedInput, pratt::*, prelude::*}; use crate::{ abstract_tree::*, error::Error, + identifier::Identifier, lexer::{Control, Keyword, Operator, Token}, }; @@ -25,12 +26,9 @@ pub fn parse<'src>(tokens: &'src [(Token<'src>, SimpleSpan)]) -> Result() -> impl Parser< - 'src, - ParserInput<'src>, - Vec>, - extra::Err, SimpleSpan>>, -> { +pub fn parser<'src>( +) -> impl Parser<'src, ParserInput<'src>, Vec, extra::Err, SimpleSpan>>> +{ let identifiers: RefCell> = RefCell::new(HashMap::new()); let _custom_types: Rc>> = Rc::new(RefCell::new(HashMap::new())); @@ -62,7 +60,7 @@ pub fn parser<'src>() -> impl Parser< Token::Integer(integer) => ValueNode::Integer(integer), Token::String(string) => ValueNode::String(string.to_string()), } - .map_with(|value, state| Expression::Value(value).with_position(state.span())); + .map_with(|value, state| Expression::Value(value.with_position(state.span()))); let r#type = recursive(|r#type| { let function_type = just(Token::Keyword(Keyword::Fn)) @@ -152,11 +150,11 @@ pub fn parser<'src>() -> impl Parser< custom_types.1.borrow_mut().insert(name, r#type); - Statement::StructureDefinition(definition).with_position(state.span()) + Statement::StructureDefinition(definition.with_position(state.span())) }); - let positioned_statement = recursive(|positioned_statement| { - let block = positioned_statement + let statement = recursive(|statement| { + let block = statement .clone() .repeated() .collect() @@ -166,9 +164,9 @@ pub fn parser<'src>() -> impl Parser< ) .map(|statements| Block::new(statements)); - let positioned_expression = recursive(|positioned_expression| { + let expression = recursive(|expression| { let identifier_expression = identifier.clone().map_with(|identifier, state| { - Expression::Identifier(identifier).with_position(state.span()) + Expression::Identifier(identifier.with_position(state.span())) }); let raw_integer = select! { @@ -180,10 +178,10 @@ pub fn parser<'src>() -> impl Parser< .then_ignore(just(Token::Control(Control::DoubleDot))) .then(raw_integer) .map_with(|(start, end), state| { - Expression::Value(ValueNode::Range(start..end)).with_position(state.span()) + Expression::Value(ValueNode::Range(start..end).with_position(state.span())) }); - let list = positioned_expression + let list = expression .clone() .separated_by(just(Token::Control(Control::Comma))) .allow_trailing() @@ -193,14 +191,14 @@ pub fn parser<'src>() -> impl Parser< just(Token::Control(Control::SquareClose)), ) .map_with(|list, state| { - Expression::Value(ValueNode::List(list)).with_position(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(positioned_expression.clone()) + .then(expression.clone()) .map(|((identifier, r#type), expression)| (identifier, r#type, expression)); let map = map_assignment @@ -212,8 +210,9 @@ pub fn parser<'src>() -> impl Parser< just(Token::Control(Control::CurlyClose)), ) .map_with(|map_assigment_list, state| { - Expression::Value(ValueNode::Map(map_assigment_list)) - .with_position(state.span()) + Expression::Value( + ValueNode::Map(map_assigment_list).with_position(state.span()), + ) }); let type_arguments = type_argument @@ -243,13 +242,16 @@ pub fn parser<'src>() -> impl Parser< ) .map_with( |(type_arguments, ((parameters, return_type), body)), state| { - Expression::Value(ValueNode::ParsedFunction { - type_arguments: type_arguments.unwrap_or_else(|| Vec::with_capacity(0)), - parameters, - return_type, - body: body.with_position(state.span()), - }) - .with_position(state.span()) + Expression::Value( + ValueNode::ParsedFunction { + type_arguments: type_arguments + .unwrap_or_else(|| Vec::with_capacity(0)), + parameters, + return_type, + body: body.with_position(state.span()), + } + .with_position(state.span()), + ) }, ); @@ -259,8 +261,9 @@ pub fn parser<'src>() -> impl Parser< } } .map_with(|built_in_function, state| { - Expression::Value(ValueNode::BuiltInFunction(built_in_function)) - .with_position(state.span()) + Expression::Value( + ValueNode::BuiltInFunction(built_in_function).with_position(state.span()), + ) }); use Operator::*; @@ -268,9 +271,9 @@ pub fn parser<'src>() -> impl Parser< let structure_field = identifier .clone() .then_ignore(just(Token::Operator(Operator::Assign))) - .then(positioned_expression.clone()); + .then(expression.clone()); - let structure_instance = identifier + let structure_instance = positioned_identifier .clone() .then( structure_field @@ -283,8 +286,9 @@ pub fn parser<'src>() -> impl Parser< ), ) .map_with(|(name, fields), state| { - Expression::Value(ValueNode::Structure { name, fields }) - .with_position(state.span()) + Expression::Value( + ValueNode::Structure { name, fields }.with_position(state.span()), + ) }); let turbofish = r#type @@ -310,7 +314,7 @@ pub fn parser<'src>() -> impl Parser< map.clone(), basic_value.clone(), identifier_expression.clone(), - positioned_expression.clone().delimited_by( + expression.clone().delimited_by( just(Token::Control(Control::ParenOpen)), just(Token::Control(Control::ParenClose)), ), @@ -318,23 +322,24 @@ pub fn parser<'src>() -> impl Parser< let logic_math_indexes_and_function_calls = atom.pratt(( prefix(2, just(Token::Operator(Not)), |_, expression, span| { - Expression::Logic(Box::new(Logic::Not(expression))).with_position(span) + Expression::Logic(Box::new(Logic::Not(expression)).with_position(span)) }), postfix( 2, - positioned_expression.clone().delimited_by( + expression.clone().delimited_by( just(Token::Control(Control::SquareOpen)), just(Token::Control(Control::SquareClose)), ), |left, right, span| { - Expression::ListIndex(Box::new(ListIndex::new(left, right))) - .with_position(span) + Expression::ListIndex( + Box::new(ListIndex::new(left, right)).with_position(span), + ) }, ), postfix( 3, turbofish.clone().or_not().then( - positioned_expression + expression .clone() .separated_by(just(Token::Control(Control::Comma))) .collect() @@ -346,117 +351,123 @@ pub fn parser<'src>() -> impl Parser< |function_expression, (type_arguments, arguments): ( Option>>, - Vec>, + Vec, ), span| { - Expression::FunctionCall(FunctionCall::new( - function_expression, - type_arguments.unwrap_or_else(|| Vec::with_capacity(0)), - arguments, - )) - .with_position(span) + Expression::FunctionCall( + FunctionCall::new( + function_expression, + type_arguments.unwrap_or_else(|| Vec::with_capacity(0)), + arguments, + ) + .with_position(span), + ) }, ), infix( left(4), just(Token::Control(Control::Dot)), |left, _, right, span| { - Expression::MapIndex(Box::new(MapIndex::new(left, right))) - .with_position(span) + Expression::MapIndex( + Box::new(MapIndex::new(left, right)).with_position(span), + ) }, ), infix( left(1), just(Token::Operator(Equal)), |left, _, right, span| { - Expression::Logic(Box::new(Logic::Equal(left, right))).with_position(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))) - .with_position(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))).with_position(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))).with_position(span) + Expression::Logic(Box::new(Logic::Less(left, right)).with_position(span)) }, ), infix( left(1), just(Token::Operator(GreaterOrEqual)), |left, _, right, span| { - Expression::Logic(Box::new(Logic::GreaterOrEqual(left, right))) - .with_position(span) + Expression::Logic( + Box::new(Logic::GreaterOrEqual(left, right)).with_position(span), + ) }, ), infix( left(1), just(Token::Operator(LessOrEqual)), |left, _, right, span| { - Expression::Logic(Box::new(Logic::LessOrEqual(left, right))) - .with_position(span) + Expression::Logic( + Box::new(Logic::LessOrEqual(left, right)).with_position(span), + ) }, ), infix( left(1), just(Token::Operator(And)), |left, _, right, span| { - Expression::Logic(Box::new(Logic::And(left, right))).with_position(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))).with_position(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))).with_position(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))).with_position(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))).with_position(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))).with_position(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))).with_position(span) + Expression::Math(Box::new(Math::Modulo(left, right)).with_position(span)) }, ), )); @@ -474,30 +485,21 @@ pub fn parser<'src>() -> impl Parser< )) }); - let expression_statement = - positioned_expression - .clone() - .map(|WithPosition { node, position }| { - Statement::Expression(node).with_position(position) - }); + let expression_statement = expression + .clone() + .map(|expression| Statement::Expression(expression)); let async_block = just(Token::Keyword(Keyword::Async)) - .ignore_then( - positioned_statement - .clone() - .repeated() - .collect() - .delimited_by( - just(Token::Control(Control::CurlyOpen)), - just(Token::Control(Control::CurlyClose)), - ), - ) + .ignore_then(statement.clone().repeated().collect().delimited_by( + just(Token::Control(Control::CurlyOpen)), + just(Token::Control(Control::CurlyClose)), + )) .map_with(|statements, state| { - Statement::AsyncBlock(AsyncBlock::new(statements)).with_position(state.span()) + Statement::AsyncBlock(AsyncBlock::new(statements).with_position(state.span())) }); let r#break = just(Token::Keyword(Keyword::Break)) - .map_with(|_, state| Statement::Break.with_position(state.span())); + .map_with(|_, state| Statement::Break(().with_position(state.span()))); let assignment = positioned_identifier .clone() @@ -507,17 +509,19 @@ pub fn parser<'src>() -> impl Parser< just(Token::Operator(Operator::AddAssign)).to(AssignmentOperator::AddAssign), just(Token::Operator(Operator::SubAssign)).to(AssignmentOperator::SubAssign), ))) - .then(positioned_statement.clone()) + .then(statement.clone()) .map_with(|(((identifier, r#type), operator), statement), state| { - Statement::Assignment(Assignment::new(identifier, r#type, operator, statement)) - .with_position(state.span()) + Statement::Assignment( + Assignment::new(identifier, r#type, operator, statement) + .with_position(state.span()), + ) }); let block_statement = block .clone() - .map_with(|block, state| Statement::Block(block).with_position(state.span())); + .map_with(|block, state| Statement::Block(block.with_position(state.span()))); - let r#loop = positioned_statement + let r#loop = statement .clone() .repeated() .at_least(1) @@ -527,37 +531,44 @@ pub fn parser<'src>() -> impl Parser< just(Token::Control(Control::CurlyClose)), ) .map_with(|statements, state| { - Statement::Loop(Loop::new(statements)).with_position(state.span()) + Statement::Loop(Loop::new(statements).with_position(state.span())) }); let r#while = just(Token::Keyword(Keyword::While)) - .ignore_then(positioned_expression.clone()) - .then( - positioned_statement - .clone() - .repeated() - .collect() - .delimited_by( - just(Token::Control(Control::CurlyOpen)), - just(Token::Control(Control::CurlyClose)), - ), - ) + .ignore_then(expression.clone()) + .then(statement.clone().repeated().collect().delimited_by( + just(Token::Control(Control::CurlyOpen)), + just(Token::Control(Control::CurlyClose)), + )) .map_with(|(expression, statements), state| { - Statement::While(While::new(expression, statements)).with_position(state.span()) + Statement::While(While::new(expression, statements).with_position(state.span())) }); let if_else = just(Token::Keyword(Keyword::If)) - .ignore_then(positioned_expression.clone()) + .ignore_then(expression.clone()) .then(block.clone()) + .then( + just(Token::Keyword(Keyword::Else)) + .ignore_then(just(Token::Keyword(Keyword::If))) + .ignore_then(expression.clone()) + .then(block.clone()) + .repeated() + .collect() + .or_not(), + ) .then( just(Token::Keyword(Keyword::Else)) .ignore_then(block.clone()) .or_not(), ) - .map_with(|((if_expression, if_block), else_block), state| { - Statement::IfElse(IfElse::new(if_expression, if_block, else_block)) - .with_position(state.span()) - }); + .map_with( + |(((if_expression, if_block), else_ifs), else_block), state| { + Statement::IfElse( + IfElse::new(if_expression, if_block, else_ifs, else_block) + .with_position(state.span()), + ) + }, + ); choice(( async_block, @@ -573,7 +584,7 @@ pub fn parser<'src>() -> impl Parser< .then_ignore(just(Token::Control(Control::Semicolon)).or_not()) }); - positioned_statement.repeated().collect() + statement.clone().repeated().collect() } #[cfg(test)] @@ -585,10 +596,10 @@ mod tests { #[test] fn built_in_function() { assert_eq!( - parse(&lex("__READ_LINE__").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::BuiltInFunction( - BuiltInFunction::ReadLine - ))) + parse(&lex("__READ_LINE__").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::BuiltInFunction(BuiltInFunction::ReadLine).with_position((0, 0)) + )) ) } @@ -605,16 +616,21 @@ mod tests { ") .unwrap() ) - .unwrap()[0] - .node, - Statement::AsyncBlock(AsyncBlock::new(vec![ - Statement::Expression(Expression::Value(ValueNode::Integer(1))) - .with_position((53, 54)), - Statement::Expression(Expression::Value(ValueNode::Integer(2))) - .with_position((79, 80)), - Statement::Expression(Expression::Value(ValueNode::Integer(3))) - .with_position((105, 106)), - ])) + .unwrap()[0], + Statement::AsyncBlock( + AsyncBlock::new(vec![ + Statement::Expression(Expression::Value( + ValueNode::Integer(1).with_position((0, 0)) + )), + Statement::Expression(Expression::Value( + ValueNode::Integer(2).with_position((0, 0)) + )), + Statement::Expression(Expression::Value( + ValueNode::Integer(3).with_position((0, 0)) + )), + ]) + .with_position((0, 0)) + ) ) } @@ -630,22 +646,25 @@ mod tests { ") .unwrap() ) - .unwrap()[0] - .node, - Statement::Expression(Expression::Value(ValueNode::Structure { - name: Identifier::new("Foo"), - fields: vec![ - ( - Identifier::new("bar"), - Expression::Value(ValueNode::Integer(42)).with_position((57, 59)) - ), - ( - Identifier::new("baz"), - Expression::Value(ValueNode::String("hiya".to_string())) - .with_position((91, 97)) - ), - ] - })) + .unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Structure { + name: Identifier::new("Foo").with_position((0, 0)), + fields: vec![ + ( + Identifier::new("bar"), + Expression::Value(ValueNode::Integer(42).with_position((57, 59))) + ), + ( + Identifier::new("baz"), + Expression::Value( + ValueNode::String("hiya".to_string()).with_position((91, 97)) + ) + ), + ] + } + .with_position((0, 0)) + )) ) } @@ -661,111 +680,139 @@ mod tests { ") .unwrap() ) - .unwrap()[0] - .node, - Statement::StructureDefinition(StructureDefinition::new( - Identifier::new("Foo"), - vec![ - ( - Identifier::new("bar"), - Type::Integer.with_position((64, 67)) - ), - ( - Identifier::new("baz"), - Type::String.with_position((99, 102)) - ), - ] - )) + .unwrap()[0], + Statement::StructureDefinition( + StructureDefinition::new( + Identifier::new("Foo"), + vec![ + ( + Identifier::new("bar"), + Type::Integer.with_position((64, 67)) + ), + ( + Identifier::new("baz"), + Type::String.with_position((99, 102)) + ), + ] + ) + .with_position((0, 0)) + ) ) } #[test] fn map_index() { assert_eq!( - parse(&lex("{ x = 42}.x").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::MapIndex(Box::new(MapIndex::new( - Expression::Value(ValueNode::Map(vec![( - Identifier::new("x"), - None, - Expression::Value(ValueNode::Integer(42)).with_position((6, 8)) - )])) - .with_position((0, 9)), - Expression::Identifier(Identifier::new("x")).with_position((10, 11)) - )))) + parse(&lex("{ x = 42}.x").unwrap()).unwrap()[0], + Statement::Expression(Expression::MapIndex( + Box::new(MapIndex::new( + Expression::Value( + ValueNode::Map(vec![( + Identifier::new("x"), + None, + Expression::Value(ValueNode::Integer(42).with_position((6, 8))) + )]) + .with_position((0, 9)) + ), + Expression::Identifier(Identifier::new("x").with_position((10, 11))) + )) + .with_position((0, 0)) + )) ); assert_eq!( - parse(&lex("foo.x").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::MapIndex(Box::new(MapIndex::new( - Expression::Identifier(Identifier::new("foo")).with_position((0, 3)), - Expression::Identifier(Identifier::new("x")).with_position((4, 5)) - )))) + parse(&lex("foo.x").unwrap()).unwrap()[0], + Statement::Expression(Expression::MapIndex( + Box::new(MapIndex::new( + Expression::Identifier(Identifier::new("foo").with_position((0, 3))), + Expression::Identifier(Identifier::new("x").with_position((4, 5))) + )) + .with_position((0, 0)) + )) ); } #[test] fn r#while() { assert_eq!( - parse(&lex("while true { output('hi') }").unwrap()).unwrap()[0].node, - Statement::While(While::new( - Expression::Value(ValueNode::Boolean(true)).with_position((6, 10)), - vec![ - Statement::Expression(Expression::FunctionCall(FunctionCall::new( - Expression::Identifier(Identifier::new("output")).with_position((13, 19)), - Vec::with_capacity(0), - vec![Expression::Value(ValueNode::String("hi".to_string())) - .with_position((20, 24))] - ))) - .with_position((13, 25)) - ] - )) + parse(&lex("while true { output('hi') }").unwrap()).unwrap()[0], + Statement::While( + While::new( + Expression::Value(ValueNode::Boolean(true).with_position((6, 10))), + vec![Statement::Expression(Expression::FunctionCall( + FunctionCall::new( + Expression::Identifier( + Identifier::new("output").with_position((13, 19)) + ), + Vec::with_capacity(0), + vec![Expression::Value( + ValueNode::String("hi".to_string()).with_position((20, 24)) + )] + ) + .with_position((13, 25)) + ))] + ) + .with_position((0, 0)) + ) ) } #[test] fn boolean_type() { assert_eq!( - parse(&lex("foobar : bool = true").unwrap()).unwrap()[0].node, - Statement::Assignment(Assignment::new( - Identifier::new("foobar").with_position((0, 6)), - Some(Type::Boolean.with_position((9, 13))), - AssignmentOperator::Assign, - Statement::Expression(Expression::Value(ValueNode::Boolean(true))) - .with_position((16, 20)) - ),) + parse(&lex("foobar : bool = true").unwrap()).unwrap()[0], + Statement::Assignment( + Assignment::new( + Identifier::new("foobar").with_position((0, 6)), + Some(Type::Boolean.with_position((9, 13))), + AssignmentOperator::Assign, + Statement::Expression(Expression::Value( + ValueNode::Boolean(true).with_position((16, 20)) + )) + ) + .with_position((0, 0)) + ) ); } #[test] fn list_type() { assert_eq!( - parse(&lex("foobar: list = []").unwrap()).unwrap()[0].node, - Statement::Assignment(Assignment::new( - Identifier::new("foobar").with_position((0, 6)), - Some(Type::List.with_position((8, 12))), - AssignmentOperator::Assign, - Statement::Expression(Expression::Value(ValueNode::List(vec![]))) - .with_position((15, 17)) - ),) + parse(&lex("foobar: list = []").unwrap()).unwrap()[0], + Statement::Assignment( + Assignment::new( + Identifier::new("foobar").with_position((0, 6)), + Some(Type::List.with_position((8, 12))), + AssignmentOperator::Assign, + Statement::Expression(Expression::Value( + ValueNode::List(vec![]).with_position((15, 17)) + )) + ) + .with_position((0, 0)) + ) ); } #[test] fn list_of_type() { assert_eq!( - parse(&lex("foobar : list(bool) = [true]").unwrap()).unwrap()[0].node, - Statement::Assignment(Assignment::new( - Identifier::new("foobar").with_position((0, 6)), - Some( - Type::ListOf(Box::new(Type::Boolean.with_position((14, 18)))) - .with_position((9, 19)) - ), - AssignmentOperator::Assign, - Statement::Expression(Expression::Value(ValueNode::List(vec![Expression::Value( - ValueNode::Boolean(true) + parse(&lex("foobar : list(bool) = [true]").unwrap()).unwrap()[0], + Statement::Assignment( + Assignment::new( + Identifier::new("foobar").with_position((0, 6)), + Some( + Type::ListOf(Box::new(Type::Boolean.with_position((14, 18)))) + .with_position((9, 19)) + ), + AssignmentOperator::Assign, + Statement::Expression(Expression::Value( + ValueNode::List(vec![Expression::Value( + ValueNode::Boolean(true).with_position((23, 27)) + )]) + .with_position((0, 0)) + )) ) - .with_position((23, 27))]))) - .with_position((22, 28)) - )) + .with_position((0, 0)) + ) ); } @@ -773,253 +820,315 @@ mod tests { fn list_exact_type() { assert_eq!( parse(&lex("foobar : [bool, str] = [true, '42']").unwrap()).unwrap()[0], - Statement::Assignment(Assignment::new( - Identifier::new("foobar").with_position((0, 6)), - Some( - Type::ListExact(vec![ - Type::Boolean.with_position((10, 14)), - Type::String.with_position((16, 19)) - ]) - .with_position((9, 20)) - ), - AssignmentOperator::Assign, - Statement::Expression(Expression::Value(ValueNode::List(vec![ - Expression::Value(ValueNode::Boolean(true)).with_position((24, 28)), - Expression::Value(ValueNode::String("42".to_string())).with_position((30, 34)) - ]))) - .with_position((23, 35)) - ),) - .with_position((0, 35)) + Statement::Assignment( + Assignment::new( + Identifier::new("foobar").with_position((0, 6)), + Some( + Type::ListExact(vec![ + Type::Boolean.with_position((10, 14)), + Type::String.with_position((16, 19)) + ]) + .with_position((9, 20)) + ), + AssignmentOperator::Assign, + Statement::Expression(Expression::Value( + ValueNode::List(vec![ + Expression::Value(ValueNode::Boolean(true).with_position((24, 28))), + Expression::Value( + ValueNode::String("42".to_string()).with_position((30, 34)) + ) + ]) + .with_position((0, 0)) + )) + ) + .with_position((0, 35)) + ) ); } #[test] fn function_type() { assert_eq!( - parse(&lex("foobar : fn() -> any = some_function").unwrap()).unwrap()[0].node, - Statement::Assignment(Assignment::new( - Identifier::new("foobar").with_position((0, 6)), - Some( - Type::Function { - parameter_types: vec![], - return_type: Box::new(Type::Any.with_position((17, 20))) - } - .with_position((9, 20)) - ), - AssignmentOperator::Assign, - Statement::Expression(Expression::Identifier(Identifier::new("some_function"))) - .with_position((23, 36)) - ),) + parse(&lex("foobar : fn() -> any = some_function").unwrap()).unwrap()[0], + Statement::Assignment( + Assignment::new( + Identifier::new("foobar").with_position((0, 6)), + Some( + Type::Function { + parameter_types: vec![], + return_type: Box::new(Type::Any.with_position((17, 20))) + } + .with_position((9, 20)) + ), + AssignmentOperator::Assign, + Statement::Expression(Expression::Identifier( + Identifier::new("some_function").with_position((0, 0)) + )) + ) + .with_position((0, 0)) + ) ); } #[test] fn function_call() { assert_eq!( - parse(&lex("io.write_line()").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::FunctionCall(FunctionCall::new( - Expression::MapIndex(Box::new(MapIndex::new( - Expression::Identifier(Identifier::new("io")).with_position((0, 2)), - Expression::Identifier(Identifier::new("write_line")).with_position((3, 13)) - ))) - .with_position((0, 13)), - Vec::with_capacity(0), - Vec::with_capacity(0), - ))) + parse(&lex("io.write_line()").unwrap()).unwrap()[0], + Statement::Expression(Expression::FunctionCall( + FunctionCall::new( + Expression::MapIndex( + Box::new(MapIndex::new( + Expression::Identifier(Identifier::new("io").with_position((0, 2))), + Expression::Identifier( + Identifier::new("write_line").with_position((3, 13)) + ) + )) + .with_position((0, 13)) + ), + Vec::with_capacity(0), + Vec::with_capacity(0), + ) + .with_position((0, 0)) + )) ) } #[test] fn function_call_with_type_arguments() { assert_eq!( - parse(&lex("foobar::(str)::('hi')").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::FunctionCall(FunctionCall::new( - Expression::Identifier(Identifier::new("foobar")).with_position((0, 6)), - vec![Type::String.with_position((9, 12))], - vec![Expression::Value(ValueNode::String("hi".to_string())).with_position((16, 20))], - ))) + parse(&lex("foobar::(str)::('hi')").unwrap()).unwrap()[0], + Statement::Expression(Expression::FunctionCall( + FunctionCall::new( + Expression::Identifier(Identifier::new("foobar").with_position((0, 6))), + vec![Type::String.with_position((9, 12))], + vec![Expression::Value( + ValueNode::String("hi".to_string()).with_position((0, 0)) + )], + ) + .with_position((0, 0)) + )) ) } #[test] fn range() { assert_eq!( - parse(&lex("1..10").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Range(1..10))) + parse(&lex("1..10").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Range(1..10).with_position((0, 0)) + )) ) } #[test] fn function() { assert_eq!( - parse(&lex("(x: int) int { x }").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::ParsedFunction { - type_arguments: Vec::with_capacity(0), - parameters: vec![(Identifier::new("x"), Type::Integer.with_position((4, 7)))], - return_type: Type::Integer.with_position((9, 12)), - body: Block::new(vec![Statement::Expression(Expression::Identifier( - Identifier::new("x") - ),) - .with_position((15, 16))]) - .with_position((0, 18)), - }),) + parse(&lex("(x: int) int { x }").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::ParsedFunction { + type_arguments: Vec::with_capacity(0), + parameters: vec![(Identifier::new("x"), Type::Integer.with_position((4, 7)))], + return_type: Type::Integer.with_position((9, 12)), + body: Block::new(vec![Statement::Expression(Expression::Identifier( + Identifier::new("x").with_position((0, 0)) + ))]) + .with_position((0, 18)), + } + .with_position((0, 0)) + ),) ) } #[test] fn function_with_type_arguments() { assert_eq!( - parse(&lex("(T, U)(x: T, y: U) T { x }").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::ParsedFunction { - type_arguments: vec![ - Type::Argument(Identifier::new("T")).with_position((1, 2)), - Type::Argument(Identifier::new("U")).with_position((4, 5)), - ], - parameters: vec![ - ( - Identifier::new("x"), - Type::Argument(Identifier::new("T")).with_position((10, 11)) - ), - ( - Identifier::new("y"), - Type::Argument(Identifier::new("U")).with_position((16, 17)) - ) - ], - return_type: Type::Argument(Identifier::new("T")).with_position((19, 20)), - body: Block::new(vec![Statement::Expression(Expression::Identifier( - Identifier::new("x") - ),) - .with_position((23, 24))]) - .with_position((0, 26)), - }),) + parse(&lex("(T, U)(x: T, y: U) T { x }").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::ParsedFunction { + type_arguments: vec![ + Type::Argument(Identifier::new("T")).with_position((1, 2)), + Type::Argument(Identifier::new("U")).with_position((4, 5)), + ], + parameters: vec![ + ( + Identifier::new("x"), + Type::Argument(Identifier::new("T")).with_position((0, 0)) + ), + ( + Identifier::new("y"), + Type::Argument(Identifier::new("U")).with_position((0, 0)) + ) + ], + return_type: Type::Argument(Identifier::new("T")).with_position((0, 0)), + body: Block::new(vec![Statement::Expression(Expression::Identifier( + Identifier::new("x").with_position((0, 0)) + ))]) + .with_position((0, 26)), + } + .with_position((0, 0)) + )) ) } #[test] fn r#if() { assert_eq!( - parse(&lex("if true { 'foo' }").unwrap()).unwrap()[0].node, - Statement::IfElse(IfElse::new( - Expression::Value(ValueNode::Boolean(true)).with_position((3, 7)), - Block::new(vec![Statement::Expression(Expression::Value( - ValueNode::String("foo".to_string()) - ),) - .with_position((10, 15))]), - None - ),) + parse(&lex("if true { 'foo' }").unwrap()).unwrap()[0], + Statement::IfElse( + IfElse::new( + Expression::Value(ValueNode::Boolean(true).with_position((3, 7))), + Block::new(vec![Statement::Expression(Expression::Value( + ValueNode::String("foo".to_string()).with_position((0, 0)) + ))]), + None, + None + ) + .with_position((0, 0)) + ) ); } #[test] fn if_else() { assert_eq!( - parse(&lex("if true {'foo' } else { 'bar' }").unwrap()).unwrap()[0].node, - Statement::IfElse(IfElse::new( - Expression::Value(ValueNode::Boolean(true)).with_position((3, 7)), - Block::new(vec![Statement::Expression(Expression::Value( - ValueNode::String("foo".to_string()) - ),) - .with_position((9, 14))]), - Some(Block::new(vec![Statement::Expression(Expression::Value( - ValueNode::String("bar".to_string()) - ),) - .with_position((24, 29))])) - ),) + parse(&lex("if true {'foo' } else { 'bar' }").unwrap()).unwrap()[0], + Statement::IfElse( + IfElse::new( + Expression::Value(ValueNode::Boolean(true).with_position((3, 7))), + Block::new(vec![Statement::Expression(Expression::Value( + ValueNode::String("foo".to_string()).with_position((0, 0)) + ))]), + None, + Some(Block::new(vec![Statement::Expression(Expression::Value( + ValueNode::String("bar".to_string()).with_position((0, 0)) + ))])) + ) + .with_position((0, 0)), + ) ) } #[test] fn map() { assert_eq!( - parse(&lex("{ foo = 'bar' }").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Map(vec![( - Identifier::new("foo"), - None, - Expression::Value(ValueNode::String("bar".to_string())).with_position((8, 13)) - )])),) + parse(&lex("{ foo = 'bar' }").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Map(vec![( + Identifier::new("foo"), + None, + Expression::Value(ValueNode::String("bar".to_string()).with_position((8, 13))) + )]) + .with_position((0, 0)) + ),) ); assert_eq!( - parse(&lex("{ x = 1, y = 2, }").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Map(vec![ - ( - Identifier::new("x"), - None, - Expression::Value(ValueNode::Integer(1)).with_position((6, 7)) - ), - ( - Identifier::new("y"), - None, - Expression::Value(ValueNode::Integer(2)).with_position((13, 14)) - ), - ])),) + parse(&lex("{ x = 1, y = 2, }").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Map(vec![ + ( + Identifier::new("x"), + None, + Expression::Value(ValueNode::Integer(1).with_position((6, 7))) + ), + ( + Identifier::new("y"), + None, + Expression::Value(ValueNode::Integer(2).with_position((13, 14))) + ), + ]) + .with_position((0, 0)) + ),) ); assert_eq!( - parse(&lex("{ x = 1 y = 2 }").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Map(vec![ - ( - Identifier::new("x"), - None, - Expression::Value(ValueNode::Integer(1)).with_position((6, 7)) - ), - ( - Identifier::new("y"), - None, - Expression::Value(ValueNode::Integer(2)).with_position((12, 13)) - ), - ])),) + parse(&lex("{ x = 1 y = 2 }").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Map(vec![ + ( + Identifier::new("x"), + None, + Expression::Value(ValueNode::Integer(1).with_position((6, 7))) + ), + ( + Identifier::new("y"), + None, + Expression::Value(ValueNode::Integer(2).with_position((12, 13))) + ), + ]) + .with_position((0, 0)) + ),) ); } #[test] fn math() { assert_eq!( - parse(&lex("1 + 1").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Math(Box::new(Math::Add( - Expression::Value(ValueNode::Integer(1)).with_position((0, 1)), - Expression::Value(ValueNode::Integer(1)).with_position((4, 5)) - ))),) + parse(&lex("1 + 1").unwrap()).unwrap()[0], + Statement::Expression(Expression::Math( + Box::new(Math::Add( + Expression::Value(ValueNode::Integer(1).with_position((0, 1))), + Expression::Value(ValueNode::Integer(1).with_position((4, 5))) + )) + .with_position((0, 0)) + )) ); } #[test] fn r#loop() { assert_eq!( - parse(&lex("loop { 42 }").unwrap()).unwrap()[0].node, - Statement::Loop(Loop::new(vec![Statement::Expression(Expression::Value( - ValueNode::Integer(42) - ),) - .with_position((7, 9))]),) + parse(&lex("loop { 42 }").unwrap()).unwrap()[0], + Statement::Loop( + Loop::new(vec![Statement::Expression(Expression::Value( + ValueNode::Integer(42).with_position((0, 0)) + ))]) + .with_position((0, 0)) + ) ); assert_eq!( - parse(&lex("loop { if i > 2 { break } else { i += 1 } }").unwrap()).unwrap()[0].node, - Statement::Loop(Loop::new(vec![Statement::IfElse(IfElse::new( - Expression::Logic(Box::new(Logic::Greater( - Expression::Identifier(Identifier::new("i")).with_position((10, 11)), - Expression::Value(ValueNode::Integer(2)).with_position((14, 15)) - ))) - .with_position((10, 15)), - Block::new(vec![Statement::Break.with_position((18, 23))]), - Some(Block::new(vec![Statement::Assignment(Assignment::new( - Identifier::new("i").with_position((33, 34)), - None, - AssignmentOperator::AddAssign, - Statement::Expression(Expression::Value(ValueNode::Integer(1))) - .with_position((38, 39)) - )) - .with_position((33, 39))])) - ),) - .with_position((7, 41))])) + parse(&lex("loop { if i > 2 { break } else { i += 1 } }").unwrap()).unwrap()[0], + Statement::Loop( + Loop::new(vec![Statement::IfElse( + IfElse::new( + Expression::Logic( + Box::new(Logic::Greater( + Expression::Identifier( + Identifier::new("i").with_position((10, 11)) + ), + Expression::Value(ValueNode::Integer(2).with_position((14, 15))) + )) + .with_position((0, 0)) + ), + Block::new(vec![Statement::Break(().with_position((18, 23)))]), + None, + Some(Block::new(vec![Statement::Assignment( + Assignment::new( + Identifier::new("i").with_position((33, 34)), + None, + AssignmentOperator::AddAssign, + Statement::Expression(Expression::Value( + ValueNode::Integer(1).with_position((0, 0)) + )) + ) + .with_position((0, 0)) + )])) + ) + .with_position((0, 0)) + )]) + .with_position((0, 0)) + ) ); } #[test] fn block() { assert_eq!( - parse(&lex("{ x }").unwrap()).unwrap()[0].node, - Statement::Block(Block::new(vec![Statement::Expression( - Expression::Identifier(Identifier::new("x")), + parse(&lex("{ x }").unwrap()).unwrap()[0], + Statement::Block( + Block::new(vec![Statement::Expression(Expression::Identifier( + Identifier::new("x").with_position((0, 0)) + ),)]) + .with_position((0, 0)) ) - .with_position((2, 3))]),) ); assert_eq!( @@ -1033,16 +1142,21 @@ mod tests { ") .unwrap() ) - .unwrap()[0] - .node, - Statement::Block(Block::new(vec![ - Statement::Expression(Expression::Identifier(Identifier::new("x"))) - .with_position((39, 40)), - Statement::Expression(Expression::Identifier(Identifier::new("y"))) - .with_position((62, 63)), - Statement::Expression(Expression::Identifier(Identifier::new("z"))) - .with_position((85, 86)), - ]),) + .unwrap()[0], + Statement::Block( + Block::new(vec![ + Statement::Expression(Expression::Identifier( + Identifier::new("x").with_position((0, 0)) + )), + Statement::Expression(Expression::Identifier( + Identifier::new("y").with_position((0, 0)) + )), + Statement::Expression(Expression::Identifier( + Identifier::new("z").with_position((0, 0)) + )), + ]) + .with_position((0, 0)), + ) ); assert_eq!( @@ -1055,221 +1169,300 @@ mod tests { ") .unwrap() ) - .unwrap()[0] - .node, - Statement::Block(Block::new(vec![ - Statement::Expression(Expression::Logic(Box::new(Logic::Equal( - Expression::Value(ValueNode::Integer(1)).with_position((39, 40)), - Expression::Value(ValueNode::Integer(1)).with_position((44, 45)) - ))),) - .with_position((39, 45)), - Statement::Expression(Expression::Identifier(Identifier::new("z"))) - .with_position((66, 67)), - ]),) + .unwrap()[0], + Statement::Block( + Block::new(vec![ + Statement::Expression(Expression::Logic( + Box::new(Logic::Equal( + Expression::Value(ValueNode::Integer(1).with_position((39, 40))), + Expression::Value(ValueNode::Integer(1).with_position((44, 45))) + )) + .with_position((0, 0)) + )), + Statement::Expression(Expression::Identifier( + Identifier::new("z").with_position((66, 67)) + )), + ]) + .with_position((0, 0)), + ) ); } #[test] fn identifier() { assert_eq!( - parse(&lex("x").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Identifier(Identifier::new("x"))) + parse(&lex("x").unwrap()).unwrap()[0], + Statement::Expression(Expression::Identifier( + Identifier::new("x").with_position((0, 0)) + )) ); assert_eq!( - parse(&lex("foobar").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Identifier(Identifier::new("foobar"))) + parse(&lex("foobar").unwrap()).unwrap()[0], + Statement::Expression(Expression::Identifier( + Identifier::new("foobar").with_position((0, 0)) + )) ); assert_eq!( - parse(&lex("HELLO").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Identifier(Identifier::new("HELLO"))) + parse(&lex("HELLO").unwrap()).unwrap()[0], + Statement::Expression(Expression::Identifier( + Identifier::new("HELLO").with_position((0, 0)) + )) ); } #[test] fn assignment() { assert_eq!( - parse(&lex("foobar = 1").unwrap()).unwrap()[0].node, - Statement::Assignment(Assignment::new( - Identifier::new("foobar").with_position((0, 6)), - None, - AssignmentOperator::Assign, - Statement::Expression(Expression::Value(ValueNode::Integer(1))) - .with_position((9, 10)) - ),) + parse(&lex("foobar = 1").unwrap()).unwrap()[0], + Statement::Assignment( + Assignment::new( + Identifier::new("foobar").with_position((0, 6)), + None, + AssignmentOperator::Assign, + Statement::Expression(Expression::Value( + ValueNode::Integer(1).with_position((9, 10)) + )) + ) + .with_position((0, 0)), + ) ); } #[test] fn assignment_with_type() { assert_eq!( - parse(&lex("foobar: int = 1").unwrap()).unwrap()[0].node, - Statement::Assignment(Assignment::new( - Identifier::new("foobar").with_position((0, 6)), - Some(Type::Integer.with_position((8, 11))), - AssignmentOperator::Assign, - Statement::Expression(Expression::Value(ValueNode::Integer(1))) - .with_position((14, 15)) - ),) + parse(&lex("foobar: int = 1").unwrap()).unwrap()[0], + Statement::Assignment( + Assignment::new( + Identifier::new("foobar").with_position((0, 6)), + Some(Type::Integer.with_position((8, 11))), + AssignmentOperator::Assign, + Statement::Expression(Expression::Value( + ValueNode::Integer(1).with_position((14, 15)) + )) + ) + .with_position((0, 0)), + ) ); } #[test] fn logic() { assert_eq!( - parse(&lex("x == 1").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Logic(Box::new(Logic::Equal( - Expression::Identifier(Identifier::new("x")).with_position((0, 1)), - Expression::Value(ValueNode::Integer(1)).with_position((5, 6)), - ))),) + parse(&lex("x == 1").unwrap()).unwrap()[0], + Statement::Expression(Expression::Logic( + Box::new(Logic::Equal( + Expression::Identifier(Identifier::new("x").with_position((0, 1))), + Expression::Value(ValueNode::Integer(1).with_position((5, 6))), + )) + .with_position((0, 0)) + )) ); assert_eq!( - parse(&lex("(x == 1) && (y == 2)").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Logic(Box::new(Logic::And( - Expression::Logic(Box::new(Logic::Equal( - Expression::Identifier(Identifier::new("x")).with_position((1, 2)), - Expression::Value(ValueNode::Integer(1)).with_position((6, 7)), - ))) - .with_position((1, 7)), - Expression::Logic(Box::new(Logic::Equal( - Expression::Identifier(Identifier::new("y")).with_position((13, 14)), - Expression::Value(ValueNode::Integer(2)).with_position((18, 19)), - ))) - .with_position((13, 19)), - ))),) + parse(&lex("(x == 1) && (y == 2)").unwrap()).unwrap()[0], + Statement::Expression(Expression::Logic( + Box::new(Logic::And( + Expression::Logic( + Box::new(Logic::Equal( + Expression::Identifier(Identifier::new("x").with_position((1, 2))), + Expression::Value(ValueNode::Integer(1).with_position((6, 7))), + )) + .with_position((0, 0)) + ), + Expression::Logic( + Box::new(Logic::Equal( + Expression::Identifier(Identifier::new("y").with_position((13, 14))), + Expression::Value(ValueNode::Integer(2).with_position((18, 19))), + )) + .with_position((0, 0)) + ) + )) + .with_position((0, 0)) + )) ); assert_eq!( - parse(&lex("(x == 1) && (y == 2) && true").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Logic(Box::new(Logic::And( - Expression::Logic(Box::new(Logic::And( - Expression::Logic(Box::new(Logic::Equal( - Expression::Identifier(Identifier::new("x")).with_position((1, 2)), - Expression::Value(ValueNode::Integer(1)).with_position((6, 7)) - ))) - .with_position((1, 7)), - Expression::Logic(Box::new(Logic::Equal( - Expression::Identifier(Identifier::new("y")).with_position((13, 14)), - Expression::Value(ValueNode::Integer(2)).with_position((18, 19)) - ))) - .with_position((13, 19)), - ))) - .with_position((0, 20)), - Expression::Value(ValueNode::Boolean(true)).with_position((24, 28)) - ))),) + parse(&lex("(x == 1) && (y == 2) && true").unwrap()).unwrap()[0], + Statement::Expression(Expression::Logic( + Box::new(Logic::And( + Expression::Logic( + Box::new(Logic::And( + Expression::Logic( + Box::new(Logic::Equal( + Expression::Identifier( + Identifier::new("x").with_position((1, 2)) + ), + Expression::Value(ValueNode::Integer(1).with_position((6, 7))) + )) + .with_position((1, 7)) + ), + Expression::Logic( + Box::new(Logic::Equal( + Expression::Identifier( + Identifier::new("y").with_position((13, 14)) + ), + Expression::Value( + ValueNode::Integer(2).with_position((18, 19)) + ) + )) + .with_position((13, 19)) + ), + )) + .with_position((0, 20)) + ), + Expression::Value(ValueNode::Boolean(true).with_position((24, 28))) + )) + .with_position((0, 0)) + )) ); } #[test] fn list() { assert_eq!( - parse(&lex("[]").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::List(Vec::with_capacity(0))),) + parse(&lex("[]").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::List(Vec::with_capacity(0)).with_position((0, 0)) + ),) ); assert_eq!( - parse(&lex("[42]").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::List(vec![Expression::Value( - ValueNode::Integer(42) - ) - .with_position((1, 3))])),) + parse(&lex("[42]").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::List(vec![Expression::Value( + ValueNode::Integer(42).with_position((0, 0)) + )]) + .with_position((1, 3)) + )) ); assert_eq!( - parse(&lex("[42, 'foo', 'bar', [1, 2, 3,]]").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::List(vec![ - Expression::Value(ValueNode::Integer(42)).with_position((1, 3)), - Expression::Value(ValueNode::String("foo".to_string())).with_position((5, 10)), - Expression::Value(ValueNode::String("bar".to_string())).with_position((12, 17)), - Expression::Value(ValueNode::List(vec![ - Expression::Value(ValueNode::Integer(1)).with_position((20, 21)), - Expression::Value(ValueNode::Integer(2)).with_position((23, 24)), - Expression::Value(ValueNode::Integer(3)).with_position((26, 27)), - ])) - .with_position((19, 29)) - ])),) + parse(&lex("[42, 'foo', 'bar', [1, 2, 3,]]").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::List(vec![ + Expression::Value(ValueNode::Integer(42).with_position((1, 3))), + Expression::Value(ValueNode::String("foo".to_string()).with_position((5, 10))), + Expression::Value(ValueNode::String("bar".to_string()).with_position((12, 17))), + Expression::Value( + ValueNode::List(vec![ + Expression::Value(ValueNode::Integer(1).with_position((20, 21))), + Expression::Value(ValueNode::Integer(2).with_position((23, 24))), + Expression::Value(ValueNode::Integer(3).with_position((26, 27))), + ]) + .with_position((0, 0)) + ) + ]) + .with_position((0, 0)) + ),) ); } #[test] fn r#true() { assert_eq!( - parse(&lex("true").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Boolean(true))) + parse(&lex("true").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Boolean(true).with_position((0, 0)) + )) ); } #[test] fn r#false() { assert_eq!( - parse(&lex("false").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Boolean(false))) + parse(&lex("false").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Boolean(false).with_position((0, 0)) + )) ); } #[test] fn positive_float() { assert_eq!( - parse(&lex("0.0").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Float(0.0))) + parse(&lex("0.0").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Float(0.0).with_position((0, 0)) + )) ); assert_eq!( - parse(&lex("42.0").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Float(42.0))) + parse(&lex("42.0").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Float(42.0).with_position((0, 0)) + )) ); let max_float = f64::MAX.to_string() + ".0"; assert_eq!( - parse(&lex(&max_float).unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Float(f64::MAX))) + parse(&lex(&max_float).unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Float(f64::MAX).with_position((0, 0)) + )) ); let min_positive_float = f64::MIN_POSITIVE.to_string(); assert_eq!( - parse(&lex(&min_positive_float).unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Float(f64::MIN_POSITIVE)),) + parse(&lex(&min_positive_float).unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Float(f64::MIN_POSITIVE).with_position((0, 0)) + ),) ); } #[test] fn negative_float() { assert_eq!( - parse(&lex("-0.0").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Float(-0.0))) + parse(&lex("-0.0").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Float(-0.0).with_position((0, 0)) + )) ); assert_eq!( - parse(&lex("-42.0").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Float(-42.0))) + parse(&lex("-42.0").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Float(-42.0).with_position((0, 0)) + )) ); let min_float = f64::MIN.to_string() + ".0"; assert_eq!( - parse(&lex(&min_float).unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Float(f64::MIN))) + parse(&lex(&min_float).unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Float(f64::MIN).with_position((0, 0)) + )) ); let max_negative_float = format!("-{}", f64::MIN_POSITIVE); assert_eq!( - parse(&lex(&max_negative_float).unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Float(-f64::MIN_POSITIVE)),) + parse(&lex(&max_negative_float).unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Float(-f64::MIN_POSITIVE).with_position((0, 0)) + ),) ); } #[test] fn other_float() { assert_eq!( - parse(&lex("Infinity").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Float(f64::INFINITY))) + parse(&lex("Infinity").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Float(f64::INFINITY).with_position((0, 0)) + )) ); assert_eq!( - parse(&lex("-Infinity").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Float(f64::NEG_INFINITY)),) + parse(&lex("-Infinity").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Float(f64::NEG_INFINITY).with_position((0, 0)) + )) ); - if let Statement::Expression(Expression::Value(ValueNode::Float(float))) = - &parse(&lex("NaN").unwrap()).unwrap()[0].node + if let Statement::Expression(Expression::Value(WithPosition { + node: ValueNode::Float(float), + .. + })) = &parse(&lex("NaN").unwrap()).unwrap()[0] { assert!(float.is_nan()); } else { @@ -1285,21 +1478,27 @@ mod tests { let statements = parse(&tokens).unwrap(); assert_eq!( - statements[0].node, - Statement::Expression(Expression::Value(ValueNode::Integer(i))) + statements[0], + Statement::Expression(Expression::Value( + ValueNode::Integer(i).with_position((0, 0)) + )) ) } assert_eq!( - parse(&lex("42").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Integer(42))) + parse(&lex("42").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Integer(42).with_position((0, 0)) + )) ); let maximum_integer = i64::MAX.to_string(); assert_eq!( - parse(&lex(&maximum_integer).unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Integer(i64::MAX))) + parse(&lex(&maximum_integer).unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Integer(i64::MAX).with_position((0, 0)) + )) ); } @@ -1311,69 +1510,93 @@ mod tests { let statements = parse(&tokens).unwrap(); assert_eq!( - statements[0].node, - Statement::Expression(Expression::Value(ValueNode::Integer(i))) + statements[0], + Statement::Expression(Expression::Value( + ValueNode::Integer(i).with_position((0, 0)) + )) ) } assert_eq!( - parse(&lex("-42").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Integer(-42))) + parse(&lex("-42").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Integer(-42).with_position((0, 0)) + )) ); let minimum_integer = i64::MIN.to_string(); assert_eq!( - parse(&lex(&minimum_integer).unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::Integer(i64::MIN))) + parse(&lex(&minimum_integer).unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::Integer(i64::MIN).with_position((0, 0)) + )) ); } #[test] fn double_quoted_string() { assert_eq!( - parse(&lex("\"\"").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::String("".to_string()))) + parse(&lex("\"\"").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::String("".to_string()).with_position((0, 0)) + )) ); assert_eq!( - parse(&lex("\"42\"").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::String("42".to_string())),) + parse(&lex("\"42\"").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::String("42".to_string()).with_position((0, 0)) + ),) ); assert_eq!( - parse(&lex("\"foobar\"").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::String("foobar".to_string())),) + parse(&lex("\"foobar\"").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::String("foobar".to_string()).with_position((0, 0)) + ),) ); } #[test] fn single_quoted_string() { assert_eq!( - parse(&lex("''").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::String("".to_string()))) + parse(&lex("''").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::String("".to_string()).with_position((0, 0)) + )) ); assert_eq!( - parse(&lex("'42'").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::String("42".to_string())),) + parse(&lex("'42'").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::String("42".to_string()).with_position((0, 0)) + ),) ); assert_eq!( - parse(&lex("'foobar'").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::String("foobar".to_string())),) + parse(&lex("'foobar'").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::String("foobar".to_string()).with_position((0, 0)) + ),) ); } #[test] fn grave_quoted_string() { assert_eq!( - parse(&lex("``").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::String("".to_string()))) + parse(&lex("``").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::String("".to_string()).with_position((0, 0)) + )) ); assert_eq!( - parse(&lex("`42`").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::String("42".to_string())),) + parse(&lex("`42`").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::String("42".to_string()).with_position((0, 0)) + ),) ); assert_eq!( - parse(&lex("`foobar`").unwrap()).unwrap()[0].node, - Statement::Expression(Expression::Value(ValueNode::String("foobar".to_string())),) + parse(&lex("`foobar`").unwrap()).unwrap()[0], + Statement::Expression(Expression::Value( + ValueNode::String("foobar".to_string()).with_position((0, 0)) + ),) ); } } diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index a6d248a..cb6d2f2 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -13,10 +13,11 @@ use stanza::{ }; use crate::{ - abstract_tree::{AbstractNode, Action, Block, Identifier, Type, WithPos, WithPosition}, + abstract_tree::{AbstractNode, Action, Block, Type, WithPos, WithPosition}, built_in_functions::BuiltInFunction, context::Context, error::{RuntimeError, ValidationError}, + identifier::Identifier, }; #[derive(Clone, Debug, PartialEq)] @@ -71,7 +72,7 @@ impl Value { )))) } - pub fn structure(name: Identifier, fields: Vec<(Identifier, Value)>) -> Self { + pub fn structure(name: WithPosition, fields: Vec<(Identifier, Value)>) -> Self { Value(Arc::new(ValueInner::Structure { name, fields })) } @@ -176,7 +177,7 @@ impl Display for Value { table = table.with_row([identifier.as_str(), &value.to_string()]); } - write!(f, "{name}\n{}", Console::default().render(&table)) + write!(f, "{}\n{}", name.node, Console::default().render(&table)) } } } @@ -207,7 +208,7 @@ pub enum ValueInner { Range(Range), String(String), Structure { - name: Identifier, + name: WithPosition, fields: Vec<(Identifier, Value)>, }, } @@ -244,10 +245,13 @@ impl ValueInner { } }, ValueInner::Structure { name, .. } => { - if let Some(r#type) = context.get_type(name)? { + if let Some(r#type) = context.get_type(&name.node)? { r#type } else { - return Err(ValidationError::VariableNotFound(name.clone())); + return Err(ValidationError::VariableNotFound { + identifier: name.node.clone(), + position: name.position, + }); } } }; diff --git a/dust-lang/tests/functions.rs b/dust-lang/tests/functions.rs index 4e6699b..e4576e1 100644 --- a/dust-lang/tests/functions.rs +++ b/dust-lang/tests/functions.rs @@ -1,6 +1,6 @@ use dust_lang::{ - abstract_tree::Identifier, error::{Error, ValidationError}, + identifier::Identifier, *, }; @@ -69,7 +69,10 @@ fn function_context_does_not_capture_values() { .unwrap_err() .errors(), &vec![Error::Validation { - error: ValidationError::VariableNotFound(Identifier::new("x")), + error: ValidationError::VariableNotFound { + identifier: Identifier::new("x"), + position: (0, 0).into() + }, position: (32, 50).into() }] ); diff --git a/dust-lang/tests/structs.rs b/dust-lang/tests/structs.rs index 4a76720..24e381a 100644 --- a/dust-lang/tests/structs.rs +++ b/dust-lang/tests/structs.rs @@ -1,6 +1,7 @@ use dust_lang::{ - abstract_tree::{Identifier, Type}, + abstract_tree::{Type, WithPos}, error::{Error, TypeConflict, ValidationError}, + identifier::Identifier, interpret, Value, }; @@ -22,7 +23,7 @@ fn simple_structure() { " ), Ok(Some(Value::structure( - Identifier::new("Foo"), + Identifier::new("Foo").with_position((0, 0)), vec![ (Identifier::new("bar"), Value::integer(42)), (Identifier::new("baz"), Value::string("hiya".to_string())), @@ -83,11 +84,11 @@ fn nested_structure() { " ), Ok(Some(Value::structure( - Identifier::new("Foo"), + Identifier::new("Foo").with_position((0, 0)), vec![( Identifier::new("bar"), Value::structure( - Identifier::new("Bar"), + Identifier::new("Bar").with_position((0, 0)), vec![(Identifier::new("baz"), Value::integer(42))] ) ),] @@ -109,7 +110,10 @@ fn undefined_struct() { .unwrap_err() .errors(), &vec![Error::Validation { - error: ValidationError::VariableNotFound(Identifier::new("Foo")), + error: ValidationError::VariableNotFound { + identifier: Identifier::new("Foo"), + position: (0, 0).into() + }, position: (17, 69).into() }] ) diff --git a/dust-lang/tests/values.rs b/dust-lang/tests/values.rs index 237696c..22767a6 100644 --- a/dust-lang/tests/values.rs +++ b/dust-lang/tests/values.rs @@ -1,8 +1,9 @@ use std::collections::BTreeMap; use dust_lang::{ - abstract_tree::{Identifier, Type, WithPos}, + abstract_tree::{Type, WithPos}, error::{Error, TypeConflict, ValidationError}, + identifier::Identifier, *, }; diff --git a/dust-lang/tests/variables.rs b/dust-lang/tests/variables.rs index 3a54e54..b1ea9e6 100644 --- a/dust-lang/tests/variables.rs +++ b/dust-lang/tests/variables.rs @@ -1,6 +1,7 @@ use dust_lang::{ - abstract_tree::{Block, Expression, Identifier, Statement, Type, WithPos}, + abstract_tree::{Block, Expression, Statement, Type, WithPos}, error::{Error, TypeConflict, ValidationError}, + identifier::Identifier, *, }; @@ -49,9 +50,8 @@ fn function_variable() { vec![(Identifier::new("x"), Type::Integer.with_position((13, 16)))], Type::Integer.with_position((18, 21)), Block::new(vec![Statement::Expression(Expression::Identifier( - Identifier::new("x") - )) - .with_position((24, 25))]) + Identifier::new("x").with_position((0, 0)) + ))]) .with_position((9, 27)) ))) ); diff --git a/examples/fizzbuzz.ds b/examples/fizzbuzz.ds new file mode 100644 index 0000000..28211cc --- /dev/null +++ b/examples/fizzbuzz.ds @@ -0,0 +1,18 @@ +count = 1 + +while count <= 15 { + divides_by_3 = count % 3 == 0 + divides_by_5 = count % 5 == 0 + + if divides_by_3 && divides_by_5 { + output('fizzbuzz') + } else if divides_by_3 { + output('fizz') + } else if divides_by_5 { + output('buzz') + } else { + output(count) + } + + count += 1 +}