diff --git a/src/abstract_tree/assignment.rs b/src/abstract_tree/assignment.rs index 0ae82ec..163f1d6 100644 --- a/src/abstract_tree/assignment.rs +++ b/src/abstract_tree/assignment.rs @@ -1,8 +1,9 @@ use serde::{Deserialize, Serialize}; use crate::{ - AbstractTree, AssignmentOperator, Error, Format, Identifier, Map, Result, Statement, - SyntaxNode, SyntaxPosition, Type, TypeSpecification, Value, + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, AssignmentOperator, Error, Format, Identifier, Map, Statement, SyntaxNode, + SyntaxPosition, Type, TypeSpecification, Value, }; /// Variable assignment, including add-assign and subtract-assign operations. @@ -17,7 +18,11 @@ pub struct Assignment { } impl AbstractTree for Assignment { - fn from_syntax(syntax_node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax( + syntax_node: SyntaxNode, + source: &str, + context: &Map, + ) -> Result { Error::expect_syntax_node(source, "assignment", syntax_node)?; let child_count = syntax_node.child_count(); @@ -57,7 +62,7 @@ impl AbstractTree for Assignment { }) } - fn check_type(&self, source: &str, context: &Map) -> Result<()> { + 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 { @@ -103,7 +108,7 @@ impl AbstractTree for Assignment { Ok(()) } - fn run(&self, source: &str, context: &Map) -> Result { + fn run(&self, source: &str, context: &Map) -> Result { let key = self.identifier.inner(); let value = self.statement.run(source, context)?; @@ -113,7 +118,9 @@ impl AbstractTree for Assignment { previous_value += value; previous_value } else { - return Err(Error::VariableIdentifierNotFound(key.clone())); + return Err(Error::Runtime(RuntimeError::VariableIdentifierNotFound( + key.clone(), + ))); } } AssignmentOperator::MinusEqual => { @@ -121,7 +128,9 @@ impl AbstractTree for Assignment { previous_value -= value; previous_value } else { - return Err(Error::VariableIdentifierNotFound(key.clone())); + return Err(Error::Runtime(RuntimeError::VariableIdentifierNotFound( + key.clone(), + ))); } } AssignmentOperator::Equal => value, @@ -132,7 +141,7 @@ impl AbstractTree for Assignment { Ok(Value::none()) } - fn expected_type(&self, _context: &Map) -> Result { + fn expected_type(&self, _context: &Map) -> Result { Ok(Type::None) } } diff --git a/src/abstract_tree/assignment_operator.rs b/src/abstract_tree/assignment_operator.rs index 4fe09da..21cb351 100644 --- a/src/abstract_tree/assignment_operator.rs +++ b/src/abstract_tree/assignment_operator.rs @@ -1,6 +1,9 @@ use serde::{Deserialize, Serialize}; -use crate::{AbstractTree, Error, Format, Map, Result, SyntaxNode, Type, Value}; +use crate::{ + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Error, Format, Map, SyntaxNode, Type, Value, +}; /// Operators that be used in an assignment statement. #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] @@ -11,7 +14,11 @@ pub enum AssignmentOperator { } impl AbstractTree for AssignmentOperator { - fn from_syntax(node: SyntaxNode, source: &str, _context: &crate::Map) -> Result { + fn from_syntax( + node: SyntaxNode, + source: &str, + _context: &crate::Map, + ) -> Result { Error::expect_syntax_node(source, "assignment_operator", node)?; let operator_node = node.child(0).unwrap(); @@ -32,13 +39,17 @@ impl AbstractTree for AssignmentOperator { Ok(operator) } - fn run(&self, _source: &str, _context: &Map) -> Result { + fn run(&self, _source: &str, _context: &Map) -> Result { Ok(Value::none()) } - fn expected_type(&self, _context: &Map) -> Result { + fn expected_type(&self, _context: &Map) -> Result { Ok(Type::None) } + + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + Ok(()) + } } impl Format for AssignmentOperator { diff --git a/src/abstract_tree/block.rs b/src/abstract_tree/block.rs index 9a87881..b1d95fb 100644 --- a/src/abstract_tree/block.rs +++ b/src/abstract_tree/block.rs @@ -3,7 +3,10 @@ use std::sync::RwLock; use rayon::prelude::*; use serde::{Deserialize, Serialize}; -use crate::{AbstractTree, Error, Format, Map, Result, Statement, SyntaxNode, Type, Value}; +use crate::{ + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Error, Format, Map, Statement, SyntaxNode, Type, Value, +}; /// Abstract representation of a block. /// @@ -20,7 +23,7 @@ pub struct Block { } impl AbstractTree for Block { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { Error::expect_syntax_node(source, "block", node)?; let first_child = node.child(0).unwrap(); @@ -49,7 +52,7 @@ impl AbstractTree for Block { }) } - fn check_type(&self, _source: &str, _context: &Map) -> Result<()> { + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { for statement in &self.statements { if let Statement::Return(inner_statement) = statement { return inner_statement.check_type(_source, _context); @@ -61,7 +64,7 @@ impl AbstractTree for Block { Ok(()) } - fn run(&self, source: &str, context: &Map) -> Result { + fn run(&self, source: &str, context: &Map) -> Result { if self.is_async { let statements = &self.statements; let final_result = RwLock::new(Ok(Value::none())); @@ -110,7 +113,7 @@ impl AbstractTree for Block { } } - fn expected_type(&self, context: &Map) -> Result { + fn expected_type(&self, context: &Map) -> Result { if let Some(statement) = self.statements.iter().find(|statement| { if let Statement::Return(_) = statement { true diff --git a/src/abstract_tree/built_in_value.rs b/src/abstract_tree/built_in_value.rs index 471a75a..8e56203 100644 --- a/src/abstract_tree/built_in_value.rs +++ b/src/abstract_tree/built_in_value.rs @@ -5,7 +5,8 @@ use serde::{Deserialize, Serialize}; use crate::{ built_in_functions::{fs::fs_functions, json::json_functions, str::string_functions, Callable}, - AbstractTree, BuiltInFunction, Format, Function, List, Map, Result, SyntaxNode, Type, Value, + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, BuiltInFunction, Format, Function, List, Map, SyntaxNode, Type, Value, }; static ARGS: OnceLock = OnceLock::new(); @@ -174,7 +175,7 @@ impl BuiltInValue { } impl AbstractTree for BuiltInValue { - fn from_syntax(node: SyntaxNode, _source: &str, _context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, _source: &str, _context: &Map) -> Result { let built_in_value = match node.kind() { "args" => BuiltInValue::Args, "assert_equal" => BuiltInValue::AssertEqual, @@ -190,12 +191,16 @@ impl AbstractTree for BuiltInValue { Ok(built_in_value) } - fn run(&self, _source: &str, _context: &Map) -> Result { - Ok(self.get().clone()) + fn expected_type(&self, _context: &Map) -> Result { + Ok(self.r#type()) } - fn expected_type(&self, _context: &Map) -> Result { - Ok(self.r#type()) + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + Ok(()) + } + + fn run(&self, _source: &str, _context: &Map) -> Result { + Ok(self.get().clone()) } } diff --git a/src/abstract_tree/command.rs b/src/abstract_tree/command.rs index d67e7a0..b172bb3 100644 --- a/src/abstract_tree/command.rs +++ b/src/abstract_tree/command.rs @@ -2,7 +2,10 @@ use std::process; use serde::{Deserialize, Serialize}; -use crate::{AbstractTree, Error, Format, Map, Result, Type, Value}; +use crate::{ + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Error, Format, Map, Type, Value, +}; /// An external program invokation. #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] @@ -12,7 +15,11 @@ pub struct Command { } impl AbstractTree for Command { - fn from_syntax(node: tree_sitter::Node, source: &str, _context: &crate::Map) -> Result { + fn from_syntax( + node: tree_sitter::Node, + source: &str, + _context: &crate::Map, + ) -> Result { Error::expect_syntax_node(source, "command", node)?; let command_text_node = node.child(1).unwrap(); @@ -40,7 +47,15 @@ impl AbstractTree for Command { }) } - fn run(&self, _source: &str, _context: &Map) -> Result { + fn expected_type(&self, _context: &Map) -> Result { + Ok(Type::String) + } + + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + todo!() + } + + fn run(&self, _source: &str, _context: &Map) -> Result { let output = process::Command::new(&self.command_text) .args(&self.command_arguments) .spawn()? @@ -50,10 +65,6 @@ impl AbstractTree for Command { Ok(Value::String(string)) } - - fn expected_type(&self, _context: &Map) -> Result { - Ok(Type::String) - } } impl Format for Command { diff --git a/src/abstract_tree/expression.rs b/src/abstract_tree/expression.rs index b49a536..c9751d7 100644 --- a/src/abstract_tree/expression.rs +++ b/src/abstract_tree/expression.rs @@ -1,8 +1,10 @@ use serde::{Deserialize, Serialize}; use crate::{ - value_node::ValueNode, AbstractTree, Command, Error, Format, FunctionCall, Identifier, Index, - Logic, Map, Math, New, Result, SyntaxNode, Type, Value, Yield, + error::{RuntimeError, SyntaxError, ValidationError}, + value_node::ValueNode, + AbstractTree, Command, Error, Format, FunctionCall, Identifier, Index, Logic, Map, Math, New, + SyntaxNode, Type, Value, Yield, }; /// Abstract representation of an expression statement. @@ -24,7 +26,7 @@ pub enum Expression { } impl AbstractTree for Expression { - fn from_syntax(node: SyntaxNode, source: &str, _context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, _context: &Map) -> Result { Error::expect_syntax_node(source, "expression", node)?; let child = if node.child(0).unwrap().is_named() { @@ -62,7 +64,21 @@ impl AbstractTree for Expression { Ok(expression) } - fn check_type(&self, _source: &str, _context: &Map) -> Result<()> { + fn expected_type(&self, _context: &Map) -> Result { + match self { + Expression::Value(value_node) => value_node.expected_type(_context), + Expression::Identifier(identifier) => identifier.expected_type(_context), + Expression::Math(math) => math.expected_type(_context), + Expression::Logic(logic) => logic.expected_type(_context), + Expression::FunctionCall(function_call) => function_call.expected_type(_context), + Expression::Index(index) => index.expected_type(_context), + Expression::Yield(r#yield) => r#yield.expected_type(_context), + Expression::New(new) => new.expected_type(_context), + Expression::Command(command) => command.expected_type(_context), + } + } + + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { match self { Expression::Value(value_node) => value_node.check_type(_source, _context), Expression::Identifier(identifier) => identifier.check_type(_source, _context), @@ -76,7 +92,7 @@ impl AbstractTree for Expression { } } - fn run(&self, _source: &str, _context: &Map) -> Result { + fn run(&self, _source: &str, _context: &Map) -> Result { match self { Expression::Value(value_node) => value_node.run(_source, _context), Expression::Identifier(identifier) => identifier.run(_source, _context), @@ -89,20 +105,6 @@ impl AbstractTree for Expression { Expression::Command(command) => command.run(_source, _context), } } - - fn expected_type(&self, _context: &Map) -> Result { - match self { - Expression::Value(value_node) => value_node.expected_type(_context), - Expression::Identifier(identifier) => identifier.expected_type(_context), - Expression::Math(math) => math.expected_type(_context), - Expression::Logic(logic) => logic.expected_type(_context), - Expression::FunctionCall(function_call) => function_call.expected_type(_context), - Expression::Index(index) => index.expected_type(_context), - Expression::Yield(r#yield) => r#yield.expected_type(_context), - Expression::New(new) => new.expected_type(_context), - Expression::Command(command) => command.expected_type(_context), - } - } } impl Format for Expression { diff --git a/src/abstract_tree/for.rs b/src/abstract_tree/for.rs index 48d812c..799759a 100644 --- a/src/abstract_tree/for.rs +++ b/src/abstract_tree/for.rs @@ -2,8 +2,8 @@ use rayon::prelude::*; use serde::{Deserialize, Serialize}; use crate::{ - AbstractTree, Block, Error, Expression, Format, Identifier, Map, Result, SyntaxNode, Type, - Value, + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Block, Error, Expression, Format, Identifier, Map, SyntaxNode, Type, Value, }; /// Abstract representation of a for loop statement. @@ -16,7 +16,7 @@ pub struct For { } impl AbstractTree for For { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { Error::expect_syntax_node(source, "for", node)?; let for_node = node.child(0).unwrap(); @@ -50,7 +50,15 @@ impl AbstractTree for For { }) } - fn run(&self, source: &str, context: &Map) -> Result { + fn expected_type(&self, _context: &Map) -> Result { + Ok(Type::None) + } + + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + self.block.check_type(_source, _context) + } + + fn run(&self, source: &str, context: &Map) -> Result { let expression_run = self.collection.run(source, context)?; let key = self.item_id.inner(); @@ -98,10 +106,6 @@ impl AbstractTree for For { Ok(Value::none()) } - - fn expected_type(&self, _context: &Map) -> Result { - Ok(Type::None) - } } impl Format for For { diff --git a/src/abstract_tree/function_call.rs b/src/abstract_tree/function_call.rs index 1839882..4fced7f 100644 --- a/src/abstract_tree/function_call.rs +++ b/src/abstract_tree/function_call.rs @@ -1,8 +1,9 @@ use serde::{Deserialize, Serialize}; use crate::{ - AbstractTree, Error, Expression, Format, FunctionExpression, Map, Result, SyntaxNode, - SyntaxPosition, Type, Value, + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Error, Expression, Format, FunctionExpression, Map, SyntaxNode, SyntaxPosition, + Type, Value, }; /// A function being invoked and the arguments it is being passed. @@ -29,7 +30,7 @@ impl FunctionCall { } impl AbstractTree for FunctionCall { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { Error::expect_syntax_node(source, "function_call", node)?; let function_node = node.child(0).unwrap(); @@ -54,7 +55,37 @@ impl AbstractTree for FunctionCall { }) } - fn check_type(&self, source: &str, context: &Map) -> Result<()> { + fn expected_type(&self, context: &Map) -> Result { + match &self.function_expression { + FunctionExpression::Identifier(identifier) => { + let identifier_type = identifier.expected_type(context)?; + + if let Type::Function { + parameter_types: _, + return_type, + } = &identifier_type + { + Ok(*return_type.clone()) + } else { + Ok(identifier_type) + } + } + FunctionExpression::FunctionCall(function_call) => function_call.expected_type(context), + FunctionExpression::Value(value_node) => { + let value_type = value_node.expected_type(context)?; + + if let Type::Function { return_type, .. } = value_type { + Ok(*return_type) + } else { + Ok(value_type) + } + } + FunctionExpression::Index(index) => index.expected_type(context), + FunctionExpression::Yield(r#yield) => r#yield.expected_type(context), + } + } + + 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 { @@ -89,7 +120,7 @@ impl AbstractTree for FunctionCall { Ok(()) } - fn run(&self, source: &str, context: &Map) -> Result { + fn run(&self, source: &str, context: &Map) -> Result { let value = match &self.function_expression { FunctionExpression::Identifier(identifier) => { let key = identifier.inner(); @@ -121,36 +152,6 @@ impl AbstractTree for FunctionCall { value.as_function()?.call(&arguments, source, context) } - - fn expected_type(&self, context: &Map) -> Result { - match &self.function_expression { - FunctionExpression::Identifier(identifier) => { - let identifier_type = identifier.expected_type(context)?; - - if let Type::Function { - parameter_types: _, - return_type, - } = &identifier_type - { - Ok(*return_type.clone()) - } else { - Ok(identifier_type) - } - } - FunctionExpression::FunctionCall(function_call) => function_call.expected_type(context), - FunctionExpression::Value(value_node) => { - let value_type = value_node.expected_type(context)?; - - if let Type::Function { return_type, .. } = value_type { - Ok(*return_type) - } else { - Ok(value_type) - } - } - FunctionExpression::Index(index) => index.expected_type(context), - FunctionExpression::Yield(r#yield) => r#yield.expected_type(context), - } - } } impl Format for FunctionCall { diff --git a/src/abstract_tree/function_expression.rs b/src/abstract_tree/function_expression.rs index 8e2ced9..5590cf8 100644 --- a/src/abstract_tree/function_expression.rs +++ b/src/abstract_tree/function_expression.rs @@ -1,8 +1,9 @@ use serde::{Deserialize, Serialize}; use crate::{ - AbstractTree, Error, Format, FunctionCall, Identifier, Index, Map, Result, SyntaxNode, Type, - Value, ValueNode, Yield, + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Error, Format, FunctionCall, Identifier, Index, Map, SyntaxNode, Type, Value, + ValueNode, Yield, }; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] @@ -15,7 +16,7 @@ pub enum FunctionExpression { } impl AbstractTree for FunctionExpression { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { Error::expect_syntax_node(source, "function_expression", node)?; let first_child = node.child(0).unwrap(); @@ -51,17 +52,7 @@ impl AbstractTree for FunctionExpression { Ok(function_expression) } - fn run(&self, source: &str, context: &Map) -> Result { - match self { - FunctionExpression::Identifier(identifier) => identifier.run(source, context), - FunctionExpression::FunctionCall(function_call) => function_call.run(source, context), - FunctionExpression::Value(value_node) => value_node.run(source, context), - FunctionExpression::Index(index) => index.run(source, context), - FunctionExpression::Yield(r#yield) => r#yield.run(source, context), - } - } - - fn expected_type(&self, context: &Map) -> Result { + fn expected_type(&self, context: &Map) -> Result { match self { FunctionExpression::Identifier(identifier) => identifier.expected_type(context), FunctionExpression::FunctionCall(function_call) => function_call.expected_type(context), @@ -70,6 +61,28 @@ impl AbstractTree for FunctionExpression { FunctionExpression::Yield(r#yield) => r#yield.expected_type(context), } } + + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + match self { + FunctionExpression::Identifier(identifier) => identifier.check_type(_source, _context), + FunctionExpression::FunctionCall(function_call) => { + function_call.check_type(_source, _context) + } + FunctionExpression::Value(value_node) => value_node.check_type(_source, _context), + FunctionExpression::Index(index) => index.check_type(_source, _context), + FunctionExpression::Yield(r#yield) => r#yield.check_type(_source, _context), + } + } + + fn run(&self, source: &str, context: &Map) -> Result { + match self { + FunctionExpression::Identifier(identifier) => identifier.run(source, context), + FunctionExpression::FunctionCall(function_call) => function_call.run(source, context), + FunctionExpression::Value(value_node) => value_node.run(source, context), + FunctionExpression::Index(index) => index.run(source, context), + FunctionExpression::Yield(r#yield) => r#yield.run(source, context), + } + } } impl Format for FunctionExpression { diff --git a/src/abstract_tree/function_node.rs b/src/abstract_tree/function_node.rs index 32ac575..367a525 100644 --- a/src/abstract_tree/function_node.rs +++ b/src/abstract_tree/function_node.rs @@ -3,8 +3,9 @@ use std::fmt::{self, Display, Formatter}; use serde::{Deserialize, Serialize}; use crate::{ - AbstractTree, Block, Error, Format, Function, Identifier, Map, Result, SyntaxNode, - SyntaxPosition, Type, TypeSpecification, Value, + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Block, Error, Format, Function, Identifier, Map, SyntaxNode, SyntaxPosition, + Type, TypeSpecification, Value, }; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] @@ -56,7 +57,12 @@ impl FunctionNode { } } - pub fn call(&self, arguments: &[Value], source: &str, outer_context: &Map) -> Result { + pub fn call( + &self, + arguments: &[Value], + source: &str, + outer_context: &Map, + ) -> Result { let function_context = Map::new(); let parameter_argument_pairs = self.parameters.iter().zip(arguments.iter()); @@ -79,7 +85,11 @@ impl FunctionNode { } impl AbstractTree for FunctionNode { - fn from_syntax(node: SyntaxNode, source: &str, outer_context: &Map) -> Result { + fn from_syntax( + node: SyntaxNode, + source: &str, + outer_context: &Map, + ) -> Result { Error::expect_syntax_node(source, "function", node)?; let child_count = node.child_count(); @@ -132,7 +142,11 @@ impl AbstractTree for FunctionNode { }) } - fn check_type(&self, source: &str, context: &Map) -> Result<()> { + fn expected_type(&self, _context: &Map) -> Result { + Ok(self.r#type().clone()) + } + + fn check_type(&self, source: &str, context: &Map) -> Result<(), ValidationError> { let function_context = Map::new(); for (key, (_value, r#type)) in context.variables()?.iter() { @@ -163,15 +177,11 @@ impl AbstractTree for FunctionNode { } } - fn run(&self, _source: &str, _context: &Map) -> Result { + fn run(&self, _source: &str, _context: &Map) -> Result { let self_as_value = Value::Function(Function::ContextDefined(self.clone())); Ok(self_as_value) } - - fn expected_type(&self, _context: &Map) -> Result { - Ok(self.r#type().clone()) - } } impl Format for FunctionNode { diff --git a/src/abstract_tree/identifier.rs b/src/abstract_tree/identifier.rs index a4a58ef..3861c82 100644 --- a/src/abstract_tree/identifier.rs +++ b/src/abstract_tree/identifier.rs @@ -2,7 +2,10 @@ use std::fmt::{self, Display, Formatter}; use serde::{Deserialize, Serialize}; -use crate::{AbstractTree, Error, Format, Map, Result, SyntaxNode, Type, Value}; +use crate::{ + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Error, Format, Map, SyntaxNode, Type, Value, +}; /// A string by which a variable is known to a context. /// @@ -26,7 +29,7 @@ impl Identifier { } impl AbstractTree for Identifier { - fn from_syntax(node: SyntaxNode, source: &str, _context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, _context: &Map) -> Result { Error::expect_syntax_node(source, "identifier", node)?; let text = &source[node.byte_range()]; @@ -36,21 +39,21 @@ impl AbstractTree for Identifier { Ok(Identifier(text.to_string())) } - fn run(&self, _source: &str, context: &Map) -> Result { - if let Some((value, _)) = context.variables()?.get(&self.0) { - Ok(value.clone()) + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + Ok(()) + } + + fn expected_type(&self, context: &Map) -> Result { + if let Some((_value, r#type)) = context.variables()?.get(&self.0) { + Ok(r#type.clone()) } else { Err(Error::VariableIdentifierNotFound(self.0.clone())) } } - fn check_type(&self, _source: &str, _context: &Map) -> Result<()> { - Ok(()) - } - - fn expected_type(&self, context: &Map) -> Result { - if let Some((_value, r#type)) = context.variables()?.get(&self.0) { - Ok(r#type.clone()) + fn run(&self, _source: &str, context: &Map) -> Result { + if let Some((value, _)) = context.variables()?.get(&self.0) { + Ok(value.clone()) } else { Err(Error::VariableIdentifierNotFound(self.0.clone())) } diff --git a/src/abstract_tree/if_else.rs b/src/abstract_tree/if_else.rs index 37d0d69..29bb860 100644 --- a/src/abstract_tree/if_else.rs +++ b/src/abstract_tree/if_else.rs @@ -1,6 +1,9 @@ use serde::{Deserialize, Serialize}; -use crate::{AbstractTree, Block, Expression, Format, Map, Result, SyntaxNode, Type, Value}; +use crate::{ + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Block, Expression, Format, Map, SyntaxNode, Type, Value, +}; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] pub struct IfElse { @@ -12,7 +15,7 @@ pub struct IfElse { } impl AbstractTree for IfElse { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { let if_expression_node = node.child(0).unwrap().child(1).unwrap(); let if_expression = Expression::from_syntax(if_expression_node, source, context)?; @@ -54,7 +57,35 @@ impl AbstractTree for IfElse { }) } - fn run(&self, source: &str, context: &Map) -> Result { + fn expected_type(&self, context: &Map) -> Result { + self.if_block.expected_type(context) + } + + fn check_type(&self, _source: &str, context: &Map) -> Result<(), ValidationError> { + self.if_expression.check_type(_source, context)?; + self.if_block.check_type(_source, context)?; + + let expected_type = self.if_block.expected_type(context)?; + let else_ifs = self + .else_if_expressions + .iter() + .zip(self.else_if_blocks.iter()); + + for (expression, block) in else_ifs { + expression.check_type(_source, context)?; + block.check_type(_source, context)?; + + expected_type.check(&block.expected_type(context)?)?; + } + + if let Some(expression) = self.else_block { + expected_type.check(&expression.expected_type(context)?)?; + } + + Ok(()) + } + + fn run(&self, source: &str, context: &Map) -> Result { let if_boolean = self.if_expression.run(source, context)?.as_boolean()?; if if_boolean { @@ -79,10 +110,6 @@ impl AbstractTree for IfElse { } } } - - fn expected_type(&self, context: &Map) -> Result { - self.if_block.expected_type(context) - } } impl Format for IfElse { diff --git a/src/abstract_tree/index.rs b/src/abstract_tree/index.rs index 59332dc..f71186c 100644 --- a/src/abstract_tree/index.rs +++ b/src/abstract_tree/index.rs @@ -1,7 +1,8 @@ use serde::{Deserialize, Serialize}; use crate::{ - AbstractTree, Error, Format, IndexExpression, List, Map, Result, SyntaxNode, Type, Value, + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Error, Format, IndexExpression, List, Map, SyntaxNode, Type, Value, }; /// Abstract representation of an index expression. @@ -15,7 +16,7 @@ pub struct Index { } impl AbstractTree for Index { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { Error::expect_syntax_node(source, "index", node)?; let collection_node = node.child(0).unwrap(); @@ -42,7 +43,27 @@ impl AbstractTree for Index { }) } - fn run(&self, source: &str, context: &Map) -> Result { + fn expected_type(&self, context: &Map) -> Result { + match self.collection.expected_type(context)? { + Type::List(item_type) => Ok(*item_type.clone()), + Type::Map(_) => Ok(Type::Any), + Type::None => Ok(Type::None), + r#type => Ok(r#type), + } + } + + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + self.collection.check_type(_source, _context)?; + self.index.check_type(_source, _context)?; + + if let Some(index_end) = self.index_end { + index_end.check_type(_source, _context)?; + } + + Ok(()) + } + + fn run(&self, source: &str, context: &Map) -> Result { let collection = self.collection.run(source, context)?; match collection { @@ -97,15 +118,6 @@ impl AbstractTree for Index { _ => Err(Error::ExpectedCollection { actual: collection }), } } - - fn expected_type(&self, context: &Map) -> Result { - match self.collection.expected_type(context)? { - Type::List(item_type) => Ok(*item_type.clone()), - Type::Map(_) => Ok(Type::Any), - Type::None => Ok(Type::None), - r#type => Ok(r#type), - } - } } impl Format for Index { diff --git a/src/abstract_tree/index_assignment.rs b/src/abstract_tree/index_assignment.rs index 1caa054..defcb18 100644 --- a/src/abstract_tree/index_assignment.rs +++ b/src/abstract_tree/index_assignment.rs @@ -1,8 +1,9 @@ use serde::{Deserialize, Serialize}; use crate::{ - AbstractTree, AssignmentOperator, Error, Format, Index, IndexExpression, Map, Result, - Statement, SyntaxNode, Type, Value, + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, AssignmentOperator, Error, Format, Index, IndexExpression, Map, Statement, + SyntaxNode, Type, Value, }; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] @@ -13,7 +14,7 @@ pub struct IndexAssignment { } impl AbstractTree for IndexAssignment { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { Error::expect_syntax_node(source, "index_assignment", node)?; let index_node = node.child(0).unwrap(); @@ -32,7 +33,16 @@ impl AbstractTree for IndexAssignment { }) } - fn run(&self, source: &str, context: &Map) -> Result { + fn expected_type(&self, _context: &Map) -> Result { + Ok(Type::None) + } + + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + self.index.check_type(_source, _context)?; + self.statement.check_type(_source, _context) + } + + fn run(&self, source: &str, context: &Map) -> Result { let index_collection = self.index.collection.run(source, context)?; let index_context = index_collection.as_map().unwrap_or(context); let index_key = if let IndexExpression::Identifier(identifier) = &self.index.index { @@ -73,10 +83,6 @@ impl AbstractTree for IndexAssignment { Ok(Value::none()) } - - fn expected_type(&self, _context: &Map) -> Result { - Ok(Type::None) - } } impl Format for IndexAssignment { diff --git a/src/abstract_tree/index_expression.rs b/src/abstract_tree/index_expression.rs index 2778da2..bc988bb 100644 --- a/src/abstract_tree/index_expression.rs +++ b/src/abstract_tree/index_expression.rs @@ -1,8 +1,9 @@ use serde::{Deserialize, Serialize}; use crate::{ - value_node::ValueNode, AbstractTree, Error, Format, FunctionCall, Identifier, Index, Map, - Result, SyntaxNode, Type, Value, + error::{RuntimeError, SyntaxError, ValidationError}, + value_node::ValueNode, + AbstractTree, Error, Format, FunctionCall, Identifier, Index, Map, SyntaxNode, Type, Value, }; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] @@ -14,7 +15,7 @@ pub enum IndexExpression { } impl AbstractTree for IndexExpression { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { Error::expect_syntax_node(source, "index_expression", node)?; let first_child = node.child(0).unwrap(); @@ -48,16 +49,7 @@ impl AbstractTree for IndexExpression { Ok(abstract_node) } - fn run(&self, source: &str, context: &Map) -> Result { - match self { - IndexExpression::Value(value_node) => value_node.run(source, context), - IndexExpression::Identifier(identifier) => identifier.run(source, context), - IndexExpression::Index(index) => index.run(source, context), - IndexExpression::FunctionCall(function_call) => function_call.run(source, context), - } - } - - fn expected_type(&self, context: &Map) -> Result { + fn expected_type(&self, context: &Map) -> Result { match self { IndexExpression::Value(value_node) => value_node.expected_type(context), IndexExpression::Identifier(identifier) => identifier.expected_type(context), @@ -65,6 +57,26 @@ impl AbstractTree for IndexExpression { IndexExpression::FunctionCall(function_call) => function_call.expected_type(context), } } + + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + match self { + IndexExpression::Value(value_node) => value_node.check_type(_source, _context), + IndexExpression::Identifier(identifier) => identifier.check_type(_source, _context), + IndexExpression::Index(index) => index.check_type(_source, _context), + IndexExpression::FunctionCall(function_call) => { + function_call.check_type(_source, _context) + } + } + } + + fn run(&self, source: &str, context: &Map) -> Result { + match self { + IndexExpression::Value(value_node) => value_node.run(source, context), + IndexExpression::Identifier(identifier) => identifier.run(source, context), + IndexExpression::Index(index) => index.run(source, context), + IndexExpression::FunctionCall(function_call) => function_call.run(source, context), + } + } } impl Format for IndexExpression { diff --git a/src/abstract_tree/logic.rs b/src/abstract_tree/logic.rs index 542c9d8..e7bcbca 100644 --- a/src/abstract_tree/logic.rs +++ b/src/abstract_tree/logic.rs @@ -1,7 +1,8 @@ use serde::{Deserialize, Serialize}; use crate::{ - AbstractTree, Error, Expression, Format, LogicOperator, Map, Result, SyntaxNode, Type, Value, + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Error, Expression, Format, LogicOperator, Map, SyntaxNode, Type, Value, }; /// Abstract representation of a logic expression. @@ -13,7 +14,7 @@ pub struct Logic { } impl AbstractTree for Logic { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { Error::expect_syntax_node(source, "logic", node)?; let first_node = node.child(0).unwrap(); @@ -39,7 +40,16 @@ impl AbstractTree for Logic { }) } - fn run(&self, source: &str, context: &Map) -> Result { + fn expected_type(&self, _context: &Map) -> Result { + Ok(Type::Boolean) + } + + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + self.left.check_type(_source, _context)?; + self.right.check_type(_source, _context) + } + + fn run(&self, source: &str, context: &Map) -> Result { let left = self.left.run(source, context)?; let right = self.right.run(source, context)?; let result = match self.operator { @@ -67,10 +77,6 @@ impl AbstractTree for Logic { Ok(Value::Boolean(result)) } - - fn expected_type(&self, _context: &Map) -> Result { - Ok(Type::Boolean) - } } impl Format for Logic { diff --git a/src/abstract_tree/logic_operator.rs b/src/abstract_tree/logic_operator.rs index 4ec9035..c31fb26 100644 --- a/src/abstract_tree/logic_operator.rs +++ b/src/abstract_tree/logic_operator.rs @@ -1,6 +1,9 @@ use serde::{Deserialize, Serialize}; -use crate::{AbstractTree, Error, Format, Map, Result, SyntaxNode, Type, Value}; +use crate::{ + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Error, Format, Map, SyntaxNode, Type, Value, +}; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] pub enum LogicOperator { @@ -15,7 +18,7 @@ pub enum LogicOperator { } impl AbstractTree for LogicOperator { - fn from_syntax(node: SyntaxNode, source: &str, _context: &Map) -> crate::Result { + fn from_syntax(node: SyntaxNode, source: &str, _context: &Map) -> Result { Error::expect_syntax_node(source, "logic_operator", node)?; let operator_node = node.child(0).unwrap(); @@ -41,12 +44,16 @@ impl AbstractTree for LogicOperator { Ok(operator) } - fn run(&self, _source: &str, _context: &Map) -> Result { - Ok(Value::none()) + fn expected_type(&self, _context: &Map) -> Result { + Ok(Type::None) } - fn expected_type(&self, _context: &Map) -> Result { - Ok(Type::None) + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + Ok(()) + } + + fn run(&self, _source: &str, _context: &Map) -> Result { + Ok(Value::none()) } } diff --git a/src/abstract_tree/match.rs b/src/abstract_tree/match.rs index e86c584..0ad5767 100644 --- a/src/abstract_tree/match.rs +++ b/src/abstract_tree/match.rs @@ -5,7 +5,8 @@ use serde::{Deserialize, Serialize}; use crate::{ - AbstractTree, Error, Expression, Format, Map, Result, Statement, SyntaxNode, Type, Value, + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Error, Expression, Format, Map, Statement, SyntaxNode, Type, Value, }; /// Abstract representation of a match statement. @@ -17,7 +18,7 @@ pub struct Match { } impl AbstractTree for Match { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { Error::expect_syntax_node(source, "match", node)?; let matcher_node = node.child(1).unwrap(); @@ -58,7 +59,28 @@ impl AbstractTree for Match { }) } - fn run(&self, source: &str, context: &Map) -> Result { + fn expected_type(&self, context: &Map) -> Result { + let (_, first_statement) = self.options.first().unwrap(); + + first_statement.expected_type(context) + } + + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + self.matcher.check_type(_source, _context)?; + + for (expression, statement) in self.options { + expression.check_type(_source, _context)?; + statement.check_type(_source, _context)?; + } + + if let Some(statement) = self.fallback { + statement.check_type(_source, _context)?; + } + + Ok(()) + } + + fn run(&self, source: &str, context: &Map) -> Result { let matcher_value = self.matcher.run(source, context)?; for (expression, statement) in &self.options { @@ -75,12 +97,6 @@ impl AbstractTree for Match { Ok(Value::none()) } } - - fn expected_type(&self, context: &Map) -> Result { - let (_, first_statement) = self.options.first().unwrap(); - - first_statement.expected_type(context) - } } impl Format for Match { diff --git a/src/abstract_tree/math.rs b/src/abstract_tree/math.rs index 2a37bf0..c7a80aa 100644 --- a/src/abstract_tree/math.rs +++ b/src/abstract_tree/math.rs @@ -1,7 +1,8 @@ use serde::{Deserialize, Serialize}; use crate::{ - AbstractTree, Error, Expression, Format, Map, MathOperator, Result, SyntaxNode, Type, Value, + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Error, Expression, Format, Map, MathOperator, SyntaxNode, Type, Value, }; /// Abstract representation of a math operation. @@ -16,7 +17,7 @@ pub struct Math { } impl AbstractTree for Math { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { Error::expect_syntax_node(source, "math", node)?; let left_node = node.child(0).unwrap(); @@ -35,7 +36,16 @@ impl AbstractTree for Math { }) } - fn run(&self, source: &str, context: &Map) -> Result { + fn expected_type(&self, context: &Map) -> Result { + self.left.expected_type(context) + } + + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + self.left.check_type(_source, _context)?; + self.right.check_type(_source, _context) + } + + fn run(&self, source: &str, context: &Map) -> Result { let left = self.left.run(source, context)?; let right = self.right.run(source, context)?; let value = match self.operator { @@ -48,10 +58,6 @@ impl AbstractTree for Math { Ok(value) } - - fn expected_type(&self, context: &Map) -> Result { - self.left.expected_type(context) - } } impl Format for Math { diff --git a/src/abstract_tree/math_operator.rs b/src/abstract_tree/math_operator.rs index 8b74fbd..497f7d0 100644 --- a/src/abstract_tree/math_operator.rs +++ b/src/abstract_tree/math_operator.rs @@ -1,6 +1,9 @@ use serde::{Deserialize, Serialize}; -use crate::{AbstractTree, Error, Format, Map, Result, SyntaxNode, Type, Value}; +use crate::{ + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Error, Format, Map, SyntaxNode, Type, Value, +}; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] pub enum MathOperator { @@ -12,7 +15,7 @@ pub enum MathOperator { } impl AbstractTree for MathOperator { - fn from_syntax(node: SyntaxNode, source: &str, _context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, _context: &Map) -> Result { let operator_node = node.child(0).unwrap(); let operator = match operator_node.kind() { "+" => MathOperator::Add, @@ -33,12 +36,16 @@ impl AbstractTree for MathOperator { Ok(operator) } - fn run(&self, _source: &str, _context: &Map) -> Result { - Ok(Value::none()) + fn expected_type(&self, _context: &Map) -> Result { + Ok(Type::None) } - fn expected_type(&self, _context: &Map) -> Result { - Ok(Type::None) + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + Ok(()) + } + + fn run(&self, _source: &str, _context: &Map) -> Result { + Ok(Value::none()) } } diff --git a/src/abstract_tree/mod.rs b/src/abstract_tree/mod.rs index 1808cbc..95f46b0 100644 --- a/src/abstract_tree/mod.rs +++ b/src/abstract_tree/mod.rs @@ -44,7 +44,10 @@ pub use { use serde::{Deserialize, Serialize}; -use crate::{Error, Map, Result, SyntaxNode, Value}; +use crate::{ + error::{RuntimeError, SyntaxError, ValidationError}, + Error, Map, SyntaxNode, Value, +}; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] pub struct SyntaxPosition { @@ -78,7 +81,7 @@ pub struct Root { // instead of indexes. This will be more performant when there are a lot of // top-level statements in the tree. impl AbstractTree for Root { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { Error::expect_syntax_node(source, "root", node)?; let statement_count = node.child_count(); @@ -94,7 +97,7 @@ impl AbstractTree for Root { Ok(Root { statements }) } - fn check_type(&self, _source: &str, _context: &Map) -> Result<()> { + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { for statement in &self.statements { if let Statement::Return(inner_statement) = statement { return inner_statement.check_type(_source, _context); @@ -106,7 +109,7 @@ impl AbstractTree for Root { Ok(()) } - fn run(&self, source: &str, context: &Map) -> Result { + fn run(&self, source: &str, context: &Map) -> Result { let mut value = Value::none(); for statement in &self.statements { @@ -120,7 +123,7 @@ impl AbstractTree for Root { Ok(value) } - fn expected_type(&self, context: &Map) -> Result { + fn expected_type(&self, context: &Map) -> Result { self.statements.last().unwrap().expected_type(context) } } @@ -149,17 +152,15 @@ pub trait AbstractTree: Sized + Format { /// /// If necessary, the source code can be accessed directly by getting the /// node's byte range. - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result; + 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<()> { - Ok(()) - } + 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; + fn run(&self, source: &str, context: &Map) -> Result; - fn expected_type(&self, context: &Map) -> Result; + fn expected_type(&self, context: &Map) -> Result; } pub trait Format { diff --git a/src/abstract_tree/new.rs b/src/abstract_tree/new.rs index 93a4d7e..a517d66 100644 --- a/src/abstract_tree/new.rs +++ b/src/abstract_tree/new.rs @@ -2,7 +2,8 @@ use serde::{Deserialize, Serialize}; use tree_sitter::Node; use crate::{ - AbstractTree, Format, Identifier, Map, Result, Type, TypeSpecification, Value, ValueNode, + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Format, Identifier, Map, Type, TypeSpecification, Value, ValueNode, }; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] @@ -12,7 +13,7 @@ pub struct New { } impl AbstractTree for New { - fn from_syntax(node: Node, source: &str, context: &Map) -> Result { + fn from_syntax(node: Node, source: &str, context: &Map) -> Result { let identifier_node = node.child(1).unwrap(); let identifier = Identifier::from_syntax(identifier_node, source, context)?; @@ -24,11 +25,15 @@ impl AbstractTree for New { }) } - fn run(&self, _source: &str, _context: &crate::Map) -> crate::Result { + fn expected_type(&self, _context: &Map) -> Result { todo!() } - fn expected_type(&self, _context: &crate::Map) -> crate::Result { + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + todo!() + } + + fn run(&self, _source: &str, _context: &Map) -> Result { todo!() } } diff --git a/src/abstract_tree/statement.rs b/src/abstract_tree/statement.rs index 4054ad2..db1cc23 100644 --- a/src/abstract_tree/statement.rs +++ b/src/abstract_tree/statement.rs @@ -1,8 +1,9 @@ use serde::{Deserialize, Serialize}; use crate::{ + error::{RuntimeError, SyntaxError, ValidationError}, AbstractTree, Assignment, Block, Error, Expression, For, Format, IfElse, IndexAssignment, Map, - Match, Result, SyntaxNode, Type, Value, While, + Match, SyntaxNode, Type, Value, While, }; /// Abstract representation of a statement. @@ -20,7 +21,7 @@ pub enum Statement { } impl AbstractTree for Statement { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { Error::expect_syntax_node(source, "statement", node)?; let child = node.child(0).unwrap(); @@ -65,7 +66,21 @@ impl AbstractTree for Statement { } } - fn check_type(&self, _source: &str, _context: &Map) -> Result<()> { + fn expected_type(&self, context: &Map) -> Result { + match self { + Statement::Assignment(assignment) => assignment.expected_type(context), + Statement::Expression(expression) => expression.expected_type(context), + Statement::IfElse(if_else) => if_else.expected_type(context), + Statement::Match(r#match) => r#match.expected_type(context), + Statement::While(r#while) => r#while.expected_type(context), + Statement::Block(block) => block.expected_type(context), + Statement::For(r#for) => r#for.expected_type(context), + Statement::IndexAssignment(index_assignment) => index_assignment.expected_type(context), + Statement::Return(statement) => statement.expected_type(context), + } + } + + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { match self { Statement::Assignment(assignment) => assignment.check_type(_source, _context), Statement::Expression(expression) => expression.check_type(_source, _context), @@ -81,7 +96,7 @@ impl AbstractTree for Statement { } } - fn run(&self, source: &str, context: &Map) -> Result { + fn run(&self, source: &str, context: &Map) -> Result { match self { Statement::Assignment(assignment) => assignment.run(source, context), Statement::Expression(expression) => expression.run(source, context), @@ -94,20 +109,6 @@ impl AbstractTree for Statement { Statement::Return(statement) => statement.run(source, context), } } - - fn expected_type(&self, context: &Map) -> Result { - match self { - Statement::Assignment(assignment) => assignment.expected_type(context), - Statement::Expression(expression) => expression.expected_type(context), - Statement::IfElse(if_else) => if_else.expected_type(context), - Statement::Match(r#match) => r#match.expected_type(context), - Statement::While(r#while) => r#while.expected_type(context), - Statement::Block(block) => block.expected_type(context), - Statement::For(r#for) => r#for.expected_type(context), - Statement::IndexAssignment(index_assignment) => index_assignment.expected_type(context), - Statement::Return(statement) => statement.expected_type(context), - } - } } impl Format for Statement { diff --git a/src/abstract_tree/type.rs b/src/abstract_tree/type.rs index eaf9618..7aa8b2a 100644 --- a/src/abstract_tree/type.rs +++ b/src/abstract_tree/type.rs @@ -2,7 +2,10 @@ use std::fmt::{self, Display, Formatter}; use serde::{Deserialize, Serialize}; -use crate::{AbstractTree, Error, Format, Identifier, Map, Result, Structure, SyntaxNode, Value}; +use crate::{ + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Error, Format, Identifier, Map, Structure, SyntaxNode, Value, +}; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] pub enum Type { @@ -41,7 +44,7 @@ impl Type { Type::Option(Box::new(optional_type)) } - pub fn check(&self, other: &Type) -> Result<()> { + pub fn check(&self, other: &Type) -> Result<(), ValidationError> { log::info!("Checking type {self} against {other}."); match (self, other) { @@ -153,7 +156,7 @@ impl Type { } impl AbstractTree for Type { - fn from_syntax(node: SyntaxNode, _source: &str, _context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, _source: &str, _context: &Map) -> Result { Error::expect_syntax_node(_source, "type", node)?; let type_node = node.child(0).unwrap(); @@ -219,12 +222,16 @@ impl AbstractTree for Type { Ok(r#type) } - fn run(&self, _source: &str, _context: &Map) -> Result { - Ok(Value::none()) + fn expected_type(&self, _context: &Map) -> Result { + Ok(Type::None) } - fn expected_type(&self, _context: &Map) -> Result { - Ok(Type::None) + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + Ok(()) + } + + fn run(&self, _source: &str, _context: &Map) -> Result { + Ok(Value::none()) } } diff --git a/src/abstract_tree/type_specification.rs b/src/abstract_tree/type_specification.rs index c1ed7ff..f5aa116 100644 --- a/src/abstract_tree/type_specification.rs +++ b/src/abstract_tree/type_specification.rs @@ -1,6 +1,9 @@ use serde::{Deserialize, Serialize}; -use crate::{AbstractTree, Error, Format, Map, Result, SyntaxNode, Type, Value}; +use crate::{ + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Error, Format, Map, SyntaxNode, Type, Value, +}; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] pub struct TypeSpecification { @@ -22,7 +25,7 @@ impl TypeSpecification { } impl AbstractTree for TypeSpecification { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { Error::expect_syntax_node(source, "type_specification", node)?; let type_node = node.child(1).unwrap(); @@ -31,12 +34,16 @@ impl AbstractTree for TypeSpecification { Ok(TypeSpecification { r#type }) } - fn run(&self, source: &str, context: &Map) -> Result { - self.r#type.run(source, context) + fn expected_type(&self, context: &Map) -> Result { + self.r#type.expected_type(context) } - fn expected_type(&self, context: &Map) -> Result { - self.r#type.expected_type(context) + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + Ok(()) + } + + fn run(&self, source: &str, context: &Map) -> Result { + self.r#type.run(source, context) } } diff --git a/src/abstract_tree/value_node.rs b/src/abstract_tree/value_node.rs index 6edf918..1c1e912 100644 --- a/src/abstract_tree/value_node.rs +++ b/src/abstract_tree/value_node.rs @@ -1,14 +1,11 @@ -use std::{ - cmp::Ordering, - collections::BTreeMap, - ops::{Range, RangeInclusive}, -}; +use std::{cmp::Ordering, collections::BTreeMap, ops::RangeInclusive}; use serde::{Deserialize, Serialize}; use crate::{ + error::{RuntimeError, SyntaxError, ValidationError}, AbstractTree, BuiltInValue, Error, Expression, Format, Function, FunctionNode, Identifier, - List, Map, Result, Statement, Structure, SyntaxNode, Type, TypeSpecification, Value, + List, Map, Statement, Structure, SyntaxNode, Type, TypeSpecification, Value, }; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] @@ -27,7 +24,7 @@ pub enum ValueNode { } impl AbstractTree for ValueNode { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { Error::expect_syntax_node(source, "value", node)?; let child = node.child(0).unwrap(); @@ -189,7 +186,59 @@ impl AbstractTree for ValueNode { Ok(value_node) } - fn check_type(&self, _source: &str, _context: &Map) -> Result<()> { + fn expected_type(&self, context: &Map) -> Result { + let r#type = match self { + ValueNode::Boolean(_) => Type::Boolean, + ValueNode::Float(_) => Type::Float, + ValueNode::Function(function) => function.r#type().clone(), + ValueNode::Integer(_) => Type::Integer, + ValueNode::String(_) => Type::String, + ValueNode::List(expressions) => { + let mut previous_type = None; + + for expression in expressions { + let expression_type = expression.expected_type(context)?; + + if let Some(previous) = previous_type { + if expression_type != previous { + return Ok(Type::List(Box::new(Type::Any))); + } + } + + previous_type = Some(expression_type); + } + + if let Some(previous) = previous_type { + Type::List(Box::new(previous)) + } else { + Type::List(Box::new(Type::Any)) + } + } + ValueNode::Option(option) => { + if let Some(expression) = option { + Type::Option(Box::new(expression.expected_type(context)?)) + } else { + Type::None + } + } + ValueNode::Map(_) => Type::Map(None), + ValueNode::BuiltInValue(built_in_value) => built_in_value.expected_type(context)?, + ValueNode::Structure(node_map) => { + let mut value_map = BTreeMap::new(); + + for (key, (_statement_option, r#type)) in node_map { + value_map.insert(key.to_string(), (None, r#type.clone())); + } + + Type::Map(Some(Structure::new(value_map))) + } + ValueNode::Range(_) => Type::Range, + }; + + Ok(r#type) + } + + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { match self { ValueNode::Function(function) => { if let Function::ContextDefined(function_node) = function { @@ -202,7 +251,7 @@ impl AbstractTree for ValueNode { Ok(()) } - fn run(&self, source: &str, context: &Map) -> Result { + fn run(&self, source: &str, context: &Map) -> Result { let value = match self { ValueNode::Boolean(value_source) => Value::Boolean(value_source.parse().unwrap()), ValueNode::Float(value_source) => { @@ -267,58 +316,6 @@ impl AbstractTree for ValueNode { Ok(value) } - - fn expected_type(&self, context: &Map) -> Result { - let r#type = match self { - ValueNode::Boolean(_) => Type::Boolean, - ValueNode::Float(_) => Type::Float, - ValueNode::Function(function) => function.r#type().clone(), - ValueNode::Integer(_) => Type::Integer, - ValueNode::String(_) => Type::String, - ValueNode::List(expressions) => { - let mut previous_type = None; - - for expression in expressions { - let expression_type = expression.expected_type(context)?; - - if let Some(previous) = previous_type { - if expression_type != previous { - return Ok(Type::List(Box::new(Type::Any))); - } - } - - previous_type = Some(expression_type); - } - - if let Some(previous) = previous_type { - Type::List(Box::new(previous)) - } else { - Type::List(Box::new(Type::Any)) - } - } - ValueNode::Option(option) => { - if let Some(expression) = option { - Type::Option(Box::new(expression.expected_type(context)?)) - } else { - Type::None - } - } - ValueNode::Map(_) => Type::Map(None), - ValueNode::BuiltInValue(built_in_value) => built_in_value.expected_type(context)?, - ValueNode::Structure(node_map) => { - let mut value_map = BTreeMap::new(); - - for (key, (_statement_option, r#type)) in node_map { - value_map.insert(key.to_string(), (None, r#type.clone())); - } - - Type::Map(Some(Structure::new(value_map))) - } - ValueNode::Range(_) => Type::Range, - }; - - Ok(r#type) - } } impl Format for ValueNode { diff --git a/src/abstract_tree/while.rs b/src/abstract_tree/while.rs index 664f154..22243f1 100644 --- a/src/abstract_tree/while.rs +++ b/src/abstract_tree/while.rs @@ -1,6 +1,9 @@ use serde::{Deserialize, Serialize}; -use crate::{AbstractTree, Block, Error, Expression, Format, Map, Result, SyntaxNode, Type, Value}; +use crate::{ + error::{RuntimeError, SyntaxError, ValidationError}, + AbstractTree, Block, Error, Expression, Format, Map, SyntaxNode, Type, Value, +}; /// Abstract representation of a while loop. /// @@ -12,7 +15,7 @@ pub struct While { } impl AbstractTree for While { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> crate::Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { Error::expect_syntax_node(source, "while", node)?; let expression_node = node.child(1).unwrap(); @@ -24,17 +27,22 @@ impl AbstractTree for While { Ok(While { expression, block }) } - fn run(&self, source: &str, context: &Map) -> Result { + fn expected_type(&self, context: &Map) -> Result { + self.block.expected_type(context) + } + + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + self.expression.check_type(_source, _context)?; + self.block.check_type(_source, _context) + } + + fn run(&self, source: &str, context: &Map) -> Result { while self.expression.run(source, context)?.as_boolean()? { self.block.run(source, context)?; } Ok(Value::none()) } - - fn expected_type(&self, context: &Map) -> Result { - self.block.expected_type(context) - } } impl Format for While { diff --git a/src/abstract_tree/yield.rs b/src/abstract_tree/yield.rs index 2400828..9657196 100644 --- a/src/abstract_tree/yield.rs +++ b/src/abstract_tree/yield.rs @@ -1,8 +1,9 @@ use serde::{Deserialize, Serialize}; use crate::{ - function_expression::FunctionExpression, AbstractTree, Error, Expression, Format, FunctionCall, - Map, Result, SyntaxNode, Type, Value, + error::{RuntimeError, SyntaxError, ValidationError}, + function_expression::FunctionExpression, + AbstractTree, Error, Expression, Format, FunctionCall, Map, SyntaxNode, Type, Value, }; /// Abstract representation of a yield expression. @@ -14,7 +15,7 @@ pub struct Yield { } impl AbstractTree for Yield { - fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { + fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result { Error::expect_syntax_node(source, "yield", node)?; let input_node = node.child(0).unwrap(); @@ -42,12 +43,16 @@ impl AbstractTree for Yield { Ok(Yield { call }) } - fn run(&self, source: &str, context: &Map) -> Result { - self.call.run(source, context) + fn expected_type(&self, context: &Map) -> Result { + self.call.expected_type(context) } - fn expected_type(&self, context: &Map) -> Result { - self.call.expected_type(context) + fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> { + self.call.check_type(_source, _context) + } + + fn run(&self, source: &str, context: &Map) -> Result { + self.call.run(source, context) } } diff --git a/src/built_in_functions/fs.rs b/src/built_in_functions/fs.rs index 4983d34..ddbb8ac 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, Map, Result, Type, Value}; +use crate::{error::RuntimeError, Error, Map, Type, Value}; use super::Callable; @@ -35,7 +35,12 @@ impl Callable for Fs { } } - fn call(&self, arguments: &[Value], _source: &str, _outer_context: &Map) -> Result { + fn call( + &self, + arguments: &[Value], + _source: &str, + _outer_context: &Map, + ) -> Result { match self { Fs::ReadFile => { Error::expect_argument_amount(self.name(), 1, arguments.len())?; diff --git a/src/built_in_functions/json.rs b/src/built_in_functions/json.rs index fb34548..ebe1c6a 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, Map, Result, Type, Value}; +use crate::{error::RuntimeError, Error, Map, Type, Value}; use super::Callable; @@ -41,7 +41,12 @@ impl Callable for Json { } } - fn call(&self, arguments: &[Value], _source: &str, _outer_context: &Map) -> Result { + fn call( + &self, + arguments: &[Value], + _source: &str, + _outer_context: &Map, + ) -> Result { match self { Json::Create => { Error::expect_argument_amount(self.name(), 1, arguments.len())?; diff --git a/src/built_in_functions/mod.rs b/src/built_in_functions/mod.rs index 45eb7a3..ef17410 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, Format, Map, Result, Type, Value}; +use crate::{error::RuntimeError, Error, Format, Map, Type, Value}; use self::{fs::Fs, json::Json, str::StrFunction}; @@ -15,7 +15,12 @@ pub trait Callable { fn name(&self) -> &'static str; fn description(&self) -> &'static str; fn r#type(&self) -> Type; - fn call(&self, arguments: &[Value], source: &str, outer_context: &Map) -> Result; + fn call( + &self, + arguments: &[Value], + source: &str, + outer_context: &Map, + ) -> Result; } #[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] @@ -78,7 +83,12 @@ impl Callable for BuiltInFunction { } } - fn call(&self, arguments: &[Value], _source: &str, _outer_context: &Map) -> Result { + fn call( + &self, + arguments: &[Value], + _source: &str, + _outer_context: &Map, + ) -> Result { match self { BuiltInFunction::AssertEqual => { Error::expect_argument_amount(self.name(), 2, arguments.len())?; diff --git a/src/built_in_functions/str.rs b/src/built_in_functions/str.rs index 2b53dd5..29f03cb 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, List, Map, Result, Type, Value}; +use crate::{error::RuntimeError, Error, List, Map, Type, Value}; use super::Callable; @@ -198,7 +198,12 @@ impl Callable for StrFunction { } } - fn call(&self, arguments: &[Value], _source: &str, _outer_context: &Map) -> Result { + fn call( + &self, + arguments: &[Value], + _source: &str, + _outer_context: &Map, + ) -> Result { let value = match self { StrFunction::AsBytes => { Error::expect_argument_amount(self.name(), 1, arguments.len())?; diff --git a/src/error.rs b/src/error.rs deleted file mode 100644 index 378d024..0000000 --- a/src/error.rs +++ /dev/null @@ -1,468 +0,0 @@ -//! Error and Result types. -//! -//! 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. - -use serde::{Deserialize, Serialize}; -use tree_sitter::{LanguageError, Node, Point}; - -use crate::{value::Value, SyntaxPosition, Type}; - -use std::{ - fmt::{self, Formatter}, - io, - num::ParseFloatError, - string::FromUtf8Error, - sync::PoisonError, - time, -}; - -pub type Result = std::result::Result; - -#[derive(Clone, PartialEq, Serialize, Deserialize)] -pub enum Error { - AtSourcePosition { - error: Box, - source: String, - start_row: usize, - start_column: usize, - end_row: usize, - end_column: usize, - }, - - UnexpectedSyntaxNode { - expected: String, - actual: String, - #[serde(skip)] - location: Point, - relevant_source: String, - }, - - TypeCheck { - expected: Type, - actual: Type, - }, - - TypeCheckExpectedFunction { - actual: Type, - }, - - /// The 'assert' macro did not resolve successfully. - AssertEqualFailed { - expected: Value, - actual: Value, - }, - - /// The 'assert' macro did not resolve successfully. - AssertFailed, - - /// A row was inserted to a table with the wrong amount of values. - WrongColumnAmount { - expected: usize, - actual: usize, - }, - - /// An operator was called with the wrong amount of arguments. - ExpectedOperatorArgumentAmount { - expected: usize, - actual: usize, - }, - - /// A 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, - }, - - ExpectedFunctionType { - actual: Type, - }, - - ExpectedString { - actual: Value, - }, - - ExpectedInteger { - actual: Value, - }, - - ExpectedFloat { - actual: Value, - }, - - /// An integer, floating point or value was expected. - ExpectedNumber { - actual: Value, - }, - - /// An integer, floating point or string value was expected. - ExpectedNumberOrString { - actual: Value, - }, - - ExpectedBoolean { - actual: Value, - }, - - ExpectedList { - actual: Value, - }, - - ExpectedMinLengthList { - minimum_len: usize, - actual_len: usize, - }, - - ExpectedFixedLenList { - expected_len: usize, - actual: Value, - }, - - ExpectedNone { - actual: Value, - }, - - ExpectedMap { - actual: Value, - }, - - ExpectedTable { - actual: Value, - }, - - ExpectedFunction { - actual: Value, - }, - - ExpectedOption { - actual: Value, - }, - - /// A string, list, map or table value was expected. - ExpectedCollection { - actual: Value, - }, - - /// Failed to find a variable with a value for this key. - VariableIdentifierNotFound(String), - - /// 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, - }, -} - -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, actual: Node) -> Result<()> { - log::info!("Converting {} to abstract node", actual.kind()); - - if expected == actual.kind() { - Ok(()) - } else if actual.is_error() { - Err(Error::Syntax { - source: source[actual.byte_range()].to_string(), - location: actual.start_position(), - }) - } else { - Err(Error::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<()> { - 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: 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()) - } -} - -impl std::error::Error for Error {} - -impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{self}") - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - use Error::*; - - match self { - AssertEqualFailed { expected, actual } => { - write!( - f, - "Equality assertion failed. {expected} does not equal {actual}." - ) - } - AssertFailed => write!( - f, - "Assertion failed. A false value was passed to \"assert\"." - ), - ExpectedOperatorArgumentAmount { expected, actual } => write!( - f, - "An operator expected {} arguments, but got {}.", - expected, actual - ), - 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}." - ) - } - 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}.", - ) - } - VariableIdentifierNotFound(key) => write!(f, "Variable {key} does not exist.",), - UnexpectedSyntaxNode { - expected, - actual, - location, - relevant_source, - } => { - let location = get_position(location); - - write!( - f, - "Expected {expected}, but got {actual} at {location}. Code: {relevant_source} ", - ) - } - WrongColumnAmount { expected, actual } => write!( - f, - "Wrong column amount. Expected {expected} but got {actual}." - ), - External(message) => write!(f, "External error: {message}"), - CustomMessage(message) => write!(f, "{message}"), - Syntax { source, location } => { - let location = get_position(location); - - write!(f, "Syntax error at {location}: {source}") - } - TypeCheck { expected, actual } => write!( - f, - "Type check error. Expected type {expected} but got type {actual}." - ), - TypeCheckExpectedFunction { actual } => { - write!(f, "Type check error. Expected a function but got {actual}.") - } - 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 - ) - } - ExpectedFunctionType { actual } => write!(f, "Expected a function but got {actual}."), - ExpectedIterable { actual } => { - write!(f, "Expected an iterable value but got {actual}.") - } - } - } -} - -fn get_position(position: &Point) -> String { - format!("column {}, row {}", position.row + 1, position.column) -} diff --git a/src/error/mod.rs b/src/error/mod.rs new file mode 100644 index 0000000..29925ec --- /dev/null +++ b/src/error/mod.rs @@ -0,0 +1,247 @@ +//! Error and Result types. +//! +//! 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; +mod syntax_error; +mod validation_error; + +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 std::{ + fmt::{self, Formatter}, + io, + num::ParseFloatError, + string::FromUtf8Error, + sync::PoisonError, + time, +}; + +#[derive(Clone, PartialEq, Serialize, Deserialize)] +pub enum Error { + Parsing(SyntaxError), + + Verification(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, + }, +} + +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, + actual: Node, + ) -> Result<(), SyntaxError> { + log::info!("Converting {} to abstract node", actual.kind()); + + if expected == actual.kind() { + Ok(()) + } else if actual.is_error() { + Error::Syntax { + source: source[actual.byte_range()].to_string(), + location: actual.start_position(), + } + } else { + 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: 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()) + } +} + +impl std::error::Error for Error {} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{self}") + } +} + +impl fmt::Display for Error { + 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!(), + Runtime(_) => todo!(), + External(_) => todo!(), + CustomMessage(_) => todo!(), + Syntax { source, location } => todo!(), + } + } +} + +fn get_position(position: &Point) -> String { + format!("column {}, row {}", position.row + 1, position.column) +} diff --git a/src/error/runtime_error.rs b/src/error/runtime_error.rs new file mode 100644 index 0000000..1363700 --- /dev/null +++ b/src/error/runtime_error.rs @@ -0,0 +1,181 @@ +use std::fmt::{self, Display, Formatter}; + +use serde::{Deserialize, Serialize}; + +use crate::Value; + +#[derive(Clone, PartialEq, Serialize, Deserialize)] +pub enum RuntimeError { + ExpectedString { + actual: Value, + }, + + ExpectedInteger { + actual: Value, + }, + + ExpectedFloat { + actual: Value, + }, + + /// An integer, floating point or value was expected. + ExpectedNumber { + actual: Value, + }, + + /// An integer, floating point or string value was expected. + ExpectedNumberOrString { + actual: Value, + }, + + ExpectedBoolean { + actual: Value, + }, + + ExpectedList { + actual: Value, + }, + + ExpectedMinLengthList { + minimum_len: usize, + actual_len: usize, + }, + + ExpectedFixedLenList { + expected_len: usize, + actual: Value, + }, + + ExpectedNone { + actual: Value, + }, + + ExpectedMap { + actual: Value, + }, + + ExpectedTable { + actual: Value, + }, + + ExpectedFunction { + actual: Value, + }, + + ExpectedOption { + actual: Value, + }, + + /// A string, list, map or table value was expected. + ExpectedCollection { + actual: Value, + }, + + /// A 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, + 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!(), + } + } +} diff --git a/src/error/syntax_error.rs b/src/error/syntax_error.rs new file mode 100644 index 0000000..35063f5 --- /dev/null +++ b/src/error/syntax_error.rs @@ -0,0 +1,15 @@ +use serde::{Deserialize, Serialize}; +use tree_sitter::Point; + +#[derive(Clone, PartialEq, Serialize, Deserialize)] +pub enum SyntaxError { + UnexpectedSyntaxNode { + expected: String, + actual: String, + + #[serde(skip)] + location: Point, + + relevant_source: String, + }, +} diff --git a/src/error/validation_error.rs b/src/error/validation_error.rs new file mode 100644 index 0000000..4b447b6 --- /dev/null +++ b/src/error/validation_error.rs @@ -0,0 +1,27 @@ +use serde::{Deserialize, Serialize}; + +use crate::{Type, Value}; + +#[derive(Clone, PartialEq, Serialize, Deserialize)] +pub enum ValidationError { + /// The 'assert' macro did not resolve successfully. + AssertEqualFailed { + expected: Value, + actual: Value, + }, + + /// The 'assert' macro did not resolve successfully. + AssertFailed, + + TypeCheck { + expected: Type, + actual: Type, + }, + + TypeCheckExpectedFunction { + actual: Type, + }, + + /// Failed to find a variable with a value for this key. + VariableIdentifierNotFound(String), +} diff --git a/src/interpret.rs b/src/interpret.rs index ddc16b0..57ce972 100644 --- a/src/interpret.rs +++ b/src/interpret.rs @@ -37,13 +37,16 @@ //! ``` use tree_sitter::{Node as SyntaxNode, Parser, Tree as SyntaxTree, TreeCursor}; -use crate::{language, AbstractTree, Error, Format, Map, Result, Root, Value}; +use crate::{ + error::{RuntimeError, SyntaxError, ValidationError}, + language, AbstractTree, Error, Format, Map, Root, Value, +}; /// Interpret the given source code. Returns the value of last statement or the /// first error encountered. /// /// See the [module-level docs][self] for more info. -pub fn interpret(source: &str) -> Result { +pub fn interpret(source: &str) -> Result { interpret_with_context(source, Map::new()) } @@ -55,7 +58,7 @@ pub fn interpret(source: &str) -> Result { /// maps. /// /// See the [module-level docs][self] for more info. -pub fn interpret_with_context(source: &str, context: Map) -> Result { +pub fn interpret_with_context(source: &str, context: Map) -> Result { let mut interpreter = Interpreter::new(context); let value = interpreter.run(source)?; @@ -93,7 +96,7 @@ impl Interpreter { /// /// Tree sitter is designed to be run on every keystroke, so this is generally a lightweight /// function to call. - pub fn parse(&mut self, source: &str) -> Result { + pub fn parse(&mut self, source: &str) -> Result { if let Some(tree) = self.parser.parse(source, None) { Ok(tree) } else { @@ -109,8 +112,12 @@ impl Interpreter { /// - check the syntax tree for errors /// - generate an abstract tree from the source and syntax tree /// - check the abstract tree for type errors - pub fn verify(&mut self, source: &str) -> Result { - fn check_for_error(node: SyntaxNode, source: &str, cursor: &mut TreeCursor) -> Result<()> { + pub fn verify(&mut self, source: &str) -> Result { + fn check_for_error( + node: SyntaxNode, + source: &str, + cursor: &mut TreeCursor, + ) -> Result<(), ValidationError> { if node.is_error() { Err(Error::Syntax { source: source[node.byte_range()].to_string(), @@ -142,13 +149,13 @@ 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 { + pub fn run(&mut self, source: &str) -> Result { self.verify(source)?.run(source, &self.context) } /// Return an s-expression displaying a syntax tree of the source, or the ParserCancelled error /// if the parser takes too long. - pub fn syntax_tree(&mut self, source: &str) -> Result { + pub fn syntax_tree(&mut self, source: &str) -> Result { Ok(self.parse(source)?.root_node().to_sexp()) } @@ -157,7 +164,7 @@ impl Interpreter { /// /// You should call [verify][Interpreter::verify] before calling this function. You can only /// create formatted source from a valid abstract tree. - pub fn format(&mut self, source: &str) -> Result { + pub fn format(&mut self, source: &str) -> Result { let mut formatted_output = String::new(); self.verify(source)?.format(&mut formatted_output, 0); diff --git a/src/lib.rs b/src/lib.rs index b9b3593..7c50ec8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ //! You can use this library externally by calling either of the "interpret" //! functions or by constructing your own Interpreter. pub use crate::{ - abstract_tree::*, built_in_functions::BuiltInFunction, error::*, interpret::*, value::*, + abstract_tree::*, built_in_functions::BuiltInFunction, error::Error, interpret::*, value::*, }; pub use tree_sitter::Node as SyntaxNode; diff --git a/src/value/function.rs b/src/value/function.rs index 9f8c4c3..9690db7 100644 --- a/src/value/function.rs +++ b/src/value/function.rs @@ -3,7 +3,8 @@ use std::fmt::{self, Display, Formatter}; use serde::{Deserialize, Serialize}; use crate::{ - built_in_functions::Callable, BuiltInFunction, Format, FunctionNode, Map, Result, Type, Value, + built_in_functions::Callable, error::RuntimeError, BuiltInFunction, Format, FunctionNode, Map, + Type, Value, }; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] @@ -13,7 +14,12 @@ pub enum Function { } impl Function { - pub fn call(&self, arguments: &[Value], source: &str, outer_context: &Map) -> Result { + pub fn call( + &self, + arguments: &[Value], + source: &str, + outer_context: &Map, + ) -> Result { match self { Function::BuiltIn(built_in_function) => { built_in_function.call(arguments, source, outer_context) diff --git a/src/value/map.rs b/src/value/map.rs index ed30e2e..ae8ec8f 100644 --- a/src/value/map.rs +++ b/src/value/map.rs @@ -13,10 +13,12 @@ use std::{ collections::BTreeMap, fmt::{self, Display, Formatter}, marker::PhantomData, - sync::{Arc, RwLock, RwLockReadGuard}, + sync::{Arc, PoisonError, RwLock, RwLockReadGuard}, }; -use crate::{value::Value, Result, Structure, Type}; +use crate::{value::Value, Structure, Type}; + +pub type MapAccessError<'a> = PoisonError>>; /// A collection dust variables comprised of key-value pairs. /// @@ -63,7 +65,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() { @@ -76,11 +78,13 @@ impl Map { }) } - pub fn variables(&self) -> Result>> { - Ok(self.variables.read()?) + pub fn variables( + &self, + ) -> Result>, MapAccessError> { + self.variables.read() } - pub fn set(&self, key: String, value: Value) -> Result> { + pub fn set(&self, key: String, value: Value) -> Result, MapAccessError> { log::info!("Setting variable {key} = {value}"); let value_type = value.r#type(); @@ -92,7 +96,7 @@ impl Map { Ok(previous) } - pub fn set_type(&self, key: String, r#type: Type) -> Result> { + pub fn set_type(&self, key: String, r#type: Type) -> Result, ()> { log::info!("Setting type {key} = {}", r#type); let previous = self.variables.write()?.insert(key, (Value::none(), r#type)); diff --git a/src/value/mod.rs b/src/value/mod.rs index 3a0c3b5..6c62da4 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -1,6 +1,6 @@ //! Types that represent runtime values. use crate::{ - error::{Error, Result}, + error::{Error, RuntimeError}, Identifier, Type, TypeSpecification, }; @@ -15,7 +15,7 @@ use std::{ convert::TryFrom, fmt::{self, Display, Formatter}, marker::PhantomData, - ops::{Add, AddAssign, Div, Mul, Range, RangeInclusive, Rem, Sub, SubAssign}, + ops::{Add, AddAssign, Div, Mul, RangeInclusive, Rem, Sub, SubAssign}, }; pub use self::{function::Function, list::List, map::Map, structure::Structure}; @@ -164,7 +164,7 @@ impl Value { } /// Borrows the value stored in `self` as `&String`, or returns `Err` if `self` is not a `Value::String`. - pub fn as_string(&self) -> Result<&String> { + pub fn as_string(&self) -> Result<&String, RuntimeError> { match self { Value::String(string) => Ok(string), value => Err(Error::ExpectedString { @@ -174,7 +174,7 @@ impl Value { } /// Copies the value stored in `self` as `i64`, or returns `Err` if `self` is not a `Value::Int` - pub fn as_integer(&self) -> Result { + pub fn as_integer(&self) -> Result { match self { Value::Integer(i) => Ok(*i), value => Err(Error::ExpectedInteger { @@ -184,7 +184,7 @@ impl Value { } /// Copies the value stored in `self` as `f64`, or returns `Err` if `self` is not a `Primitive::Float`. - pub fn as_float(&self) -> Result { + pub fn as_float(&self) -> Result { match self { Value::Float(f) => Ok(*f), value => Err(Error::ExpectedFloat { @@ -195,7 +195,7 @@ impl Value { /// Copies the value stored in `self` as `f64`, or returns `Err` if `self` is not a `Primitive::Float` or `Value::Int`. /// Note that this method silently converts `i64` to `f64`, if `self` is a `Value::Int`. - pub fn as_number(&self) -> Result { + pub fn as_number(&self) -> Result { match self { Value::Float(f) => Ok(*f), Value::Integer(i) => Ok(*i as f64), @@ -206,7 +206,7 @@ impl Value { } /// Copies the value stored in `self` as `bool`, or returns `Err` if `self` is not a `Primitive::Boolean`. - pub fn as_boolean(&self) -> Result { + pub fn as_boolean(&self) -> Result { match self { Value::Boolean(boolean) => Ok(*boolean), value => Err(Error::ExpectedBoolean { @@ -216,7 +216,7 @@ impl Value { } /// Borrows the value stored in `self` as `Vec`, or returns `Err` if `self` is not a `Value::List`. - pub fn as_list(&self) -> Result<&List> { + pub fn as_list(&self) -> Result<&List, RuntimeError> { match self { Value::List(list) => Ok(list), value => Err(Error::ExpectedList { @@ -226,7 +226,7 @@ impl Value { } /// Takes ownership of the value stored in `self` as `Vec`, or returns `Err` if `self` is not a `Value::List`. - pub fn into_inner_list(self) -> Result { + pub fn into_inner_list(self) -> Result { match self { Value::List(list) => Ok(list), value => Err(Error::ExpectedList { @@ -236,7 +236,7 @@ impl Value { } /// Borrows the value stored in `self` as `Vec`, or returns `Err` if `self` is not a `Value::Map`. - pub fn as_map(&self) -> Result<&Map> { + pub fn as_map(&self) -> Result<&Map, RuntimeError> { match self { Value::Map(map) => Ok(map), value => Err(Error::ExpectedMap { @@ -247,7 +247,7 @@ impl Value { /// Borrows the value stored in `self` as `Function`, or returns `Err` if /// `self` is not a `Value::Function`. - pub fn as_function(&self) -> Result<&Function> { + pub fn as_function(&self) -> Result<&Function, RuntimeError> { match self { Value::Function(function) => Ok(function), value => Err(Error::ExpectedFunction { @@ -257,7 +257,7 @@ impl Value { } /// Returns `Option`, or returns `Err` if `self` is not a `Value::Option`. - pub fn as_option(&self) -> Result<&Option>> { + pub fn as_option(&self) -> Result<&Option>, RuntimeError> { match self { Value::Option(option) => Ok(option), value => Err(Error::ExpectedOption { @@ -267,7 +267,7 @@ impl Value { } /// Returns `()`, or returns `Err` if `self` is not a `Value::none()`. - pub fn as_none(&self) -> Result<()> { + pub fn as_none(&self) -> Result<(), RuntimeError> { match self { Value::Option(option) => { if option.is_none() { @@ -292,7 +292,7 @@ impl Default for &Value { } impl Add for Value { - type Output = Result; + type Output = Result; fn add(self, other: Self) -> Self::Output { if let (Ok(left), Ok(right)) = (self.as_integer(), other.as_integer()) { @@ -326,7 +326,7 @@ impl Add for Value { } impl Sub for Value { - type Output = Result; + type Output = Result; fn sub(self, other: Self) -> Self::Output { if let (Ok(left), Ok(right)) = (self.as_integer(), other.as_integer()) { @@ -346,7 +346,7 @@ impl Sub for Value { } impl Mul for Value { - type Output = Result; + type Output = Result; fn mul(self, other: Self) -> Self::Output { if let (Ok(left), Ok(right)) = (self.as_integer(), other.as_integer()) { @@ -362,7 +362,7 @@ impl Mul for Value { } impl Div for Value { - type Output = Result; + type Output = Result; fn div(self, other: Self) -> Self::Output { if let (Ok(left), Ok(right)) = (self.as_number(), other.as_number()) { @@ -383,7 +383,7 @@ impl Div for Value { } impl Rem for Value { - type Output = Result; + type Output = Result; fn rem(self, other: Self) -> Self::Output { let left = self.as_integer()?; @@ -583,7 +583,7 @@ impl From> for Value { } } -impl From for Result { +impl From for Result { fn from(value: Value) -> Self { Ok(value) }