From 7dcfccf7cb2cd16057eb65033b35ec1c24522070 Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 18 Mar 2024 05:39:09 -0400 Subject: [PATCH] Improve errors --- src/abstract_tree/assignment.rs | 86 ++++++-- src/abstract_tree/identifier.rs | 15 +- src/abstract_tree/if_else.rs | 9 +- src/abstract_tree/list_index.rs | 18 +- src/abstract_tree/logic.rs | 340 ++++++++++++++------------------ src/abstract_tree/loop.rs | 4 +- src/abstract_tree/map_index.rs | 20 +- src/abstract_tree/math.rs | 245 ++++++++++++++++++----- src/abstract_tree/value_node.rs | 18 +- src/abstract_tree/while.rs | 14 +- src/error.rs | 21 +- src/main.rs | 61 +----- src/parser.rs | 16 +- src/value.rs | 54 +---- 14 files changed, 508 insertions(+), 413 deletions(-) diff --git a/src/abstract_tree/assignment.rs b/src/abstract_tree/assignment.rs index aac360b..f246538 100644 --- a/src/abstract_tree/assignment.rs +++ b/src/abstract_tree/assignment.rs @@ -1,6 +1,7 @@ use crate::{ error::{RuntimeError, ValidationError}, - Context, + value::ValueInner, + Context, Value, }; use super::{AbstractTree, Action, Identifier, Statement, Type, WithPosition}; @@ -70,40 +71,94 @@ impl AbstractTree for Assignment { fn run(self, context: &Context) -> Result { let action = self.statement.node.run(context)?; - let value = match action { + let right = match action { Action::Return(value) => value, r#break => return Ok(r#break), }; match self.operator { AssignmentOperator::Assign => { - context.set_value(self.identifier.node, value)?; + context.set_value(self.identifier.node, right)?; } AssignmentOperator::AddAssign => { - if let Some(previous_value) = context.get_value(&self.identifier.node)? { - let new_value = previous_value.add(&value)?; + if let Some(left) = context.get_value(&self.identifier.node)? { + let new_value = match (left.inner().as_ref(), right.inner().as_ref()) { + (ValueInner::Integer(left), ValueInner::Integer(right)) => { + let sum = left.saturating_add(*right); + Value::integer(sum) + } + (ValueInner::Float(left), ValueInner::Float(right)) => { + let sum = left + right; + + Value::float(sum) + } + (ValueInner::Float(left), ValueInner::Integer(right)) => { + let sum = left + *right as f64; + + Value::float(sum) + } + (ValueInner::Integer(left), ValueInner::Float(right)) => { + let sum = *left as f64 + right; + + Value::float(sum) + } + (ValueInner::Integer(_) | ValueInner::Float(_), _) => { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedIntegerOrFloat(self.statement.position), + )) + } + _ => { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedIntegerOrFloat(self.identifier.position), + )) + } + }; context.set_value(self.identifier.node, new_value)?; } else { return Err(RuntimeError::ValidationFailure( - ValidationError::VariableNotFound { - identifier: self.identifier.node, - position: self.identifier.position, - }, + ValidationError::VariableNotFound(self.identifier.node), )); } } AssignmentOperator::SubAssign => { - if let Some(previous_value) = context.get_value(&self.identifier.node)? { - let new_value = previous_value.subtract(&value)?; + if let Some(left) = context.get_value(&self.identifier.node)? { + let new_value = match (left.inner().as_ref(), right.inner().as_ref()) { + (ValueInner::Integer(left), ValueInner::Integer(right)) => { + let difference = left.saturating_sub(*right); + Value::integer(difference) + } + (ValueInner::Float(left), ValueInner::Float(right)) => { + let difference = left - right; + + Value::float(difference) + } + (ValueInner::Float(left), ValueInner::Integer(right)) => { + let difference = left - *right as f64; + + Value::float(difference) + } + (ValueInner::Integer(left), ValueInner::Float(right)) => { + let difference = *left as f64 - right; + + Value::float(difference) + } + (ValueInner::Integer(_) | ValueInner::Float(_), _) => { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedIntegerOrFloat(self.statement.position), + )) + } + _ => { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedIntegerOrFloat(self.identifier.position), + )) + } + }; context.set_value(self.identifier.node, new_value)?; } else { return Err(RuntimeError::ValidationFailure( - ValidationError::VariableNotFound { - identifier: self.identifier.node, - position: self.identifier.position, - }, + ValidationError::VariableNotFound(self.identifier.node), )); } } @@ -118,7 +173,6 @@ mod tests { use crate::{ abstract_tree::{Expression, ValueNode}, error::TypeConflict, - Value, }; use super::*; diff --git a/src/abstract_tree/identifier.rs b/src/abstract_tree/identifier.rs index 78aa1d8..aaaa9be 100644 --- a/src/abstract_tree/identifier.rs +++ b/src/abstract_tree/identifier.rs @@ -28,10 +28,7 @@ impl AbstractTree for Identifier { if let Some(r#type) = context.get_type(self)? { Ok(r#type) } else { - Err(ValidationError::VariableNotFound { - identifier: todo!(), - position: todo!(), - }) + Err(ValidationError::VariableNotFound(self.clone())) } } @@ -39,10 +36,7 @@ impl AbstractTree for Identifier { if context.contains(self)? { Ok(()) } else { - Err(ValidationError::VariableNotFound { - identifier: todo!(), - position: todo!(), - }) + Err(ValidationError::VariableNotFound(self.clone())) } } @@ -53,10 +47,7 @@ impl AbstractTree for Identifier { Ok(action) } else { Err(RuntimeError::ValidationFailure( - ValidationError::VariableNotFound { - identifier: todo!(), - position: todo!(), - }, + ValidationError::VariableNotFound(self.clone()), )) } } diff --git a/src/abstract_tree/if_else.rs b/src/abstract_tree/if_else.rs index 215d4c9..027a1e2 100644 --- a/src/abstract_tree/if_else.rs +++ b/src/abstract_tree/if_else.rs @@ -64,7 +64,14 @@ impl AbstractTree for IfElse { } fn run(self, _context: &Context) -> Result { - let value = self.if_expression.node.run(_context)?.as_return_value()?; + let action = self.if_expression.node.run(_context)?; + let value = if let Action::Return(value) = action { + value + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::InterpreterExpectedReturn(self.if_expression.position), + )); + }; if let ValueInner::Boolean(if_boolean) = value.inner().as_ref() { if *if_boolean { diff --git a/src/abstract_tree/list_index.rs b/src/abstract_tree/list_index.rs index 001129e..a6cc62a 100644 --- a/src/abstract_tree/list_index.rs +++ b/src/abstract_tree/list_index.rs @@ -69,8 +69,22 @@ impl AbstractTree for ListIndex { } fn run(self, _context: &Context) -> Result { - let left_value = self.left.node.run(_context)?.as_return_value()?; - let right_value = self.right.node.run(_context)?.as_return_value()?; + let left_action = self.left.node.run(_context)?; + let left_value = if let Action::Return(value) = left_action { + value + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::InterpreterExpectedReturn(self.left.position), + )); + }; + let right_action = self.right.node.run(_context)?; + let right_value = if let Action::Return(value) = right_action { + value + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::InterpreterExpectedReturn(self.left.position), + )); + }; if let (Some(list), Some(index)) = (left_value.as_list(), right_value.as_integer()) { let found_item = list.get(index as usize); diff --git a/src/abstract_tree/logic.rs b/src/abstract_tree/logic.rs index 86ebb02..32650f0 100644 --- a/src/abstract_tree/logic.rs +++ b/src/abstract_tree/logic.rs @@ -84,110 +84,100 @@ impl AbstractTree for Logic { } fn run(self, _context: &Context) -> Result { - let boolean = match self { - Logic::Equal(left, right) => { - let left = left.node.run(_context)?.as_return_value()?; - let right = right.node.run(_context)?.as_return_value()?; - - left == right - } - Logic::NotEqual(left, right) => { - let left = left.node.run(_context)?.as_return_value()?; - let right = right.node.run(_context)?.as_return_value()?; - - left != right - } - Logic::Greater(left, right) => { - let left = left.node.run(_context)?.as_return_value()?; - let right = right.node.run(_context)?.as_return_value()?; - - left > right - } - Logic::Less(left, right) => { - let left = left.node.run(_context)?.as_return_value()?; - let right = right.node.run(_context)?.as_return_value()?; - - left < right - } - Logic::GreaterOrEqual(left, right) => { - let left = left.node.run(_context)?.as_return_value()?; - let right = right.node.run(_context)?.as_return_value()?; - - left >= right - } - Logic::LessOrEqual(left, right) => { - let left = left.node.run(_context)?.as_return_value()?; - let right = right.node.run(_context)?.as_return_value()?; - - left <= right - } - Logic::And(left, right) => { - let left_value = left.node.run(_context)?.as_return_value()?; - let right_value = right.node.run(_context)?.as_return_value()?; - - let left = if let ValueInner::Boolean(boolean) = left_value.inner().as_ref() { - boolean + 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::ExpectedBoolean { - actual: left_value.r#type(), - position: left.position, - }, - )); - }; - let right = if let ValueInner::Boolean(boolean) = right_value.inner().as_ref() { - boolean - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedBoolean { - actual: right_value.r#type(), - position: right.position, - }, + ValidationError::InterpreterExpectedReturn(expression.position), )); }; - *left && *right - } - Logic::Or(left, right) => { - let left_value = left.node.run(_context)?.as_return_value()?; - let right_value = right.node.run(_context)?.as_return_value()?; + Ok(value) + }; - let left = if let ValueInner::Boolean(boolean) = left_value.inner().as_ref() { - boolean + 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::ExpectedBoolean { - actual: left_value.r#type(), - position: left.position, - }, + ValidationError::InterpreterExpectedReturn(expression.position), )); }; - let right = if let ValueInner::Boolean(boolean) = right_value.inner().as_ref() { - boolean - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedBoolean { - actual: right_value.r#type(), - position: right.position, - }, - )); - }; - - *left || *right - } - Logic::Not(statement) => { - let value = statement.node.run(_context)?.as_return_value()?; if let ValueInner::Boolean(boolean) = value.inner().as_ref() { - !boolean + Ok(*boolean) } else { return Err(RuntimeError::ValidationFailure( ValidationError::ExpectedBoolean { actual: value.r#type(), - position: statement.position, + position: expression.position, }, )); } + }; + + let boolean = match self { + Logic::Equal(left, right) => { + let (left_value, right_value) = + (run_and_expect_value(left)?, run_and_expect_value(right)?); + + left_value == right_value + } + Logic::NotEqual(left, right) => { + let (left_value, right_value) = + (run_and_expect_value(left)?, run_and_expect_value(right)?); + + left_value != right_value + } + Logic::Greater(left, right) => { + let (left_value, right_value) = + (run_and_expect_value(left)?, run_and_expect_value(right)?); + + left_value > right_value + } + Logic::Less(left, right) => { + let (left_value, right_value) = + (run_and_expect_value(left)?, run_and_expect_value(right)?); + + left_value < right_value + } + Logic::GreaterOrEqual(left, right) => { + let (left_value, right_value) = + (run_and_expect_value(left)?, run_and_expect_value(right)?); + + left_value >= right_value + } + Logic::LessOrEqual(left, right) => { + let (left_value, right_value) = + (run_and_expect_value(left)?, run_and_expect_value(right)?); + + left_value <= right_value + } + Logic::And(left, right) => { + let (left_boolean, right_boolean) = ( + run_and_expect_boolean(left)?, + run_and_expect_boolean(right)?, + ); + + left_boolean && right_boolean + } + Logic::Or(left, right) => { + let (left_boolean, right_boolean) = ( + run_and_expect_boolean(left)?, + run_and_expect_boolean(right)?, + ); + + left_boolean || right_boolean + } + Logic::Not(statement) => { + let boolean = run_and_expect_boolean(statement)?; + + !boolean } }; @@ -203,148 +193,124 @@ mod tests { #[test] fn equal() { - assert!(Logic::Equal( - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), + assert_eq!( + Logic::Equal( + 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))) ) - .run(&Context::new()) - .unwrap() - .as_return_value() - .unwrap() - .as_boolean() - .unwrap()) } #[test] fn not_equal() { - assert!(Logic::NotEqual( - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), - Expression::Value(ValueNode::Integer(43)).with_position((0, 0)), + assert_eq!( + Logic::NotEqual( + 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))) ) - .run(&Context::new()) - .unwrap() - .as_return_value() - .unwrap() - .as_boolean() - .unwrap()) } #[test] fn greater() { - assert!(Logic::Greater( - Expression::Value(ValueNode::Integer(43)).with_position((0, 0)), - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), + assert_eq!( + Logic::Greater( + 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))) ) - .run(&Context::new()) - .unwrap() - .as_return_value() - .unwrap() - .as_boolean() - .unwrap()) } #[test] fn less() { - assert!(Logic::Less( - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), - Expression::Value(ValueNode::Integer(43)).with_position((0, 0)), + assert_eq!( + Logic::Less( + 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))) ) - .run(&Context::new()) - .unwrap() - .as_return_value() - .unwrap() - .as_boolean() - .unwrap()) } #[test] fn greater_or_equal() { - assert!(Logic::GreaterOrEqual( - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), - Expression::Value(ValueNode::Integer(41)).with_position((0, 0)), - ) - .run(&Context::new()) - .unwrap() - .as_return_value() - .unwrap() - .as_boolean() - .unwrap()); + assert_eq!( + Logic::GreaterOrEqual( + 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))) + ); - assert!(Logic::GreaterOrEqual( - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), - ) - .run(&Context::new()) - .unwrap() - .as_return_value() - .unwrap() - .as_boolean() - .unwrap()) + assert_eq!( + Logic::GreaterOrEqual( + 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))) + ); } #[test] fn less_or_equal() { - assert!(Logic::LessOrEqual( - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), - Expression::Value(ValueNode::Integer(43)).with_position((0, 0)), - ) - .run(&Context::new()) - .unwrap() - .as_return_value() - .unwrap() - .as_boolean() - .unwrap()); + assert_eq!( + Logic::LessOrEqual( + 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))) + ); - assert!(Logic::LessOrEqual( - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), - Expression::Value(ValueNode::Integer(42)).with_position((0, 0)), - ) - .run(&Context::new()) - .unwrap() - .as_return_value() - .unwrap() - .as_boolean() - .unwrap()) + assert_eq!( + Logic::LessOrEqual( + 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))) + ); } #[test] fn and() { - assert!(Logic::And( - Expression::Value(ValueNode::Boolean(true)).with_position((0, 0)), - Expression::Value(ValueNode::Boolean(true)).with_position((0, 0)), + assert_eq!( + Logic::And( + 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))) ) - .run(&Context::new()) - .unwrap() - .as_return_value() - .unwrap() - .as_boolean() - .unwrap()) } #[test] fn or() { - assert!(Logic::Or( - Expression::Value(ValueNode::Boolean(true)).with_position((0, 0)), - Expression::Value(ValueNode::Boolean(false)).with_position((0, 0)), + assert_eq!( + Logic::Or( + 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))) ) - .run(&Context::new()) - .unwrap() - .as_return_value() - .unwrap() - .as_boolean() - .unwrap()) } #[test] fn not() { - assert!( - Logic::Not(Expression::Value(ValueNode::Boolean(false)).with_position((0, 0))) - .run(&Context::new()) - .unwrap() - .as_return_value() - .unwrap() - .as_boolean() - .unwrap() + assert_eq!( + Logic::Not(Expression::Value(ValueNode::Boolean(false)).with_position((0, 0)),) + .run(&Context::new()), + Ok(Action::Return(Value::boolean(true))) ) } } diff --git a/src/abstract_tree/loop.rs b/src/abstract_tree/loop.rs index b17b3fc..605727c 100644 --- a/src/abstract_tree/loop.rs +++ b/src/abstract_tree/loop.rs @@ -90,7 +90,7 @@ mod tests { fn complex_loop() { let action = Block::new(vec![ Statement::Assignment(Assignment::new( - Identifier::new("i"), + Identifier::new("i").with_position((0, 0)), None, AssignmentOperator::Assign, Statement::Expression(Expression::Value(ValueNode::Integer(1))) @@ -105,7 +105,7 @@ mod tests { .with_position((10, 15)), Block::new(vec![Statement::Break.with_position((18, 24))]), Some(Block::new(vec![Statement::Assignment(Assignment::new( - Identifier::new("i"), + Identifier::new("i").with_position((0, 0)), None, AssignmentOperator::AddAssign, Statement::Expression(Expression::Value(ValueNode::Integer(1))) diff --git a/src/abstract_tree/map_index.rs b/src/abstract_tree/map_index.rs index 8de559e..8f25736 100644 --- a/src/abstract_tree/map_index.rs +++ b/src/abstract_tree/map_index.rs @@ -39,9 +39,10 @@ impl AbstractTree for MapIndex { return if let Some(value) = map.get(index_identifier) { Ok(value.r#type()) } else { - Err(ValidationError::PropertyNotFound( - collection_identifier.clone(), - )) + Err(ValidationError::PropertyNotFound { + identifier: index_identifier.clone(), + position: self.right.position, + }) }; }; } @@ -72,7 +73,7 @@ impl AbstractTree for MapIndex { Err(ValidationError::CannotIndexWith { collection_type: left_type, - collection_position: todo!(), + collection_position: self.left.position, index_type: self.right.node.expected_type(_context)?, index_position: self.right.position, }) @@ -100,7 +101,14 @@ impl AbstractTree for MapIndex { } fn run(self, _context: &Context) -> Result { - let collection = self.left.node.run(_context)?.as_return_value()?; + let action = self.left.node.run(_context)?; + let collection = if let Action::Return(value) = action { + value + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::InterpreterExpectedReturn(self.left.position), + )); + }; if let (ValueInner::Map(map), Expression::Identifier(identifier)) = (collection.inner().as_ref(), &self.right.node) @@ -115,7 +123,7 @@ impl AbstractTree for MapIndex { Err(RuntimeError::ValidationFailure( ValidationError::CannotIndexWith { collection_type: collection.r#type(), - collection_position: todo!(), + collection_position: self.left.position, index_type: self.right.node.expected_type(_context)?, index_position: self.right.position, }, diff --git a/src/abstract_tree/math.rs b/src/abstract_tree/math.rs index f63ff2e..6725b14 100644 --- a/src/abstract_tree/math.rs +++ b/src/abstract_tree/math.rs @@ -5,7 +5,7 @@ use crate::{ Value, }; -use super::{AbstractTree, Action, Expression, Type, WithPosition}; +use super::{AbstractTree, Action, Expression, SourcePosition, Type, WithPosition}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum Math { @@ -37,71 +37,218 @@ impl AbstractTree for Math { let left_type = left.node.expected_type(context)?; let right_type = right.node.expected_type(context)?; - match (left_type, right_type) { - (Type::Integer, Type::Integer) - | (Type::Float, Type::Float) - | (Type::Integer, Type::Float) - | (Type::Float, Type::Integer) => Ok(()), - _ => Err(ValidationError::ExpectedIntegerOrFloat), + if let Type::Integer | Type::Float = left_type { + if let Type::Integer | Type::Float = right_type { + Ok(()) + } else { + Err(ValidationError::ExpectedIntegerOrFloat(right.position)) + } + } else { + Err(ValidationError::ExpectedIntegerOrFloat(left.position)) } } } } fn run(self, _context: &Context) -> Result { - let value = match self { - Math::Add(left, right) => { - let left_value = left.node.run(_context)?.as_return_value()?; - let right_value = right.node.run(_context)?.as_return_value()?; - - left_value.add(&right_value)? - } - Math::Subtract(left, right) => { - let left_value = left.node.run(_context)?.as_return_value()?; - let right_value = right.node.run(_context)?.as_return_value()?; - - left_value.subtract(&right_value)? - } - Math::Multiply(left, right) => { - let left_value = left.node.run(_context)?.as_return_value()?; - let right_value = right.node.run(_context)?.as_return_value()?; - - if let (ValueInner::Integer(left), ValueInner::Integer(right)) = - (left_value.inner().as_ref(), right_value.inner().as_ref()) - { - Value::integer(left * right) + let run_and_expect_value = + |expression: Expression, position: SourcePosition| -> Result { + let action = expression.run(_context)?; + let value = if let Action::Return(value) = action { + value } else { return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat, + ValidationError::InterpreterExpectedReturn(position), )); + }; + + Ok(value) + }; + + 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)?; + + match (left_value.inner().as_ref(), right_value.inner().as_ref()) { + (ValueInner::Integer(left), ValueInner::Integer(right)) => { + let sum = left.saturating_add(*right); + + Value::integer(sum) + } + (ValueInner::Float(left), ValueInner::Float(right)) => { + let sum = left + right; + + Value::float(sum) + } + (ValueInner::Float(left), ValueInner::Integer(right)) => { + let sum = left + *right as f64; + + Value::float(sum) + } + (ValueInner::Integer(left), ValueInner::Float(right)) => { + let sum = *left as f64 + right; + + Value::float(sum) + } + (ValueInner::Integer(_) | ValueInner::Float(_), _) => { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedIntegerOrFloat(right.position), + )) + } + _ => { + return Err(RuntimeError::ValidationFailure( + 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)?; + + match (left_value.inner().as_ref(), right_value.inner().as_ref()) { + (ValueInner::Integer(left), ValueInner::Integer(right)) => { + let difference = left.saturating_sub(*right); + + Value::integer(difference) + } + (ValueInner::Float(left), ValueInner::Float(right)) => { + let difference = left - right; + + Value::float(difference) + } + (ValueInner::Float(left), ValueInner::Integer(right)) => { + let difference = left - *right as f64; + + Value::float(difference) + } + (ValueInner::Integer(left), ValueInner::Float(right)) => { + let difference = *left as f64 - right; + + Value::float(difference) + } + (ValueInner::Integer(_) | ValueInner::Float(_), _) => { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedIntegerOrFloat(right.position), + )) + } + _ => { + return Err(RuntimeError::ValidationFailure( + 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)?; + + match (left_value.inner().as_ref(), right_value.inner().as_ref()) { + (ValueInner::Integer(left), ValueInner::Integer(right)) => { + let product = left.saturating_mul(*right); + + Value::integer(product) + } + (ValueInner::Float(left), ValueInner::Float(right)) => { + let product = left * right; + + Value::float(product) + } + (ValueInner::Float(left), ValueInner::Integer(right)) => { + let product = left * *right as f64; + + Value::float(product) + } + (ValueInner::Integer(left), ValueInner::Float(right)) => { + let product = *left as f64 * right; + + Value::float(product) + } + (ValueInner::Integer(_) | ValueInner::Float(_), _) => { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedIntegerOrFloat(right.position).into(), + )) + } + _ => { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedIntegerOrFloat(left.position), + )) + } } } Math::Divide(left, right) => { - let left_value = left.node.run(_context)?.as_return_value()?; - let right_value = right.node.run(_context)?.as_return_value()?; + let left_value = run_and_expect_value(left.node, left.position)?; + let right_value = run_and_expect_value(right.node, right.position)?; - if let (ValueInner::Integer(left), ValueInner::Integer(right)) = - (left_value.inner().as_ref(), right_value.inner().as_ref()) - { - Value::integer(left / right) - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat, - )); + match (left_value.inner().as_ref(), right_value.inner().as_ref()) { + (ValueInner::Integer(left), ValueInner::Integer(right)) => { + let quotient = left.saturating_div(*right); + + Value::integer(quotient) + } + (ValueInner::Float(left), ValueInner::Float(right)) => { + let quotient = left / right; + + Value::float(quotient) + } + (ValueInner::Float(left), ValueInner::Integer(right)) => { + let quotient = left / *right as f64; + + Value::float(quotient) + } + (ValueInner::Integer(left), ValueInner::Float(right)) => { + let quotient = *left as f64 / right; + + Value::float(quotient) + } + (ValueInner::Integer(_) | ValueInner::Float(_), _) => { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedIntegerOrFloat(right.position).into(), + )) + } + _ => { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedIntegerOrFloat(left.position), + )) + } } } Math::Modulo(left, right) => { - let left_value = left.node.run(_context)?.as_return_value()?; - let right_value = right.node.run(_context)?.as_return_value()?; + let left_value = run_and_expect_value(left.node, left.position)?; + let right_value = run_and_expect_value(right.node, right.position)?; - if let (ValueInner::Integer(left), ValueInner::Integer(right)) = - (left_value.inner().as_ref(), right_value.inner().as_ref()) - { - Value::integer(left % right) - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat, - )); + match (left_value.inner().as_ref(), right_value.inner().as_ref()) { + (ValueInner::Integer(left), ValueInner::Integer(right)) => { + let remainder = left % right; + + Value::integer(remainder) + } + (ValueInner::Float(left), ValueInner::Float(right)) => { + let remainder = left % right; + + Value::float(remainder) + } + (ValueInner::Float(left), ValueInner::Integer(right)) => { + let remainder = left % *right as f64; + + Value::float(remainder) + } + (ValueInner::Integer(left), ValueInner::Float(right)) => { + let remainder = *left as f64 % right; + + Value::float(remainder) + } + (ValueInner::Integer(_) | ValueInner::Float(_), _) => { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedIntegerOrFloat(right.position).into(), + )) + } + _ => { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedIntegerOrFloat(left.position), + )) + } } } }; diff --git a/src/abstract_tree/value_node.rs b/src/abstract_tree/value_node.rs index 1a596d5..9e5b3b3 100644 --- a/src/abstract_tree/value_node.rs +++ b/src/abstract_tree/value_node.rs @@ -121,7 +121,14 @@ impl AbstractTree for ValueNode { let mut value_list = Vec::with_capacity(expression_list.len()); for expression in expression_list { - let value = expression.node.run(_context)?.as_return_value()?; + let action = expression.node.run(_context)?; + let value = if let Action::Return(value) = action { + value + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::InterpreterExpectedReturn(expression.position), + )); + }; value_list.push(value); } @@ -132,7 +139,14 @@ impl AbstractTree for ValueNode { let mut property_map = BTreeMap::new(); for (identifier, _type, expression) in property_list { - let value = expression.node.run(_context)?.as_return_value()?; + let action = expression.node.run(_context)?; + let value = if let Action::Return(value) = action { + value + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::InterpreterExpectedReturn(expression.position), + )); + }; property_map.insert(identifier, value); } diff --git a/src/abstract_tree/while.rs b/src/abstract_tree/while.rs index f64d341..14dbc09 100644 --- a/src/abstract_tree/while.rs +++ b/src/abstract_tree/while.rs @@ -42,9 +42,15 @@ impl AbstractTree for While { fn run(self, _context: &Context) -> Result { let get_boolean = || -> Result { - let value = self.expression.node.run(_context)?.as_return_value()?; + let action = self.expression.node.run(_context)?; - Ok(value) + if let Action::Return(value) = action { + Ok(value) + } else { + Err(RuntimeError::ValidationFailure( + ValidationError::InterpreterExpectedReturn(self.expression.position), + )) + } }; if let ValueInner::Boolean(boolean) = get_boolean()?.inner().as_ref() { @@ -77,7 +83,7 @@ mod tests { fn simple_while_loop() { let action = Statement::Block(Block::new(vec![ Statement::Assignment(Assignment::new( - Identifier::new("i"), + Identifier::new("i").with_position((0, 0)), None, AssignmentOperator::Assign, Statement::Expression(Expression::Value(ValueNode::Integer(3))) @@ -91,7 +97,7 @@ mod tests { ))) .with_position((0, 0)), statements: vec![Statement::Assignment(Assignment::new( - Identifier::new("i"), + Identifier::new("i").with_position((0, 0)), None, AssignmentOperator::AddAssign, Statement::Expression(Expression::Value(ValueNode::Integer(1))) diff --git a/src/error.rs b/src/error.rs index c0935eb..15ef81f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -96,6 +96,7 @@ impl Error { }; let type_color = Color::Green; + let identifier_color = Color::Blue; if let Some(validation_error) = validation_error { match validation_error { @@ -133,16 +134,10 @@ impl Error { .with_message(format!("Got type {} here.", actual.fg(type_color))), ]); } - ValidationError::VariableNotFound { - identifier, - position, - } => { - builder.add_label( - Label::new(("input", position.0..position.1)) - .with_message(format!("The variable {identifier} does not exist.")) - .with_priority(1), - ); - } + ValidationError::VariableNotFound(identifier) => builder.set_message(format!( + "{} does not exist in this context.", + identifier.fg(identifier_color) + )), ValidationError::CannotIndex { r#type, position } => builder.add_label( Label::new(("input", position.0..position.1)) .with_message(format!("Cannot index into a {}.", r#type.fg(type_color))), @@ -270,11 +265,7 @@ pub enum ValidationError { /// The position of the item that gave the "expected" type. expected_position: SourcePosition, }, - VariableNotFound { - identifier: Identifier, - position: SourcePosition, - }, - + VariableNotFound(Identifier), PropertyNotFound { identifier: Identifier, position: SourcePosition, diff --git a/src/main.rs b/src/main.rs index c734fb9..968413f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,12 @@ //! Command line interface for the dust programming language. -use ariadne::{sources, Color, Label, Report, ReportKind, Source}; -use chumsky::span::SimpleSpan; +use ariadne::sources; use clap::Parser; use colored::Colorize; -use std::{fs::read_to_string, io::Write, ops::Range}; +use std::{fs::read_to_string, io::Write}; -use dust_lang::{context::Context, error::Error, Interpreter}; +use dust_lang::{context::Context, Interpreter}; /// Command-line arguments to be parsed. #[derive(Parser, Debug)] @@ -55,58 +54,8 @@ fn main() { } Err(errors) => { for error in errors { - let mut report_builder = match &error { - Error::Parse { expected, span } => { - let message = if expected.is_empty() { - "Invalid token.".to_string() - } else { - format!("Expected {expected}.") - }; - - Report::build( - ReportKind::Custom("Parsing Error", Color::White), - "input", - span.1, - ) - .with_label( - Label::new(("input", span.0..span.1)) - .with_message(message) - .with_color(Color::Red), - ) - } - Error::Lex { expected, span } => { - let message = if expected.is_empty() { - "Invalid token.".to_string() - } else { - format!("Expected {expected}.") - }; - - Report::build( - ReportKind::Custom("Dust Error", Color::White), - "input", - span.1, - ) - .with_label( - Label::new(("input", span.0..span.1)) - .with_message(message) - .with_color(Color::Red), - ) - } - Error::Runtime { error, position } => Report::build( - ReportKind::Custom("Dust Error", Color::White), - "input", - position.1, - ), - Error::Validation { error, position } => Report::build( - ReportKind::Custom("Dust Error", Color::White), - "input", - position.1, - ), - }; - - report_builder = error.build_report(report_builder); - - report_builder + error + .build_report() .finish() .eprint(sources([("input", &source)])) .unwrap() diff --git a/src/parser.rs b/src/parser.rs index 66ef5c3..3f3f842 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -491,7 +491,7 @@ mod tests { assert_eq!( parse(&lex("foobar : bool = true").unwrap()).unwrap()[0].node, Statement::Assignment(Assignment::new( - Identifier::new("foobar"), + Identifier::new("foobar").with_position((0, 6)), Some(Type::Boolean.with_position((9, 14))), AssignmentOperator::Assign, Statement::Expression(Expression::Value(ValueNode::Boolean(true))) @@ -505,7 +505,7 @@ mod tests { assert_eq!( parse(&lex("foobar: list = []").unwrap()).unwrap()[0].node, Statement::Assignment(Assignment::new( - Identifier::new("foobar"), + Identifier::new("foobar").with_position((0, 6)), Some(Type::List.with_position((8, 13))), AssignmentOperator::Assign, Statement::Expression(Expression::Value(ValueNode::List(vec![]))) @@ -519,7 +519,7 @@ mod tests { assert_eq!( parse(&lex("foobar : list(bool) = [true]").unwrap()).unwrap()[0].node, Statement::Assignment(Assignment::new( - Identifier::new("foobar"), + Identifier::new("foobar").with_position((0, 6)), Some(Type::ListOf(Box::new(Type::Boolean)).with_position((9, 20))), AssignmentOperator::Assign, Statement::Expression(Expression::Value(ValueNode::List(vec![Expression::Value( @@ -536,7 +536,7 @@ mod tests { assert_eq!( parse(&lex("foobar : [bool, str] = [true, '42']").unwrap()).unwrap()[0], Statement::Assignment(Assignment::new( - Identifier::new("foobar"), + Identifier::new("foobar").with_position((0, 6)), Some(Type::ListExact(vec![Type::Boolean, Type::String]).with_position((9, 21))), AssignmentOperator::Assign, Statement::Expression(Expression::Value(ValueNode::List(vec![ @@ -554,7 +554,7 @@ mod tests { assert_eq!( parse(&lex("foobar : () -> any = some_function").unwrap()).unwrap()[0].node, Statement::Assignment(Assignment::new( - Identifier::new("foobar"), + Identifier::new("foobar").with_position((0, 6)), Some( Type::Function { parameter_types: vec![], @@ -709,7 +709,7 @@ mod tests { .with_position((10, 15)), Block::new(vec![Statement::Break.with_position((18, 24))]), Some(Block::new(vec![Statement::Assignment(Assignment::new( - Identifier::new("i"), + Identifier::new("i").with_position((33, 34)), None, AssignmentOperator::AddAssign, Statement::Expression(Expression::Value(ValueNode::Integer(1))) @@ -799,7 +799,7 @@ mod tests { assert_eq!( parse(&lex("foobar = 1").unwrap()).unwrap()[0].node, Statement::Assignment(Assignment::new( - Identifier::new("foobar"), + Identifier::new("foobar").with_position((0, 6)), None, AssignmentOperator::Assign, Statement::Expression(Expression::Value(ValueNode::Integer(1))) @@ -813,7 +813,7 @@ mod tests { assert_eq!( parse(&lex("foobar: int = 1").unwrap()).unwrap()[0].node, Statement::Assignment(Assignment::new( - Identifier::new("foobar"), + Identifier::new("foobar").with_position((0, 6)), Some(Type::Integer.with_position((8, 12))), AssignmentOperator::Assign, Statement::Expression(Expression::Value(ValueNode::Integer(1))) diff --git a/src/value.rs b/src/value.rs index fd012d1..98cfbee 100644 --- a/src/value.rs +++ b/src/value.rs @@ -16,7 +16,7 @@ use stanza::{ use crate::{ abstract_tree::{AbstractTree, Action, Block, Identifier, Type, WithPosition}, context::Context, - error::{RuntimeError, ValidationError}, + error::RuntimeError, }; #[derive(Clone, Debug, PartialEq)] @@ -127,58 +127,6 @@ impl Value { None } } - - pub fn add(&self, other: &Self) -> Result { - match (self.inner().as_ref(), other.inner().as_ref()) { - (ValueInner::Integer(left), ValueInner::Integer(right)) => { - let sum = left.saturating_add(*right); - - Ok(Value::integer(sum)) - } - (ValueInner::Float(left), ValueInner::Float(right)) => { - let sum = left + right; - - Ok(Value::float(sum)) - } - (ValueInner::Float(left), ValueInner::Integer(right)) => { - let sum = left + *right as f64; - - Ok(Value::float(sum)) - } - (ValueInner::Integer(left), ValueInner::Float(right)) => { - let sum = *left as f64 + right; - - Ok(Value::float(sum)) - } - _ => Err(ValidationError::ExpectedIntegerOrFloat), - } - } - - pub fn subtract(&self, other: &Self) -> Result { - match (self.inner().as_ref(), other.inner().as_ref()) { - (ValueInner::Integer(left), ValueInner::Integer(right)) => { - let sum = left.saturating_sub(*right); - - Ok(Value::integer(sum)) - } - (ValueInner::Float(left), ValueInner::Float(right)) => { - let sum = left - right; - - Ok(Value::float(sum)) - } - (ValueInner::Float(left), ValueInner::Integer(right)) => { - let sum = left - *right as f64; - - Ok(Value::float(sum)) - } - (ValueInner::Integer(left), ValueInner::Float(right)) => { - let sum = *left as f64 - right; - - Ok(Value::float(sum)) - } - _ => Err(ValidationError::ExpectedIntegerOrFloat), - } - } } impl Display for Value {