diff --git a/src/abstract_tree/assignment.rs b/src/abstract_tree/assignment.rs index 163f1d6..d32e879 100644 --- a/src/abstract_tree/assignment.rs +++ b/src/abstract_tree/assignment.rs @@ -2,8 +2,8 @@ use serde::{Deserialize, Serialize}; use crate::{ error::{RuntimeError, SyntaxError, ValidationError}, - AbstractTree, AssignmentOperator, Error, Format, Identifier, Map, Statement, SyntaxNode, - SyntaxPosition, Type, TypeSpecification, Value, + AbstractTree, AssignmentOperator, Error, Format, Identifier, Map, SourcePosition, Statement, + SyntaxNode, Type, TypeSpecification, Value, }; /// Variable assignment, including add-assign and subtract-assign operations. @@ -14,7 +14,7 @@ pub struct Assignment { operator: AssignmentOperator, statement: Statement, - syntax_position: SyntaxPosition, + syntax_position: SourcePosition, } impl AbstractTree for Assignment { @@ -43,15 +43,15 @@ impl AbstractTree for Assignment { let statement_node = syntax_node.child(child_count - 1).unwrap(); let statement = Statement::from_syntax(statement_node, source, context)?; - if let AssignmentOperator::Equal = operator { - let r#type = if let Some(definition) = &type_specification { - definition.inner().clone() - } else { - statement.expected_type(context)? - }; + // if let AssignmentOperator::Equal = operator { + // let r#type = if let Some(definition) = &type_specification { + // definition.inner().clone() + // } else { + // statement.expected_type(context)? + // }; - context.set_type(identifier.inner().clone(), r#type)?; - } + // context.set_type(identifier.inner().clone(), r#type)?; + // } Ok(Assignment { identifier, @@ -63,28 +63,42 @@ impl AbstractTree for Assignment { } fn check_type(&self, source: &str, context: &Map) -> Result<(), ValidationError> { - let actual_type = self.statement.expected_type(context)?; - if let Some(type_specification) = &self.type_specification { match self.operator { AssignmentOperator::Equal => { - type_specification - .inner() - .check(&actual_type) - .map_err(|error| error.at_source_position(source, self.syntax_position))?; + let expected = type_specification.inner(); + let actual = self.statement.expected_type(context)?; + + if !expected.accepts(&actual) { + return Err(ValidationError::TypeCheck { + expected: expected.clone(), + actual, + position: self.syntax_position, + }); + } } AssignmentOperator::PlusEqual => { - if let Type::List(item_type) = type_specification.inner() { - item_type.check(&actual_type).map_err(|error| { - error.at_source_position(source, self.syntax_position) - })?; + if let Type::List(expected) = type_specification.inner() { + let actual = self.identifier.expected_type(context)?; + + if !expected.accepts(&actual) { + return Err(ValidationError::TypeCheck { + expected: expected.as_ref().clone(), + actual, + position: self.syntax_position, + }); + } } else { - type_specification - .inner() - .check(&self.identifier.expected_type(context)?) - .map_err(|error| { - error.at_source_position(source, self.syntax_position) - })?; + let expected = type_specification.inner(); + let actual = self.identifier.expected_type(context)?; + + if !expected.accepts(&actual) { + return Err(ValidationError::TypeCheck { + expected: expected.clone(), + actual, + position: self.syntax_position, + }); + } } } AssignmentOperator::MinusEqual => todo!(), @@ -93,10 +107,16 @@ impl AbstractTree for Assignment { match self.operator { AssignmentOperator::Equal => {} AssignmentOperator::PlusEqual => { - if let Type::List(item_type) = self.identifier.expected_type(context)? { - item_type.check(&actual_type).map_err(|error| { - error.at_source_position(source, self.syntax_position) - })?; + if let Type::List(expected) = self.identifier.expected_type(context)? { + let actual = self.statement.expected_type(context)?; + + if !expected.accepts(&actual) { + return Err(ValidationError::TypeCheck { + expected: expected.as_ref().clone(), + actual, + position: self.syntax_position, + }); + } } } AssignmentOperator::MinusEqual => todo!(), @@ -118,9 +138,7 @@ impl AbstractTree for Assignment { previous_value += value; previous_value } else { - return Err(Error::Runtime(RuntimeError::VariableIdentifierNotFound( - key.clone(), - ))); + return Err(RuntimeError::VariableIdentifierNotFound(key.clone())); } } AssignmentOperator::MinusEqual => { @@ -128,9 +146,7 @@ impl AbstractTree for Assignment { previous_value -= value; previous_value } else { - return Err(Error::Runtime(RuntimeError::VariableIdentifierNotFound( - key.clone(), - ))); + return Err(RuntimeError::VariableIdentifierNotFound(key.clone())); } } AssignmentOperator::Equal => value, diff --git a/src/abstract_tree/assignment_operator.rs b/src/abstract_tree/assignment_operator.rs index 21cb351..0fa4e30 100644 --- a/src/abstract_tree/assignment_operator.rs +++ b/src/abstract_tree/assignment_operator.rs @@ -27,7 +27,7 @@ impl AbstractTree for AssignmentOperator { "+=" => AssignmentOperator::PlusEqual, "-=" => AssignmentOperator::MinusEqual, _ => { - return Err(Error::UnexpectedSyntaxNode { + return Err(SyntaxError::UnexpectedSyntaxNode { expected: "=, += or -=".to_string(), actual: operator_node.kind().to_string(), location: operator_node.start_position(), diff --git a/src/abstract_tree/block.rs b/src/abstract_tree/block.rs index b1d95fb..1d19cc9 100644 --- a/src/abstract_tree/block.rs +++ b/src/abstract_tree/block.rs @@ -4,7 +4,7 @@ use rayon::prelude::*; use serde::{Deserialize, Serialize}; use crate::{ - error::{RuntimeError, SyntaxError, ValidationError}, + error::{rw_lock_error::RwLockError, RuntimeError, SyntaxError, ValidationError}, AbstractTree, Error, Format, Map, Statement, SyntaxNode, Type, Value, }; @@ -91,13 +91,13 @@ impl AbstractTree for Block { *final_result = result; None } - Err(error) => Some(Err(error.into())), + Err(_error) => Some(Err(RuntimeError::RwLock(RwLockError))), } } else { None } }) - .unwrap_or(final_result.into_inner()?) + .unwrap_or(final_result.into_inner().map_err(|_| RwLockError)?) } else { let mut prev_result = None; diff --git a/src/abstract_tree/expression.rs b/src/abstract_tree/expression.rs index c9751d7..3571986 100644 --- a/src/abstract_tree/expression.rs +++ b/src/abstract_tree/expression.rs @@ -50,7 +50,7 @@ impl AbstractTree for Expression { "new" => Expression::New(New::from_syntax(child, source, _context)?), "command" => Expression::Command(Command::from_syntax(child, source, _context)?), _ => { - return Err(Error::UnexpectedSyntaxNode { + return Err(SyntaxError::UnexpectedSyntaxNode { expected: "value, identifier, index, math, logic, function call, new, context or ->" .to_string(), diff --git a/src/abstract_tree/for.rs b/src/abstract_tree/for.rs index 799759a..daad3d3 100644 --- a/src/abstract_tree/for.rs +++ b/src/abstract_tree/for.rs @@ -24,7 +24,7 @@ impl AbstractTree for For { "for" => false, "async for" => true, _ => { - return Err(Error::UnexpectedSyntaxNode { + return Err(SyntaxError::UnexpectedSyntaxNode { expected: "for or async for".to_string(), actual: for_node.kind().to_string(), location: for_node.start_position(), diff --git a/src/abstract_tree/function_call.rs b/src/abstract_tree/function_call.rs index 4fced7f..eb72510 100644 --- a/src/abstract_tree/function_call.rs +++ b/src/abstract_tree/function_call.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use crate::{ error::{RuntimeError, SyntaxError, ValidationError}, - AbstractTree, Error, Expression, Format, FunctionExpression, Map, SyntaxNode, SyntaxPosition, + AbstractTree, Error, Expression, Format, FunctionExpression, Map, SourcePosition, SyntaxNode, Type, Value, }; @@ -11,7 +11,7 @@ use crate::{ pub struct FunctionCall { function_expression: FunctionExpression, arguments: Vec, - syntax_position: SyntaxPosition, + syntax_position: SourcePosition, } impl FunctionCall { @@ -19,7 +19,7 @@ impl FunctionCall { pub fn new( function_expression: FunctionExpression, arguments: Vec, - syntax_position: SyntaxPosition, + syntax_position: SourcePosition, ) -> Self { Self { function_expression, @@ -85,7 +85,7 @@ impl AbstractTree for FunctionCall { } } - fn check_type(&self, source: &str, context: &Map) -> Result<(), ValidationError> { + fn check_type(&self, _source: &str, context: &Map) -> Result<(), ValidationError> { let function_expression_type = self.function_expression.expected_type(context)?; let parameter_types = match function_expression_type { @@ -94,26 +94,32 @@ impl AbstractTree for FunctionCall { } => parameter_types, Type::Any => return Ok(()), _ => { - return Err(Error::TypeCheckExpectedFunction { + return Err(ValidationError::TypeCheckExpectedFunction { actual: function_expression_type, - } - .at_source_position(source, self.syntax_position)) + position: self.syntax_position, + }); } }; if self.arguments.len() != parameter_types.len() { - return Err(Error::ExpectedFunctionArgumentAmount { + return Err(ValidationError::ExpectedFunctionArgumentAmount { expected: parameter_types.len(), actual: self.arguments.len(), - } - .at_source_position(source, self.syntax_position)); + position: self.syntax_position, + }); } for (index, expression) in self.arguments.iter().enumerate() { - if let Some(r#type) = parameter_types.get(index) { - r#type - .check(&expression.expected_type(context)?) - .map_err(|error| error.at_source_position(source, self.syntax_position))?; + if let Some(expected) = parameter_types.get(index) { + let actual = expression.expected_type(context)?; + + if !expected.accepts(&actual) { + return Err(ValidationError::TypeCheck { + expected: expected.clone(), + actual, + position: self.syntax_position, + }); + } } } @@ -129,7 +135,7 @@ impl AbstractTree for FunctionCall { if let Some((value, _)) = variables.get(key) { value.clone() } else { - return Err(Error::VariableIdentifierNotFound( + return Err(RuntimeError::VariableIdentifierNotFound( identifier.inner().clone(), )); } diff --git a/src/abstract_tree/function_expression.rs b/src/abstract_tree/function_expression.rs index 5590cf8..c957751 100644 --- a/src/abstract_tree/function_expression.rs +++ b/src/abstract_tree/function_expression.rs @@ -40,7 +40,7 @@ impl AbstractTree for FunctionExpression { FunctionExpression::Yield(Box::new(Yield::from_syntax(child, source, context)?)) } _ => { - return Err(Error::UnexpectedSyntaxNode { + return Err(SyntaxError::UnexpectedSyntaxNode { expected: "identifier, function call, value, index or yield".to_string(), actual: child.kind().to_string(), location: child.start_position(), diff --git a/src/abstract_tree/function_node.rs b/src/abstract_tree/function_node.rs index 367a525..66d8d92 100644 --- a/src/abstract_tree/function_node.rs +++ b/src/abstract_tree/function_node.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use crate::{ error::{RuntimeError, SyntaxError, ValidationError}, - AbstractTree, Block, Error, Format, Function, Identifier, Map, SyntaxNode, SyntaxPosition, + AbstractTree, Block, Error, Format, Function, Identifier, Map, SourcePosition, SyntaxNode, Type, TypeSpecification, Value, }; @@ -13,7 +13,7 @@ pub struct FunctionNode { parameters: Vec, body: Block, r#type: Type, - syntax_position: SyntaxPosition, + syntax_position: SourcePosition, } impl FunctionNode { @@ -21,7 +21,7 @@ impl FunctionNode { parameters: Vec, body: Block, r#type: Type, - syntax_position: SyntaxPosition, + syntax_position: SourcePosition, ) -> Self { FunctionNode { parameters, @@ -43,7 +43,7 @@ impl FunctionNode { &self.r#type } - pub fn syntax_position(&self) -> &SyntaxPosition { + pub fn syntax_position(&self) -> &SourcePosition { &self.syntax_position } @@ -164,15 +164,23 @@ impl AbstractTree for FunctionNode { function_context.set_type(parameter.inner().clone(), parameter_type.clone())?; } - return_type - .check(&self.body.expected_type(&function_context)?) - .map_err(|error| error.at_source_position(source, self.syntax_position))?; + let actual = self.body.expected_type(&function_context)?; + + if !return_type.accepts(&actual) { + return Err(ValidationError::TypeCheck { + expected: return_type.as_ref().clone(), + actual, + position: self.syntax_position, + }); + } + self.body.check_type(source, &function_context)?; Ok(()) } else { - Err(Error::TypeCheckExpectedFunction { + Err(ValidationError::TypeCheckExpectedFunction { actual: self.r#type.clone(), + position: self.syntax_position, }) } } diff --git a/src/abstract_tree/identifier.rs b/src/abstract_tree/identifier.rs index 3861c82..229606e 100644 --- a/src/abstract_tree/identifier.rs +++ b/src/abstract_tree/identifier.rs @@ -47,7 +47,7 @@ impl AbstractTree for Identifier { if let Some((_value, r#type)) = context.variables()?.get(&self.0) { Ok(r#type.clone()) } else { - Err(Error::VariableIdentifierNotFound(self.0.clone())) + Err(ValidationError::VariableIdentifierNotFound(self.clone())) } } @@ -55,7 +55,7 @@ impl AbstractTree for Identifier { if let Some((value, _)) = context.variables()?.get(&self.0) { Ok(value.clone()) } else { - Err(Error::VariableIdentifierNotFound(self.0.clone())) + Err(RuntimeError::VariableIdentifierNotFound(self.0.clone())) } } } diff --git a/src/abstract_tree/if_else.rs b/src/abstract_tree/if_else.rs index 29bb860..4c991f3 100644 --- a/src/abstract_tree/if_else.rs +++ b/src/abstract_tree/if_else.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use crate::{ error::{RuntimeError, SyntaxError, ValidationError}, - AbstractTree, Block, Expression, Format, Map, SyntaxNode, Type, Value, + AbstractTree, Block, Expression, Format, Map, SourcePosition, SyntaxNode, Type, Value, }; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] @@ -12,6 +12,7 @@ pub struct IfElse { else_if_expressions: Vec, else_if_blocks: Vec, else_block: Option, + source_position: SourcePosition, } impl AbstractTree for IfElse { @@ -54,6 +55,7 @@ impl AbstractTree for IfElse { else_if_expressions, else_if_blocks, else_block, + source_position: SourcePosition::from(node.range()), }) } @@ -65,7 +67,7 @@ impl AbstractTree for IfElse { self.if_expression.check_type(_source, context)?; self.if_block.check_type(_source, context)?; - let expected_type = self.if_block.expected_type(context)?; + let expected = self.if_block.expected_type(context)?; let else_ifs = self .else_if_expressions .iter() @@ -75,11 +77,27 @@ impl AbstractTree for IfElse { expression.check_type(_source, context)?; block.check_type(_source, context)?; - expected_type.check(&block.expected_type(context)?)?; + let actual = block.expected_type(context)?; + + if !expected.accepts(&actual) { + return Err(ValidationError::TypeCheck { + expected, + actual, + position: self.source_position, + }); + } } - if let Some(expression) = self.else_block { - expected_type.check(&expression.expected_type(context)?)?; + if let Some(block) = &self.else_block { + let actual = block.expected_type(context)?; + + if !expected.accepts(&actual) { + return Err(ValidationError::TypeCheck { + expected, + actual, + position: self.source_position, + }); + } } Ok(()) diff --git a/src/abstract_tree/index.rs b/src/abstract_tree/index.rs index f71186c..cab03d2 100644 --- a/src/abstract_tree/index.rs +++ b/src/abstract_tree/index.rs @@ -2,7 +2,8 @@ use serde::{Deserialize, Serialize}; use crate::{ error::{RuntimeError, SyntaxError, ValidationError}, - AbstractTree, Error, Format, IndexExpression, List, Map, SyntaxNode, Type, Value, + AbstractTree, Error, Format, IndexExpression, List, Map, SourcePosition, SyntaxNode, Type, + Value, }; /// Abstract representation of an index expression. @@ -13,6 +14,7 @@ pub struct Index { pub collection: IndexExpression, pub index: IndexExpression, pub index_end: Option, + source_position: SourcePosition, } impl AbstractTree for Index { @@ -40,6 +42,7 @@ impl AbstractTree for Index { collection, index, index_end, + source_position: SourcePosition::from(node.range()), }) } @@ -56,7 +59,7 @@ impl AbstractTree for Index { self.collection.check_type(_source, _context)?; self.index.check_type(_source, _context)?; - if let Some(index_end) = self.index_end { + if let Some(index_end) = &self.index_end { index_end.check_type(_source, _context)?; } @@ -64,9 +67,9 @@ impl AbstractTree for Index { } fn run(&self, source: &str, context: &Map) -> Result { - let collection = self.collection.run(source, context)?; + let value = self.collection.run(source, context)?; - match collection { + match value { Value::List(list) => { let index = self.index.run(source, context)?.as_integer()? as usize; @@ -104,7 +107,7 @@ impl AbstractTree for Index { }; if value.is_none() { - Err(Error::VariableIdentifierNotFound(key)) + Err(RuntimeError::VariableIdentifierNotFound(key)) } else { Ok(value) } @@ -115,7 +118,7 @@ impl AbstractTree for Index { Ok(Value::string(item.to_string())) } - _ => Err(Error::ExpectedCollection { actual: collection }), + _ => Err(RuntimeError::ExpectedCollection { actual: value }), } } } diff --git a/src/abstract_tree/index_assignment.rs b/src/abstract_tree/index_assignment.rs index defcb18..b538806 100644 --- a/src/abstract_tree/index_assignment.rs +++ b/src/abstract_tree/index_assignment.rs @@ -48,7 +48,7 @@ impl AbstractTree for IndexAssignment { let index_key = if let IndexExpression::Identifier(identifier) = &self.index.index { identifier.inner() } else { - return Err(Error::VariableIdentifierNotFound( + return Err(RuntimeError::VariableIdentifierNotFound( self.index.index.run(source, context)?.to_string(), )); }; diff --git a/src/abstract_tree/index_expression.rs b/src/abstract_tree/index_expression.rs index bc988bb..11630e0 100644 --- a/src/abstract_tree/index_expression.rs +++ b/src/abstract_tree/index_expression.rs @@ -37,7 +37,7 @@ impl AbstractTree for IndexExpression { child, source, context, )?)), _ => { - return Err(Error::UnexpectedSyntaxNode { + return Err(SyntaxError::UnexpectedSyntaxNode { expected: "value, identifier, index or function call".to_string(), actual: child.kind().to_string(), location: child.start_position(), diff --git a/src/abstract_tree/logic_operator.rs b/src/abstract_tree/logic_operator.rs index c31fb26..58971e3 100644 --- a/src/abstract_tree/logic_operator.rs +++ b/src/abstract_tree/logic_operator.rs @@ -32,7 +32,7 @@ impl AbstractTree for LogicOperator { ">=" => LogicOperator::GreaterOrEqual, "<=" => LogicOperator::LessOrEqual, _ => { - return Err(Error::UnexpectedSyntaxNode { + return Err(SyntaxError::UnexpectedSyntaxNode { expected: "==, !=, &&, ||, >, <, >= or <=".to_string(), actual: operator_node.kind().to_string(), location: operator_node.start_position(), diff --git a/src/abstract_tree/match.rs b/src/abstract_tree/match.rs index 0ad5767..8c1d3e4 100644 --- a/src/abstract_tree/match.rs +++ b/src/abstract_tree/match.rs @@ -68,12 +68,12 @@ impl AbstractTree for Match { fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { self.matcher.check_type(_source, _context)?; - for (expression, statement) in self.options { + for (expression, statement) in &self.options { expression.check_type(_source, _context)?; statement.check_type(_source, _context)?; } - if let Some(statement) = self.fallback { + if let Some(statement) = &self.fallback { statement.check_type(_source, _context)?; } diff --git a/src/abstract_tree/math_operator.rs b/src/abstract_tree/math_operator.rs index 497f7d0..3a65036 100644 --- a/src/abstract_tree/math_operator.rs +++ b/src/abstract_tree/math_operator.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use crate::{ error::{RuntimeError, SyntaxError, ValidationError}, - AbstractTree, Error, Format, Map, SyntaxNode, Type, Value, + AbstractTree, Format, Map, SyntaxNode, Type, Value, }; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] @@ -24,7 +24,7 @@ impl AbstractTree for MathOperator { "/" => MathOperator::Divide, "%" => MathOperator::Modulo, _ => { - return Err(Error::UnexpectedSyntaxNode { + return Err(SyntaxError::UnexpectedSyntaxNode { expected: "+, -, *, / or %".to_string(), actual: operator_node.kind().to_string(), location: operator_node.start_position(), diff --git a/src/abstract_tree/mod.rs b/src/abstract_tree/mod.rs index 95f46b0..42cef9d 100644 --- a/src/abstract_tree/mod.rs +++ b/src/abstract_tree/mod.rs @@ -50,7 +50,7 @@ use crate::{ }; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct SyntaxPosition { +pub struct SourcePosition { pub start_byte: usize, pub end_byte: usize, pub start_row: usize, @@ -59,9 +59,9 @@ pub struct SyntaxPosition { pub end_column: usize, } -impl From for SyntaxPosition { +impl From for SourcePosition { fn from(range: tree_sitter::Range) -> Self { - SyntaxPosition { + SourcePosition { start_byte: range.start_byte, end_byte: range.end_byte, start_row: range.start_point.row + 1, @@ -143,7 +143,8 @@ impl Format for Root { /// This trait is implemented by the Evaluator's internal types to form an /// executable tree that resolves to a single value. pub trait AbstractTree: Sized + Format { - /// Interpret the syntax tree at the given node and return the abstraction. + /// Interpret the syntax tree at the given node and return the abstraction. Returns a syntax + /// error if the source is invalid. /// /// This function is used to convert nodes in the Tree Sitter concrete /// syntax tree into executable nodes in an abstract tree. This function is @@ -154,13 +155,16 @@ pub trait AbstractTree: Sized + Format { /// node's byte range. fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result; - /// Verify the type integrity of the node. - fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError>; - - /// Execute dust code by traversing the tree. - fn run(&self, source: &str, context: &Map) -> Result; - + /// Return the type of the value that this abstract node will create when run. Returns a + /// validation error if the tree is invalid. fn expected_type(&self, context: &Map) -> Result; + + /// Verify the type integrity of the node. Returns a validation error if the tree is invalid. + fn check_type(&self, source: &str, context: &Map) -> Result<(), ValidationError>; + + /// Execute this node's logic and return a value. Returns a runtime error if the node cannot + /// resolve to a value. + fn run(&self, source: &str, context: &Map) -> Result; } pub trait Format { diff --git a/src/abstract_tree/statement.rs b/src/abstract_tree/statement.rs index db1cc23..8c326f9 100644 --- a/src/abstract_tree/statement.rs +++ b/src/abstract_tree/statement.rs @@ -56,7 +56,7 @@ impl AbstractTree for Statement { Ok(Statement::Return(Box::new(Statement::from_syntax(statement_node, source, context)?))) }, - _ => Err(Error::UnexpectedSyntaxNode { + _ => Err(SyntaxError::UnexpectedSyntaxNode { expected: "assignment, index assignment, expression, block, return, if...else, while, for or match".to_string(), actual: child.kind().to_string(), diff --git a/src/abstract_tree/type.rs b/src/abstract_tree/type.rs index 7aa8b2a..3e5ca93 100644 --- a/src/abstract_tree/type.rs +++ b/src/abstract_tree/type.rs @@ -44,7 +44,11 @@ impl Type { Type::Option(Box::new(optional_type)) } - pub fn check(&self, other: &Type) -> Result<(), ValidationError> { + /// Returns a boolean indicating whether is type is accepting of the other. + /// + /// The types do not need to match exactly. For example, the Any variant matches all of the + /// others and the Number variant accepts Number, Integer and Float. + pub fn accepts(&self, other: &Type) -> bool { log::info!("Checking type {self} against {other}."); match (self, other) { @@ -67,41 +71,20 @@ impl Type { | (Type::Integer, Type::Number) | (Type::Float, Type::Number) | (Type::None, Type::None) - | (Type::String, Type::String) => Ok(()), - (Type::Custom(left), Type::Custom(right)) => { - if left == right { - Ok(()) - } else { - Err(Error::TypeCheck { - expected: self.clone(), - actual: other.clone(), - }) - } - } + | (Type::String, Type::String) => true, + (Type::Custom(left), Type::Custom(right)) => left == right, + (Type::Option(_), Type::None) => true, (Type::Option(left), Type::Option(right)) => { - if left == right { - Ok(()) - } else if let Type::Any = left.as_ref() { - Ok(()) - } else if let Type::Any = right.as_ref() { - Ok(()) + if let Type::Any = left.as_ref() { + true + } else if left == right { + true } else { - Err(Error::TypeCheck { - expected: self.clone(), - actual: other.clone(), - }) + false } } - (Type::Option(_), Type::None) | (Type::None, Type::Option(_)) => Ok(()), (Type::List(self_item_type), Type::List(other_item_type)) => { - if self_item_type.check(other_item_type).is_err() { - Err(Error::TypeCheck { - expected: self.clone(), - actual: other.clone(), - }) - } else { - Ok(()) - } + self_item_type.accepts(&other_item_type) } ( Type::Function { @@ -118,27 +101,14 @@ impl Type { .zip(other_parameter_types.iter()); for (self_parameter_type, other_parameter_type) in parameter_type_pairs { - if self_parameter_type.check(other_parameter_type).is_err() { - return Err(Error::TypeCheck { - expected: self.clone(), - actual: other.clone(), - }); + if self_parameter_type == other_parameter_type { + return false; } } - if self_return_type.check(other_return_type).is_err() { - Err(Error::TypeCheck { - expected: self.clone(), - actual: other.clone(), - }) - } else { - Ok(()) - } + self_return_type == other_return_type } - _ => Err(Error::TypeCheck { - expected: self.clone(), - actual: other.clone(), - }), + _ => false, } } @@ -210,7 +180,7 @@ impl AbstractTree for Type { Type::Option(Box::new(inner_type)) } _ => { - return Err(Error::UnexpectedSyntaxNode { + return Err(SyntaxError::UnexpectedSyntaxNode { expected: "any, bool, float, int, num, str, option, (, [ or {".to_string(), actual: type_node.kind().to_string(), location: type_node.start_position(), diff --git a/src/abstract_tree/value_node.rs b/src/abstract_tree/value_node.rs index 1c1e912..e2fe159 100644 --- a/src/abstract_tree/value_node.rs +++ b/src/abstract_tree/value_node.rs @@ -79,10 +79,6 @@ impl AbstractTree for ValueNode { if child.kind() == "statement" { let statement = Statement::from_syntax(child, source, context)?; - if let Some(type_specification) = ¤t_type { - type_specification.check(&statement.expected_type(context)?)?; - } - child_nodes.insert(current_key.clone(), (statement, current_type.clone())); } } @@ -145,20 +141,20 @@ impl AbstractTree for ValueNode { current_statement = Some(Statement::from_syntax(child_syntax_node, source, context)?); - if let Some(identifier) = ¤t_identifier { - let r#type = if let Some(r#type) = ¤t_type { - r#type.clone() - } else if let Some(statement) = ¤t_statement { - statement.expected_type(context)? - } else { - Type::None - }; + // if let Some(identifier) = ¤t_identifier { + // let r#type = if let Some(r#type) = ¤t_type { + // r#type.clone() + // } else if let Some(statement) = ¤t_statement { + // statement.expected_type(context)? + // } else { + // Type::None + // }; - btree_map.insert( - identifier.inner().clone(), - (current_statement.clone(), r#type.clone()), - ); - } + // btree_map.insert( + // identifier.inner().clone(), + // (current_statement.clone(), r#type.clone()), + // ); + // } } } @@ -172,7 +168,7 @@ impl AbstractTree for ValueNode { ValueNode::Range(start..=end) } _ => { - return Err(Error::UnexpectedSyntaxNode { + return Err(SyntaxError::UnexpectedSyntaxNode { expected: "string, integer, float, boolean, range, list, map, option, function or structure" .to_string(), diff --git a/src/built_in_functions/fs.rs b/src/built_in_functions/fs.rs index ddbb8ac..190d7a2 100644 --- a/src/built_in_functions/fs.rs +++ b/src/built_in_functions/fs.rs @@ -3,7 +3,7 @@ use std::fs::read_to_string; use enum_iterator::{all, Sequence}; use serde::{Deserialize, Serialize}; -use crate::{error::RuntimeError, Error, Map, Type, Value}; +use crate::{error::RuntimeError, Map, Type, Value}; use super::Callable; @@ -43,7 +43,7 @@ impl Callable for Fs { ) -> Result { match self { Fs::ReadFile => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let path = arguments.first().unwrap().as_string()?; let file_content = read_to_string(path.as_str())?; diff --git a/src/built_in_functions/json.rs b/src/built_in_functions/json.rs index ebe1c6a..c0238d3 100644 --- a/src/built_in_functions/json.rs +++ b/src/built_in_functions/json.rs @@ -1,7 +1,7 @@ use enum_iterator::Sequence; use serde::{Deserialize, Serialize}; -use crate::{error::RuntimeError, Error, Map, Type, Value}; +use crate::{error::RuntimeError, Map, Type, Value}; use super::Callable; @@ -49,7 +49,7 @@ impl Callable for Json { ) -> Result { match self { Json::Create => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let value = arguments.first().unwrap(); let json_string = serde_json::to_string(value)?; @@ -57,7 +57,7 @@ impl Callable for Json { Ok(Value::String(json_string)) } Json::CreatePretty => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let value = arguments.first().unwrap(); let json_string = serde_json::to_string_pretty(value)?; @@ -65,7 +65,7 @@ impl Callable for Json { Ok(Value::String(json_string)) } Json::Parse => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let json_string = arguments.first().unwrap().as_string()?; let value = serde_json::from_str(json_string)?; diff --git a/src/built_in_functions/mod.rs b/src/built_in_functions/mod.rs index ef17410..033bc0f 100644 --- a/src/built_in_functions/mod.rs +++ b/src/built_in_functions/mod.rs @@ -7,7 +7,7 @@ use std::fmt::{self, Display, Formatter}; use rand::{random, thread_rng, Rng}; use serde::{Deserialize, Serialize}; -use crate::{error::RuntimeError, Error, Format, Map, Type, Value}; +use crate::{error::RuntimeError, Format, Map, Type, Value}; use self::{fs::Fs, json::Json, str::StrFunction}; @@ -91,7 +91,7 @@ impl Callable for BuiltInFunction { ) -> Result { match self { BuiltInFunction::AssertEqual => { - Error::expect_argument_amount(self.name(), 2, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; let left = arguments.first().unwrap(); let right = arguments.get(1).unwrap(); @@ -105,7 +105,7 @@ impl Callable for BuiltInFunction { json_function.call(arguments, _source, _outer_context) } BuiltInFunction::Length => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let value = arguments.first().unwrap(); let length = if let Ok(list) = value.as_list() { @@ -115,7 +115,7 @@ impl Callable for BuiltInFunction { } else if let Ok(str) = value.as_string() { str.chars().count() } else { - return Err(Error::ExpectedCollection { + return Err(RuntimeError::ExpectedCollection { actual: value.clone(), }); }; @@ -123,7 +123,7 @@ impl Callable for BuiltInFunction { Ok(Value::Integer(length as i64)) } BuiltInFunction::Output => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let value = arguments.first().unwrap(); @@ -132,17 +132,17 @@ impl Callable for BuiltInFunction { Ok(Value::none()) } BuiltInFunction::RandomBoolean => { - Error::expect_argument_amount(self.name(), 0, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 0, arguments.len())?; Ok(Value::Boolean(random())) } BuiltInFunction::RandomFloat => { - Error::expect_argument_amount(self.name(), 0, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 0, arguments.len())?; Ok(Value::Float(random())) } BuiltInFunction::RandomFrom => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let value = arguments.first().unwrap(); @@ -162,7 +162,7 @@ impl Callable for BuiltInFunction { } } BuiltInFunction::RandomInteger => { - Error::expect_argument_amount(self.name(), 0, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 0, arguments.len())?; Ok(Value::Integer(random())) } diff --git a/src/built_in_functions/str.rs b/src/built_in_functions/str.rs index 29f03cb..86a8eb8 100644 --- a/src/built_in_functions/str.rs +++ b/src/built_in_functions/str.rs @@ -1,7 +1,7 @@ use enum_iterator::Sequence; use serde::{Deserialize, Serialize}; -use crate::{error::RuntimeError, Error, List, Map, Type, Value}; +use crate::{error::RuntimeError, List, Map, Type, Value}; use super::Callable; @@ -206,7 +206,7 @@ impl Callable for StrFunction { ) -> Result { let value = match self { StrFunction::AsBytes => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let bytes = string @@ -217,7 +217,7 @@ impl Callable for StrFunction { Value::List(List::with_items(bytes)) } StrFunction::EndsWith => { - Error::expect_argument_amount(self.name(), 2, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let pattern_string = arguments.get(1).unwrap().as_string()?; @@ -226,7 +226,7 @@ impl Callable for StrFunction { Value::Boolean(string.ends_with(pattern)) } StrFunction::Find => { - Error::expect_argument_amount(self.name(), 2, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let pattern_string = arguments.get(1).unwrap().as_string()?; @@ -238,21 +238,21 @@ impl Callable for StrFunction { Value::Option(find) } StrFunction::IsAscii => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let string = arguments.first().unwrap().as_string()?; Value::Boolean(string.is_ascii()) } StrFunction::IsEmpty => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let string = arguments.first().unwrap().as_string()?; Value::Boolean(string.is_empty()) } StrFunction::Insert => { - Error::expect_argument_amount(self.name(), 3, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 3, arguments.len())?; let mut string = arguments.first().unwrap().as_string()?.clone(); let index = arguments.get(1).unwrap().as_integer()? as usize; @@ -263,7 +263,7 @@ impl Callable for StrFunction { Value::String(string) } StrFunction::Lines => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let lines = string @@ -274,7 +274,7 @@ impl Callable for StrFunction { Value::List(List::with_items(lines)) } StrFunction::Matches => { - Error::expect_argument_amount(self.name(), 2, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let pattern_string = arguments.get(1).unwrap().as_string()?; @@ -287,7 +287,7 @@ impl Callable for StrFunction { Value::List(List::with_items(matches)) } StrFunction::Parse => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let string = arguments.first().unwrap().as_string()?; @@ -300,7 +300,7 @@ impl Callable for StrFunction { } } StrFunction::Remove => { - Error::expect_argument_amount(self.name(), 2, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let index = arguments.get(1).unwrap().as_integer()? as usize; @@ -318,7 +318,7 @@ impl Callable for StrFunction { } } StrFunction::ReplaceRange => { - Error::expect_argument_amount(self.name(), 3, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 3, arguments.len())?; let mut string = arguments.first().unwrap().as_string()?.clone(); let range = arguments.get(1).unwrap().as_list()?.items(); @@ -331,7 +331,7 @@ impl Callable for StrFunction { Value::String(string) } StrFunction::Retain => { - Error::expect_argument_amount(self.name(), 2, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; let mut string = arguments.first().unwrap().as_string()?.clone(); let predicate = arguments.get(1).unwrap().as_function()?; @@ -347,7 +347,7 @@ impl Callable for StrFunction { Value::String(string) } StrFunction::Split => { - Error::expect_argument_amount(self.name(), 2, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let pattern_string = arguments.get(1).unwrap().as_string()?; @@ -360,7 +360,7 @@ impl Callable for StrFunction { Value::List(List::with_items(sections)) } StrFunction::SplitAt => { - Error::expect_argument_amount(self.name(), 2, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let index = arguments.get(1).unwrap().as_integer()?; @@ -372,7 +372,7 @@ impl Callable for StrFunction { ])) } StrFunction::SplitInclusive => { - Error::expect_argument_amount(self.name(), 2, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let pattern_string = arguments.get(1).unwrap().as_string()?; @@ -385,7 +385,7 @@ impl Callable for StrFunction { Value::List(List::with_items(sections)) } StrFunction::SplitN => { - Error::expect_argument_amount(self.name(), 3, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 3, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let count = arguments.get(1).unwrap().as_integer()?; @@ -399,7 +399,7 @@ impl Callable for StrFunction { Value::List(List::with_items(sections)) } StrFunction::SplitOnce => { - Error::expect_argument_amount(self.name(), 2, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let pattern_string = arguments.get(1).unwrap().as_string()?; @@ -414,7 +414,7 @@ impl Callable for StrFunction { Value::option(sections) } StrFunction::SplitTerminator => { - Error::expect_argument_amount(self.name(), 2, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let pattern_string = arguments.get(1).unwrap().as_string()?; @@ -427,7 +427,7 @@ impl Callable for StrFunction { Value::List(List::with_items(sections)) } StrFunction::SplitWhitespace => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let sections = string @@ -438,7 +438,7 @@ impl Callable for StrFunction { Value::List(List::with_items(sections)) } StrFunction::StartsWith => { - Error::expect_argument_amount(self.name(), 2, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let pattern_string = arguments.get(1).unwrap().as_string()?; @@ -447,7 +447,7 @@ impl Callable for StrFunction { Value::Boolean(string.starts_with(pattern)) } StrFunction::StripPrefix => { - Error::expect_argument_amount(self.name(), 2, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let prefix_string = arguments.get(1).unwrap().as_string()?; @@ -459,7 +459,7 @@ impl Callable for StrFunction { Value::option(stripped) } StrFunction::ToLowercase => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let lowercase = string.to_lowercase(); @@ -467,7 +467,7 @@ impl Callable for StrFunction { Value::string(lowercase) } StrFunction::ToUppercase => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let uppercase = string.to_uppercase(); @@ -475,14 +475,14 @@ impl Callable for StrFunction { Value::string(uppercase) } StrFunction::Trim => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let trimmed = arguments.first().unwrap().as_string()?.trim().to_string(); Value::string(trimmed) } StrFunction::TrimEnd => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let trimmed = arguments .first() @@ -494,7 +494,7 @@ impl Callable for StrFunction { Value::string(trimmed) } StrFunction::TrimEndMatches => { - Error::expect_argument_amount(self.name(), 2, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let pattern_string = arguments.get(1).unwrap().as_string()?; @@ -504,7 +504,7 @@ impl Callable for StrFunction { Value::string(trimmed) } StrFunction::TrimMatches => { - Error::expect_argument_amount(self.name(), 2, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let pattern = arguments @@ -518,7 +518,7 @@ impl Callable for StrFunction { Value::string(trimmed) } StrFunction::TrimStart => { - Error::expect_argument_amount(self.name(), 1, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; let trimmed = arguments .first() @@ -530,7 +530,7 @@ impl Callable for StrFunction { Value::string(trimmed) } StrFunction::TrimStartMatches => { - Error::expect_argument_amount(self.name(), 2, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; let string = arguments.first().unwrap().as_string()?; let pattern = arguments @@ -544,7 +544,7 @@ impl Callable for StrFunction { Value::string(trimmed) } StrFunction::Truncate => { - Error::expect_argument_amount(self.name(), 2, arguments.len())?; + RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; let input_string = arguments.first().unwrap().as_string()?; let new_length = arguments.get(1).unwrap().as_integer()? as usize; diff --git a/src/error/mod.rs b/src/error/mod.rs index 29925ec..369bacc 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -3,6 +3,7 @@ //! To deal with errors from dependencies, either create a new error variant //! or use the ToolFailure variant if the error can only occur inside a tool. mod runtime_error; +pub(crate) mod rw_lock_error; mod syntax_error; mod validation_error; @@ -10,77 +11,25 @@ pub use runtime_error::RuntimeError; pub use syntax_error::SyntaxError; pub use validation_error::ValidationError; -use serde::{Deserialize, Serialize}; use tree_sitter::{LanguageError, Node, Point}; -use crate::{value::Value, SyntaxPosition}; +use crate::{SourcePosition}; -use std::{ - fmt::{self, Formatter}, - io, - num::ParseFloatError, - string::FromUtf8Error, - sync::PoisonError, - time, -}; +use std::fmt::{self, Formatter}; -#[derive(Clone, PartialEq, Serialize, Deserialize)] pub enum Error { - Parsing(SyntaxError), + Syntax(SyntaxError), - Verification(ValidationError), + Validation(ValidationError), Runtime(RuntimeError), - AtSourcePosition { - error: Box, - source: String, - start_row: usize, - start_column: usize, - end_row: usize, - end_column: usize, - }, - - /// The function failed due to an external error. - External(String), - - /// A custom error explained by its message. - CustomMessage(String), - - /// Invalid user input. - Syntax { - source: String, - #[serde(skip)] - location: Point, - }, - - SerdeJson(String), - ParserCancelled, - ParseFloat { - reason: String, - }, - - ExpectedIterable { - actual: Value, - }, + Language(LanguageError), } impl Error { - pub fn at_source_position(self, source: &str, position: SyntaxPosition) -> Self { - let byte_range = position.start_byte..position.end_byte; - - Error::AtSourcePosition { - error: Box::new(self), - source: source[byte_range].to_string(), - start_row: position.start_row, - start_column: position.start_column, - end_row: position.end_row, - end_column: position.end_column, - } - } - pub fn expect_syntax_node( source: &str, expected: &str, @@ -91,103 +40,42 @@ impl Error { if expected == actual.kind() { Ok(()) } else if actual.is_error() { - Error::Syntax { + Err(SyntaxError::InvalidSource { source: source[actual.byte_range()].to_string(), - location: actual.start_position(), - } + position: SourcePosition::from(actual.range()), + }) } else { - SyntaxError::UnexpectedSyntaxNode { + Err(SyntaxError::UnexpectedSyntaxNode { expected: expected.to_string(), actual: actual.kind().to_string(), location: actual.start_position(), relevant_source: source[actual.byte_range()].to_string(), - } - } - } - - pub fn expect_argument_amount( - function_name: &str, - expected: usize, - actual: usize, - ) -> Result<(), ValidationError> { - if expected == actual { - Ok(()) - } else { - Err(Error::ExpectedBuiltInFunctionArgumentAmount { - function_name: function_name.to_string(), - expected, - actual, }) } } +} - pub fn is_error(&self, other: &Error) -> bool { - match self { - Error::AtSourcePosition { error, .. } => error.as_ref() == other, - _ => self == other, - } +impl From for Error { + fn from(error: SyntaxError) -> Self { + Error::Syntax(error) + } +} + +impl From for Error { + fn from(error: ValidationError) -> Self { + Error::Validation(error) + } +} + +impl From for Error { + fn from(error: RuntimeError) -> Self { + Error::Runtime(error) } } impl From for Error { fn from(error: LanguageError) -> Self { - Error::External(error.to_string()) - } -} - -impl From> for Error { - fn from(error: PoisonError) -> Self { - Error::External(error.to_string()) - } -} - -impl From for Error { - fn from(error: FromUtf8Error) -> Self { - Error::External(error.to_string()) - } -} - -impl From for Error { - fn from(error: ParseFloatError) -> Self { - Error::ParseFloat { - reason: error.to_string(), - } - } -} - -impl From for Error { - fn from(error: csv::Error) -> Self { - Error::External(error.to_string()) - } -} - -impl From for Error { - fn from(error: std::io::Error) -> Self { - Error::External(error.to_string()) - } -} - -impl From for Error { - fn from(error: reqwest::Error) -> Self { - Error::External(error.to_string()) - } -} - -impl From for Error { - fn from(error: serde_json::Error) -> Self { - Error::SerdeJson(error.to_string()) - } -} - -impl From for Error { - fn from(error: time::SystemTimeError) -> Self { - Error::External(error.to_string()) - } -} - -impl From for Error { - fn from(error: toml::de::Error) -> Self { - Error::External(error.to_string()) + Error::Language(error) } } @@ -200,44 +88,15 @@ impl fmt::Debug for Error { } impl fmt::Display for Error { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { + fn fmt(&self, _f: &mut Formatter) -> fmt::Result { use Error::*; match self { - AtSourcePosition { - error, - source, - start_row, - start_column, - end_row, - end_column, - } => { - write!( - f, - "{error} Occured at ({start_row}, {start_column}) to ({end_row}, {end_column}). Source: {source}" - ) - } - SerdeJson(message) => write!(f, "JSON processing error: {message}"), - ParserCancelled => write!( - f, - "Parsing was cancelled either manually or because it took too long." - ), - ParseFloat { reason } => { - write!( - f, - "Failed to parse a float value. Reason given: {}.", - reason - ) - } - ExpectedIterable { actual } => { - write!(f, "Expected an iterable value but got {actual}.") - } - Parsing(_) => todo!(), - Verification(_) => todo!(), + Syntax(_) => todo!(), + Validation(_) => todo!(), Runtime(_) => todo!(), - External(_) => todo!(), - CustomMessage(_) => todo!(), - Syntax { source, location } => todo!(), + ParserCancelled => todo!(), + Language(_) => todo!(), } } } diff --git a/src/error/runtime_error.rs b/src/error/runtime_error.rs index 1363700..9e9e3cc 100644 --- a/src/error/runtime_error.rs +++ b/src/error/runtime_error.rs @@ -1,11 +1,28 @@ -use std::fmt::{self, Display, Formatter}; +use std::{ + fmt::{self, Debug, Display, Formatter}, + io, + num::ParseFloatError, + string::FromUtf8Error, + time::{self, SystemTimeError}, +}; -use serde::{Deserialize, Serialize}; +use crate::{Value}; -use crate::Value; +use super::rw_lock_error::RwLockError; -#[derive(Clone, PartialEq, Serialize, Deserialize)] pub enum RuntimeError { + Csv(csv::Error), + + Io(io::Error), + + Reqwest(reqwest::Error), + + Json(serde_json::Error), + + SystemTime(SystemTimeError), + + Toml(toml::de::Error), + ExpectedString { actual: Value, }, @@ -71,111 +88,145 @@ pub enum RuntimeError { actual: Value, }, - /// A function was called with the wrong amount of arguments. + /// Failed to read or write a map. + /// + /// See the [MapError] docs for more info. + RwLock(RwLockError), + + ParseFloat(ParseFloatError), + + Utf8(FromUtf8Error), + + /// Failed to find a variable with a value for this key. + VariableIdentifierNotFound(String), + + /// A built-in function was called with the wrong amount of arguments. ExpectedBuiltInFunctionArgumentAmount { function_name: String, expected: usize, actual: usize, }, - - /// A function was called with the wrong amount of arguments. - ExpectedFunctionArgumentAmount { - expected: usize, - actual: usize, - }, - - /// A function was called with the wrong amount of arguments. - ExpectedFunctionArgumentMinimum { - source: String, - minumum_expected: usize, - actual: usize, - }, - - /// Failed to find a variable with a value for this key. - VariableIdentifierNotFound(String), } -impl Display for RuntimeError { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - use RuntimeError::*; - - match self { - ExpectedString { actual } => { - write!(f, "Expected a string but got {actual}.") - } - ExpectedInteger { actual } => write!(f, "Expected an integer, but got {actual}."), - ExpectedFloat { actual } => write!(f, "Expected a float, but got {actual}."), - ExpectedNumber { actual } => { - write!(f, "Expected a float or integer but got {actual}.",) - } - ExpectedNumberOrString { actual } => { - write!(f, "Expected a number or string, but got {actual}.") - } - ExpectedBoolean { actual } => { - write!(f, "Expected a boolean, but got {actual}.") - } - ExpectedList { actual } => write!(f, "Expected a list, but got {actual}."), - ExpectedMinLengthList { - minimum_len, - actual_len, - } => write!( - f, - "Expected a list of at least {minimum_len} values, but got one with {actual_len}.", - ), - ExpectedFixedLenList { - expected_len, - actual, - } => write!( - f, - "Expected a list of len {}, but got {:?}.", - expected_len, actual - ), - ExpectedNone { actual } => write!(f, "Expected an empty value, but got {actual}."), - ExpectedMap { actual } => write!(f, "Expected a map, but got {actual}."), - ExpectedTable { actual } => write!(f, "Expected a table, but got {actual}."), - ExpectedFunction { actual } => { - write!(f, "Expected function, but got {actual}.") - } - ExpectedOption { actual } => write!(f, "Expected option, but got {actual}."), - ExpectedCollection { actual } => { - write!( - f, - "Expected a string, list, map or table, but got {actual}.", - ) - } - ExpectedBuiltInFunctionArgumentAmount { - function_name, +impl RuntimeError { + pub fn expect_argument_amount( + function_name: &str, + expected: usize, + actual: usize, + ) -> Result<(), Self> { + if expected == actual { + Ok(()) + } else { + Err(RuntimeError::ExpectedBuiltInFunctionArgumentAmount { + function_name: function_name.to_string(), expected, actual, - } => todo!(), - ExpectedFunctionArgumentAmount { expected, actual } => todo!(), - ExpectedFunctionArgumentMinimum { - source, - minumum_expected, - actual, - } => todo!(), - ExpectedBuiltInFunctionArgumentAmount { - function_name: tool_name, - expected, - actual, - } => write!( - f, - "{tool_name} expected {expected} arguments, but got {actual}.", - ), - ExpectedFunctionArgumentAmount { expected, actual } => { - write!(f, "Expected {expected} arguments, but got {actual}.",) - } - ExpectedFunctionArgumentMinimum { - source, - minumum_expected, - actual, - } => { - write!( - f, - "{source} expected at least {minumum_expected} arguments, but got {actual}." - ) - } - VariableIdentifierNotFound(_) => todo!(), + }) } } } + +impl From for RuntimeError { + fn from(error: csv::Error) -> Self { + RuntimeError::Csv(error) + } +} + +impl From for RuntimeError { + fn from(error: std::io::Error) -> Self { + RuntimeError::Io(error) + } +} + +impl From for RuntimeError { + fn from(error: reqwest::Error) -> Self { + RuntimeError::Reqwest(error) + } +} + +impl From for RuntimeError { + fn from(error: serde_json::Error) -> Self { + RuntimeError::Json(error) + } +} + +impl From for RuntimeError { + fn from(error: time::SystemTimeError) -> Self { + RuntimeError::SystemTime(error) + } +} + +impl From for RuntimeError { + fn from(error: toml::de::Error) -> Self { + RuntimeError::Toml(error) + } +} + +impl From for RuntimeError { + fn from(error: ParseFloatError) -> Self { + RuntimeError::ParseFloat(error) + } +} + +impl From for RuntimeError { + fn from(error: FromUtf8Error) -> Self { + RuntimeError::Utf8(error) + } +} + +impl Display for RuntimeError { + fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result { + use RuntimeError::*; + + match self { + VariableIdentifierNotFound(_) => todo!(), + RwLock(_) => todo!(), + Csv(_) => todo!(), + Io(_) => todo!(), + Reqwest(_) => todo!(), + Json(_) => todo!(), + SystemTime(_) => todo!(), + Toml(_) => todo!(), + Utf8(_) => todo!(), + ParseFloat(_) => todo!(), + ExpectedBuiltInFunctionArgumentAmount { + function_name: _, + expected: _, + actual: _, + } => todo!(), + ExpectedString { actual: _ } => todo!(), + ExpectedInteger { actual: _ } => todo!(), + ExpectedFloat { actual: _ } => todo!(), + ExpectedNumber { actual: _ } => todo!(), + ExpectedNumberOrString { actual: _ } => todo!(), + ExpectedBoolean { actual: _ } => todo!(), + ExpectedList { actual: _ } => todo!(), + ExpectedMinLengthList { + minimum_len: _, + actual_len: _, + } => todo!(), + ExpectedFixedLenList { + expected_len: _, + actual: _, + } => todo!(), + ExpectedNone { actual: _ } => todo!(), + ExpectedMap { actual: _ } => todo!(), + ExpectedTable { actual: _ } => todo!(), + ExpectedFunction { actual: _ } => todo!(), + ExpectedOption { actual: _ } => todo!(), + ExpectedCollection { actual: _ } => todo!(), + } + } +} + +impl Debug for RuntimeError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{self}") + } +} + +impl From for RuntimeError { + fn from(error: RwLockError) -> Self { + RuntimeError::RwLock(error) + } +} diff --git a/src/error/rw_lock_error.rs b/src/error/rw_lock_error.rs new file mode 100644 index 0000000..f0938c9 --- /dev/null +++ b/src/error/rw_lock_error.rs @@ -0,0 +1,21 @@ +use std::fmt::{self, Debug, Display, Formatter}; + +use serde::{Deserialize, Serialize}; + +#[derive(Clone, PartialEq, Serialize, Deserialize)] +pub struct RwLockError; + +impl Display for RwLockError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "Map error: failed to acquire a read/write lock because another thread has panicked." + ) + } +} + +impl Debug for RwLockError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{self}") + } +} diff --git a/src/error/syntax_error.rs b/src/error/syntax_error.rs index 35063f5..dfb35d6 100644 --- a/src/error/syntax_error.rs +++ b/src/error/syntax_error.rs @@ -1,8 +1,20 @@ use serde::{Deserialize, Serialize}; use tree_sitter::Point; +use crate::SourcePosition; + +use super::rw_lock_error::RwLockError; + #[derive(Clone, PartialEq, Serialize, Deserialize)] pub enum SyntaxError { + /// Invalid user input. + InvalidSource { + source: String, + position: SourcePosition, + }, + + RwLock(RwLockError), + UnexpectedSyntaxNode { expected: String, actual: String, @@ -13,3 +25,9 @@ pub enum SyntaxError { relevant_source: String, }, } + +impl From for SyntaxError { + fn from(error: RwLockError) -> Self { + SyntaxError::RwLock(error) + } +} diff --git a/src/error/validation_error.rs b/src/error/validation_error.rs index 4b447b6..576fdc2 100644 --- a/src/error/validation_error.rs +++ b/src/error/validation_error.rs @@ -1,6 +1,8 @@ use serde::{Deserialize, Serialize}; -use crate::{Type, Value}; +use crate::{Identifier, SourcePosition, Type, Value}; + +use super::rw_lock_error::RwLockError; #[derive(Clone, PartialEq, Serialize, Deserialize)] pub enum ValidationError { @@ -8,20 +10,73 @@ pub enum ValidationError { AssertEqualFailed { expected: Value, actual: Value, + position: SourcePosition, }, /// The 'assert' macro did not resolve successfully. - AssertFailed, + AssertFailed { position: SourcePosition }, + + /// A built-in function was called with the wrong amount of arguments. + ExpectedBuiltInFunctionArgumentAmount { + function_name: String, + expected: usize, + actual: usize, + }, + + /// A function was called with the wrong amount of arguments. + ExpectedFunctionArgumentAmount { + expected: usize, + actual: usize, + position: SourcePosition, + }, + + /// A function was called with the wrong amount of arguments. + ExpectedFunctionArgumentMinimum { + minumum_expected: usize, + actual: usize, + position: SourcePosition, + }, + + /// Failed to read or write a map. + /// + /// See the [MapError] docs for more info. + RwLock(RwLockError), TypeCheck { expected: Type, actual: Type, + position: SourcePosition, }, TypeCheckExpectedFunction { actual: Type, + position: SourcePosition, }, /// Failed to find a variable with a value for this key. - VariableIdentifierNotFound(String), + VariableIdentifierNotFound(Identifier), +} + +impl ValidationError { + pub fn expect_argument_amount( + function_name: &str, + expected: usize, + actual: usize, + ) -> Result<(), Self> { + if expected == actual { + Ok(()) + } else { + Err(ValidationError::ExpectedBuiltInFunctionArgumentAmount { + function_name: function_name.to_string(), + expected, + actual, + }) + } + } +} + +impl From for ValidationError { + fn from(_error: RwLockError) -> Self { + ValidationError::RwLock(RwLockError) + } } diff --git a/src/interpret.rs b/src/interpret.rs index 57ce972..4faf40e 100644 --- a/src/interpret.rs +++ b/src/interpret.rs @@ -38,8 +38,7 @@ use tree_sitter::{Node as SyntaxNode, Parser, Tree as SyntaxTree, TreeCursor}; use crate::{ - error::{RuntimeError, SyntaxError, ValidationError}, - language, AbstractTree, Error, Format, Map, Root, Value, + error::SyntaxError, language, AbstractTree, Error, Format, Map, Root, SourcePosition, Value, }; /// Interpret the given source code. Returns the value of last statement or the @@ -84,7 +83,7 @@ impl Interpreter { .set_language(language()) .expect("Language version is incompatible with tree sitter version."); - parser.set_logger(Some(Box::new(|log_type, message| { + parser.set_logger(Some(Box::new(|_log_type, message| { log::info!("{}", message) }))); @@ -117,12 +116,12 @@ impl Interpreter { node: SyntaxNode, source: &str, cursor: &mut TreeCursor, - ) -> Result<(), ValidationError> { + ) -> Result<(), Error> { if node.is_error() { - Err(Error::Syntax { + Err(Error::Syntax(SyntaxError::InvalidSource { source: source[node.byte_range()].to_string(), - location: node.start_position(), - }) + position: SourcePosition::from(node.range()), + })) } else { for child in node.children(&mut cursor.clone()) { check_for_error(child, source, cursor)?; @@ -150,7 +149,9 @@ impl Interpreter { /// This function [parses][Self::parse], [verifies][Self::verify] and [runs][Root::run] using /// the same source code. pub fn run(&mut self, source: &str) -> Result { - self.verify(source)?.run(source, &self.context) + self.verify(source)? + .run(source, &self.context) + .map_err(|error| Error::Runtime(error)) } /// Return an s-expression displaying a syntax tree of the source, or the ParserCancelled error diff --git a/src/main.rs b/src/main.rs index 2a2b3b4..688b4f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ use reedline::{ use std::{borrow::Cow, fs::read_to_string, path::PathBuf, process::Command}; -use dust_lang::{built_in_values, Interpreter, Map, Result, Value}; +use dust_lang::{built_in_values, Error, Interpreter, Map, Value}; /// Command-line arguments to be parsed. #[derive(Parser, Debug)] @@ -332,7 +332,7 @@ impl Completer for DustCompleter { } } -fn run_shell(context: Map) -> Result<()> { +fn run_shell(context: Map) -> Result<(), Error> { let mut interpreter = Interpreter::new(context.clone()); let mut keybindings = default_emacs_keybindings(); diff --git a/src/value/map.rs b/src/value/map.rs index ae8ec8f..4c280e6 100644 --- a/src/value/map.rs +++ b/src/value/map.rs @@ -13,12 +13,10 @@ use std::{ collections::BTreeMap, fmt::{self, Display, Formatter}, marker::PhantomData, - sync::{Arc, PoisonError, RwLock, RwLockReadGuard}, + sync::{Arc, RwLock, RwLockReadGuard}, }; -use crate::{value::Value, Structure, Type}; - -pub type MapAccessError<'a> = PoisonError>>; +use crate::{error::rw_lock_error::RwLockError, value::Value, Structure, Type}; /// A collection dust variables comprised of key-value pairs. /// @@ -65,7 +63,7 @@ impl Map { } } - pub fn clone_from(other: &Self) -> Result { + pub fn clone_from(other: &Self) -> Result { let mut new_map = BTreeMap::new(); for (key, (value, r#type)) in other.variables()?.iter() { @@ -80,26 +78,35 @@ impl Map { pub fn variables( &self, - ) -> Result>, MapAccessError> { - self.variables.read() + ) -> Result>, RwLockError> { + self.variables.read().map_err(|_| RwLockError) } - pub fn set(&self, key: String, value: Value) -> Result, MapAccessError> { + pub fn set(&self, key: String, value: Value) -> Result, RwLockError> { log::info!("Setting variable {key} = {value}"); let value_type = value.r#type(); let previous = self .variables - .write()? + .write() + .map_err(|_| RwLockError)? .insert(key, (value, value_type.clone())); Ok(previous) } - pub fn set_type(&self, key: String, r#type: Type) -> Result, ()> { + pub fn set_type( + &self, + key: String, + r#type: Type, + ) -> Result, RwLockError> { log::info!("Setting type {key} = {}", r#type); - let previous = self.variables.write()?.insert(key, (Value::none(), r#type)); + let previous = self + .variables + .write() + .map_err(|_| RwLockError)? + .insert(key, (Value::none(), r#type)); Ok(previous) } diff --git a/src/value/mod.rs b/src/value/mod.rs index 6c62da4..c9b9be2 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -1,8 +1,5 @@ //! Types that represent runtime values. -use crate::{ - error::{Error, RuntimeError}, - Identifier, Type, TypeSpecification, -}; +use crate::{error::RuntimeError, Identifier, Type, TypeSpecification}; use serde::{ de::{MapAccess, SeqAccess, Visitor}, @@ -167,7 +164,7 @@ impl Value { pub fn as_string(&self) -> Result<&String, RuntimeError> { match self { Value::String(string) => Ok(string), - value => Err(Error::ExpectedString { + value => Err(RuntimeError::ExpectedString { actual: value.clone(), }), } @@ -177,7 +174,7 @@ impl Value { pub fn as_integer(&self) -> Result { match self { Value::Integer(i) => Ok(*i), - value => Err(Error::ExpectedInteger { + value => Err(RuntimeError::ExpectedInteger { actual: value.clone(), }), } @@ -187,7 +184,7 @@ impl Value { pub fn as_float(&self) -> Result { match self { Value::Float(f) => Ok(*f), - value => Err(Error::ExpectedFloat { + value => Err(RuntimeError::ExpectedFloat { actual: value.clone(), }), } @@ -199,7 +196,7 @@ impl Value { match self { Value::Float(f) => Ok(*f), Value::Integer(i) => Ok(*i as f64), - value => Err(Error::ExpectedNumber { + value => Err(RuntimeError::ExpectedNumber { actual: value.clone(), }), } @@ -209,7 +206,7 @@ impl Value { pub fn as_boolean(&self) -> Result { match self { Value::Boolean(boolean) => Ok(*boolean), - value => Err(Error::ExpectedBoolean { + value => Err(RuntimeError::ExpectedBoolean { actual: value.clone(), }), } @@ -219,7 +216,7 @@ impl Value { pub fn as_list(&self) -> Result<&List, RuntimeError> { match self { Value::List(list) => Ok(list), - value => Err(Error::ExpectedList { + value => Err(RuntimeError::ExpectedList { actual: value.clone(), }), } @@ -229,7 +226,7 @@ impl Value { pub fn into_inner_list(self) -> Result { match self { Value::List(list) => Ok(list), - value => Err(Error::ExpectedList { + value => Err(RuntimeError::ExpectedList { actual: value.clone(), }), } @@ -239,7 +236,7 @@ impl Value { pub fn as_map(&self) -> Result<&Map, RuntimeError> { match self { Value::Map(map) => Ok(map), - value => Err(Error::ExpectedMap { + value => Err(RuntimeError::ExpectedMap { actual: value.clone(), }), } @@ -250,7 +247,7 @@ impl Value { pub fn as_function(&self) -> Result<&Function, RuntimeError> { match self { Value::Function(function) => Ok(function), - value => Err(Error::ExpectedFunction { + value => Err(RuntimeError::ExpectedFunction { actual: value.clone(), }), } @@ -260,7 +257,7 @@ impl Value { pub fn as_option(&self) -> Result<&Option>, RuntimeError> { match self { Value::Option(option) => Ok(option), - value => Err(Error::ExpectedOption { + value => Err(RuntimeError::ExpectedOption { actual: value.clone(), }), } @@ -273,12 +270,12 @@ impl Value { if option.is_none() { Ok(()) } else { - Err(Error::ExpectedNone { + Err(RuntimeError::ExpectedNone { actual: self.clone(), }) } } - value => Err(Error::ExpectedNone { + value => Err(RuntimeError::ExpectedNone { actual: value.clone(), }), } @@ -319,7 +316,7 @@ impl Add for Value { other }; - Err(Error::ExpectedNumberOrString { + Err(RuntimeError::ExpectedNumberOrString { actual: non_number_or_string, }) } @@ -341,7 +338,7 @@ impl Sub for Value { let non_number = if !self.is_number() { self } else { other }; - Err(Error::ExpectedNumber { actual: non_number }) + Err(RuntimeError::ExpectedNumber { actual: non_number }) } } @@ -356,7 +353,7 @@ impl Mul for Value { } else { let non_number = if !self.is_number() { self } else { other }; - Err(Error::ExpectedNumber { actual: non_number }) + Err(RuntimeError::ExpectedNumber { actual: non_number }) } } } @@ -377,7 +374,7 @@ impl Div for Value { } else { let non_number = if !self.is_number() { self } else { other }; - Err(Error::ExpectedNumber { actual: non_number }) + Err(RuntimeError::ExpectedNumber { actual: non_number }) } } } @@ -596,49 +593,49 @@ impl From<()> for Value { } impl TryFrom for String { - type Error = Error; + type Error = RuntimeError; fn try_from(value: Value) -> std::result::Result { if let Value::String(string) = value { Ok(string) } else { - Err(Error::ExpectedString { actual: value }) + Err(RuntimeError::ExpectedString { actual: value }) } } } impl TryFrom for f64 { - type Error = Error; + type Error = RuntimeError; fn try_from(value: Value) -> std::result::Result { if let Value::Float(value) = value { Ok(value) } else { - Err(Error::ExpectedFloat { actual: value }) + Err(RuntimeError::ExpectedFloat { actual: value }) } } } impl TryFrom for i64 { - type Error = Error; + type Error = RuntimeError; fn try_from(value: Value) -> std::result::Result { if let Value::Integer(value) = value { Ok(value) } else { - Err(Error::ExpectedInteger { actual: value }) + Err(RuntimeError::ExpectedInteger { actual: value }) } } } impl TryFrom for bool { - type Error = Error; + type Error = RuntimeError; fn try_from(value: Value) -> std::result::Result { if let Value::Boolean(value) = value { Ok(value) } else { - Err(Error::ExpectedBoolean { actual: value }) + Err(RuntimeError::ExpectedBoolean { actual: value }) } } }