Begin error overhaul
This commit is contained in:
parent
cd4296c941
commit
7f849f13a3
@ -1,8 +1,9 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AbstractTree, AssignmentOperator, Error, Format, Identifier, Map, Result, Statement,
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
SyntaxNode, SyntaxPosition, Type, TypeSpecification, Value,
|
AbstractTree, AssignmentOperator, Error, Format, Identifier, Map, Statement, SyntaxNode,
|
||||||
|
SyntaxPosition, Type, TypeSpecification, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Variable assignment, including add-assign and subtract-assign operations.
|
/// Variable assignment, including add-assign and subtract-assign operations.
|
||||||
@ -17,7 +18,11 @@ pub struct Assignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Assignment {
|
impl AbstractTree for Assignment {
|
||||||
fn from_syntax(syntax_node: SyntaxNode, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(
|
||||||
|
syntax_node: SyntaxNode,
|
||||||
|
source: &str,
|
||||||
|
context: &Map,
|
||||||
|
) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "assignment", syntax_node)?;
|
Error::expect_syntax_node(source, "assignment", syntax_node)?;
|
||||||
|
|
||||||
let child_count = syntax_node.child_count();
|
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)?;
|
let actual_type = self.statement.expected_type(context)?;
|
||||||
|
|
||||||
if let Some(type_specification) = &self.type_specification {
|
if let Some(type_specification) = &self.type_specification {
|
||||||
@ -103,7 +108,7 @@ impl AbstractTree for Assignment {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &Map) -> Result<Value, RuntimeError> {
|
||||||
let key = self.identifier.inner();
|
let key = self.identifier.inner();
|
||||||
let value = self.statement.run(source, context)?;
|
let value = self.statement.run(source, context)?;
|
||||||
|
|
||||||
@ -113,7 +118,9 @@ impl AbstractTree for Assignment {
|
|||||||
previous_value += value;
|
previous_value += value;
|
||||||
previous_value
|
previous_value
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::VariableIdentifierNotFound(key.clone()));
|
return Err(Error::Runtime(RuntimeError::VariableIdentifierNotFound(
|
||||||
|
key.clone(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssignmentOperator::MinusEqual => {
|
AssignmentOperator::MinusEqual => {
|
||||||
@ -121,7 +128,9 @@ impl AbstractTree for Assignment {
|
|||||||
previous_value -= value;
|
previous_value -= value;
|
||||||
previous_value
|
previous_value
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::VariableIdentifierNotFound(key.clone()));
|
return Err(Error::Runtime(RuntimeError::VariableIdentifierNotFound(
|
||||||
|
key.clone(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssignmentOperator::Equal => value,
|
AssignmentOperator::Equal => value,
|
||||||
@ -132,7 +141,7 @@ impl AbstractTree for Assignment {
|
|||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
fn expected_type(&self, _context: &Map) -> Result<Type, ValidationError> {
|
||||||
Ok(Type::None)
|
Ok(Type::None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
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.
|
/// Operators that be used in an assignment statement.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
@ -11,7 +14,11 @@ pub enum AssignmentOperator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for AssignmentOperator {
|
impl AbstractTree for AssignmentOperator {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, _context: &crate::Map) -> Result<Self> {
|
fn from_syntax(
|
||||||
|
node: SyntaxNode,
|
||||||
|
source: &str,
|
||||||
|
_context: &crate::Map,
|
||||||
|
) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "assignment_operator", node)?;
|
Error::expect_syntax_node(source, "assignment_operator", node)?;
|
||||||
|
|
||||||
let operator_node = node.child(0).unwrap();
|
let operator_node = node.child(0).unwrap();
|
||||||
@ -32,13 +39,17 @@ impl AbstractTree for AssignmentOperator {
|
|||||||
Ok(operator)
|
Ok(operator)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
fn run(&self, _source: &str, _context: &Map) -> Result<Value, RuntimeError> {
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
fn expected_type(&self, _context: &Map) -> Result<Type, ValidationError> {
|
||||||
Ok(Type::None)
|
Ok(Type::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format for AssignmentOperator {
|
impl Format for AssignmentOperator {
|
||||||
|
@ -3,7 +3,10 @@ use std::sync::RwLock;
|
|||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
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.
|
/// Abstract representation of a block.
|
||||||
///
|
///
|
||||||
@ -20,7 +23,7 @@ pub struct Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Block {
|
impl AbstractTree for Block {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "block", node)?;
|
Error::expect_syntax_node(source, "block", node)?;
|
||||||
|
|
||||||
let first_child = node.child(0).unwrap();
|
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 {
|
for statement in &self.statements {
|
||||||
if let Statement::Return(inner_statement) = statement {
|
if let Statement::Return(inner_statement) = statement {
|
||||||
return inner_statement.check_type(_source, _context);
|
return inner_statement.check_type(_source, _context);
|
||||||
@ -61,7 +64,7 @@ impl AbstractTree for Block {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &Map) -> Result<Value, RuntimeError> {
|
||||||
if self.is_async {
|
if self.is_async {
|
||||||
let statements = &self.statements;
|
let statements = &self.statements;
|
||||||
let final_result = RwLock::new(Ok(Value::none()));
|
let final_result = RwLock::new(Ok(Value::none()));
|
||||||
@ -110,7 +113,7 @@ impl AbstractTree for Block {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type, ValidationError> {
|
||||||
if let Some(statement) = self.statements.iter().find(|statement| {
|
if let Some(statement) = self.statements.iter().find(|statement| {
|
||||||
if let Statement::Return(_) = statement {
|
if let Statement::Return(_) = statement {
|
||||||
true
|
true
|
||||||
|
@ -5,7 +5,8 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
built_in_functions::{fs::fs_functions, json::json_functions, str::string_functions, Callable},
|
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<Value> = OnceLock::new();
|
static ARGS: OnceLock<Value> = OnceLock::new();
|
||||||
@ -174,7 +175,7 @@ impl BuiltInValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for BuiltInValue {
|
impl AbstractTree for BuiltInValue {
|
||||||
fn from_syntax(node: SyntaxNode, _source: &str, _context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, _source: &str, _context: &Map) -> Result<Self, SyntaxError> {
|
||||||
let built_in_value = match node.kind() {
|
let built_in_value = match node.kind() {
|
||||||
"args" => BuiltInValue::Args,
|
"args" => BuiltInValue::Args,
|
||||||
"assert_equal" => BuiltInValue::AssertEqual,
|
"assert_equal" => BuiltInValue::AssertEqual,
|
||||||
@ -190,12 +191,16 @@ impl AbstractTree for BuiltInValue {
|
|||||||
Ok(built_in_value)
|
Ok(built_in_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
fn expected_type(&self, _context: &Map) -> Result<Type, ValidationError> {
|
||||||
Ok(self.get().clone())
|
Ok(self.r#type())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> {
|
||||||
Ok(self.r#type())
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, _source: &str, _context: &Map) -> Result<Value, RuntimeError> {
|
||||||
|
Ok(self.get().clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,10 @@ use std::process;
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
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.
|
/// An external program invokation.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
@ -12,7 +15,11 @@ pub struct Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Command {
|
impl AbstractTree for Command {
|
||||||
fn from_syntax(node: tree_sitter::Node, source: &str, _context: &crate::Map) -> Result<Self> {
|
fn from_syntax(
|
||||||
|
node: tree_sitter::Node,
|
||||||
|
source: &str,
|
||||||
|
_context: &crate::Map,
|
||||||
|
) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "command", node)?;
|
Error::expect_syntax_node(source, "command", node)?;
|
||||||
|
|
||||||
let command_text_node = node.child(1).unwrap();
|
let command_text_node = node.child(1).unwrap();
|
||||||
@ -40,7 +47,15 @@ impl AbstractTree for Command {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
fn expected_type(&self, _context: &Map) -> Result<Type, ValidationError> {
|
||||||
|
Ok(Type::String)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, _source: &str, _context: &Map) -> Result<Value, RuntimeError> {
|
||||||
let output = process::Command::new(&self.command_text)
|
let output = process::Command::new(&self.command_text)
|
||||||
.args(&self.command_arguments)
|
.args(&self.command_arguments)
|
||||||
.spawn()?
|
.spawn()?
|
||||||
@ -50,10 +65,6 @@ impl AbstractTree for Command {
|
|||||||
|
|
||||||
Ok(Value::String(string))
|
Ok(Value::String(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
|
||||||
Ok(Type::String)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format for Command {
|
impl Format for Command {
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
value_node::ValueNode, AbstractTree, Command, Error, Format, FunctionCall, Identifier, Index,
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
Logic, Map, Math, New, Result, SyntaxNode, Type, Value, Yield,
|
value_node::ValueNode,
|
||||||
|
AbstractTree, Command, Error, Format, FunctionCall, Identifier, Index, Logic, Map, Math, New,
|
||||||
|
SyntaxNode, Type, Value, Yield,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Abstract representation of an expression statement.
|
/// Abstract representation of an expression statement.
|
||||||
@ -24,7 +26,7 @@ pub enum Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Expression {
|
impl AbstractTree for Expression {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, _context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, _context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "expression", node)?;
|
Error::expect_syntax_node(source, "expression", node)?;
|
||||||
|
|
||||||
let child = if node.child(0).unwrap().is_named() {
|
let child = if node.child(0).unwrap().is_named() {
|
||||||
@ -62,7 +64,21 @@ impl AbstractTree for Expression {
|
|||||||
Ok(expression)
|
Ok(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
fn expected_type(&self, _context: &Map) -> Result<Type, ValidationError> {
|
||||||
|
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 {
|
match self {
|
||||||
Expression::Value(value_node) => value_node.check_type(_source, _context),
|
Expression::Value(value_node) => value_node.check_type(_source, _context),
|
||||||
Expression::Identifier(identifier) => identifier.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<Value> {
|
fn run(&self, _source: &str, _context: &Map) -> Result<Value, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Expression::Value(value_node) => value_node.run(_source, _context),
|
Expression::Value(value_node) => value_node.run(_source, _context),
|
||||||
Expression::Identifier(identifier) => identifier.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),
|
Expression::Command(command) => command.run(_source, _context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
|
||||||
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 {
|
impl Format for Expression {
|
||||||
|
@ -2,8 +2,8 @@ use rayon::prelude::*;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AbstractTree, Block, Error, Expression, Format, Identifier, Map, Result, SyntaxNode, Type,
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
Value,
|
AbstractTree, Block, Error, Expression, Format, Identifier, Map, SyntaxNode, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Abstract representation of a for loop statement.
|
/// Abstract representation of a for loop statement.
|
||||||
@ -16,7 +16,7 @@ pub struct For {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for For {
|
impl AbstractTree for For {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "for", node)?;
|
Error::expect_syntax_node(source, "for", node)?;
|
||||||
|
|
||||||
let for_node = node.child(0).unwrap();
|
let for_node = node.child(0).unwrap();
|
||||||
@ -50,7 +50,15 @@ impl AbstractTree for For {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn expected_type(&self, _context: &Map) -> Result<Type, ValidationError> {
|
||||||
|
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<Value, RuntimeError> {
|
||||||
let expression_run = self.collection.run(source, context)?;
|
let expression_run = self.collection.run(source, context)?;
|
||||||
let key = self.item_id.inner();
|
let key = self.item_id.inner();
|
||||||
|
|
||||||
@ -98,10 +106,6 @@ impl AbstractTree for For {
|
|||||||
|
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
|
||||||
Ok(Type::None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format for For {
|
impl Format for For {
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AbstractTree, Error, Expression, Format, FunctionExpression, Map, Result, SyntaxNode,
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
SyntaxPosition, Type, Value,
|
AbstractTree, Error, Expression, Format, FunctionExpression, Map, SyntaxNode, SyntaxPosition,
|
||||||
|
Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A function being invoked and the arguments it is being passed.
|
/// A function being invoked and the arguments it is being passed.
|
||||||
@ -29,7 +30,7 @@ impl FunctionCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for FunctionCall {
|
impl AbstractTree for FunctionCall {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "function_call", node)?;
|
Error::expect_syntax_node(source, "function_call", node)?;
|
||||||
|
|
||||||
let function_node = node.child(0).unwrap();
|
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<Type, ValidationError> {
|
||||||
|
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 function_expression_type = self.function_expression.expected_type(context)?;
|
||||||
|
|
||||||
let parameter_types = match function_expression_type {
|
let parameter_types = match function_expression_type {
|
||||||
@ -89,7 +120,7 @@ impl AbstractTree for FunctionCall {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &Map) -> Result<Value, RuntimeError> {
|
||||||
let value = match &self.function_expression {
|
let value = match &self.function_expression {
|
||||||
FunctionExpression::Identifier(identifier) => {
|
FunctionExpression::Identifier(identifier) => {
|
||||||
let key = identifier.inner();
|
let key = identifier.inner();
|
||||||
@ -121,36 +152,6 @@ impl AbstractTree for FunctionCall {
|
|||||||
|
|
||||||
value.as_function()?.call(&arguments, source, context)
|
value.as_function()?.call(&arguments, source, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
|
||||||
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 {
|
impl Format for FunctionCall {
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AbstractTree, Error, Format, FunctionCall, Identifier, Index, Map, Result, SyntaxNode, Type,
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
Value, ValueNode, Yield,
|
AbstractTree, Error, Format, FunctionCall, Identifier, Index, Map, SyntaxNode, Type, Value,
|
||||||
|
ValueNode, Yield,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
@ -15,7 +16,7 @@ pub enum FunctionExpression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for FunctionExpression {
|
impl AbstractTree for FunctionExpression {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "function_expression", node)?;
|
Error::expect_syntax_node(source, "function_expression", node)?;
|
||||||
|
|
||||||
let first_child = node.child(0).unwrap();
|
let first_child = node.child(0).unwrap();
|
||||||
@ -51,17 +52,7 @@ impl AbstractTree for FunctionExpression {
|
|||||||
Ok(function_expression)
|
Ok(function_expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn expected_type(&self, context: &Map) -> Result<Type, ValidationError> {
|
||||||
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<Type> {
|
|
||||||
match self {
|
match self {
|
||||||
FunctionExpression::Identifier(identifier) => identifier.expected_type(context),
|
FunctionExpression::Identifier(identifier) => identifier.expected_type(context),
|
||||||
FunctionExpression::FunctionCall(function_call) => function_call.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),
|
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<Value, RuntimeError> {
|
||||||
|
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 {
|
impl Format for FunctionExpression {
|
||||||
|
@ -3,8 +3,9 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AbstractTree, Block, Error, Format, Function, Identifier, Map, Result, SyntaxNode,
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
SyntaxPosition, Type, TypeSpecification, Value,
|
AbstractTree, Block, Error, Format, Function, Identifier, Map, SyntaxNode, SyntaxPosition,
|
||||||
|
Type, TypeSpecification, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
#[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<Value> {
|
pub fn call(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
source: &str,
|
||||||
|
outer_context: &Map,
|
||||||
|
) -> Result<Value, RuntimeError> {
|
||||||
let function_context = Map::new();
|
let function_context = Map::new();
|
||||||
let parameter_argument_pairs = self.parameters.iter().zip(arguments.iter());
|
let parameter_argument_pairs = self.parameters.iter().zip(arguments.iter());
|
||||||
|
|
||||||
@ -79,7 +85,11 @@ impl FunctionNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for FunctionNode {
|
impl AbstractTree for FunctionNode {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, outer_context: &Map) -> Result<Self> {
|
fn from_syntax(
|
||||||
|
node: SyntaxNode,
|
||||||
|
source: &str,
|
||||||
|
outer_context: &Map,
|
||||||
|
) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "function", node)?;
|
Error::expect_syntax_node(source, "function", node)?;
|
||||||
|
|
||||||
let child_count = node.child_count();
|
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<Type, ValidationError> {
|
||||||
|
Ok(self.r#type().clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, source: &str, context: &Map) -> Result<(), ValidationError> {
|
||||||
let function_context = Map::new();
|
let function_context = Map::new();
|
||||||
|
|
||||||
for (key, (_value, r#type)) in context.variables()?.iter() {
|
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<Value> {
|
fn run(&self, _source: &str, _context: &Map) -> Result<Value, RuntimeError> {
|
||||||
let self_as_value = Value::Function(Function::ContextDefined(self.clone()));
|
let self_as_value = Value::Function(Function::ContextDefined(self.clone()));
|
||||||
|
|
||||||
Ok(self_as_value)
|
Ok(self_as_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
|
||||||
Ok(self.r#type().clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format for FunctionNode {
|
impl Format for FunctionNode {
|
||||||
|
@ -2,7 +2,10 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
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.
|
/// A string by which a variable is known to a context.
|
||||||
///
|
///
|
||||||
@ -26,7 +29,7 @@ impl Identifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Identifier {
|
impl AbstractTree for Identifier {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, _context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, _context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "identifier", node)?;
|
Error::expect_syntax_node(source, "identifier", node)?;
|
||||||
|
|
||||||
let text = &source[node.byte_range()];
|
let text = &source[node.byte_range()];
|
||||||
@ -36,21 +39,21 @@ impl AbstractTree for Identifier {
|
|||||||
Ok(Identifier(text.to_string()))
|
Ok(Identifier(text.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, context: &Map) -> Result<Value> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> {
|
||||||
if let Some((value, _)) = context.variables()?.get(&self.0) {
|
Ok(())
|
||||||
Ok(value.clone())
|
}
|
||||||
|
|
||||||
|
fn expected_type(&self, context: &Map) -> Result<Type, ValidationError> {
|
||||||
|
if let Some((_value, r#type)) = context.variables()?.get(&self.0) {
|
||||||
|
Ok(r#type.clone())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::VariableIdentifierNotFound(self.0.clone()))
|
Err(Error::VariableIdentifierNotFound(self.0.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
fn run(&self, _source: &str, context: &Map) -> Result<Value, RuntimeError> {
|
||||||
Ok(())
|
if let Some((value, _)) = context.variables()?.get(&self.0) {
|
||||||
}
|
Ok(value.clone())
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
|
||||||
if let Some((_value, r#type)) = context.variables()?.get(&self.0) {
|
|
||||||
Ok(r#type.clone())
|
|
||||||
} else {
|
} else {
|
||||||
Err(Error::VariableIdentifierNotFound(self.0.clone()))
|
Err(Error::VariableIdentifierNotFound(self.0.clone()))
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
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)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct IfElse {
|
pub struct IfElse {
|
||||||
@ -12,7 +15,7 @@ pub struct IfElse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for IfElse {
|
impl AbstractTree for IfElse {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
let if_expression_node = node.child(0).unwrap().child(1).unwrap();
|
let if_expression_node = node.child(0).unwrap().child(1).unwrap();
|
||||||
let if_expression = Expression::from_syntax(if_expression_node, source, context)?;
|
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<Value> {
|
fn expected_type(&self, context: &Map) -> Result<Type, ValidationError> {
|
||||||
|
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<Value, RuntimeError> {
|
||||||
let if_boolean = self.if_expression.run(source, context)?.as_boolean()?;
|
let if_boolean = self.if_expression.run(source, context)?.as_boolean()?;
|
||||||
|
|
||||||
if if_boolean {
|
if if_boolean {
|
||||||
@ -79,10 +110,6 @@ impl AbstractTree for IfElse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
|
||||||
self.if_block.expected_type(context)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format for IfElse {
|
impl Format for IfElse {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
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.
|
/// Abstract representation of an index expression.
|
||||||
@ -15,7 +16,7 @@ pub struct Index {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Index {
|
impl AbstractTree for Index {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "index", node)?;
|
Error::expect_syntax_node(source, "index", node)?;
|
||||||
|
|
||||||
let collection_node = node.child(0).unwrap();
|
let collection_node = node.child(0).unwrap();
|
||||||
@ -42,7 +43,27 @@ impl AbstractTree for Index {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn expected_type(&self, context: &Map) -> Result<Type, ValidationError> {
|
||||||
|
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<Value, RuntimeError> {
|
||||||
let collection = self.collection.run(source, context)?;
|
let collection = self.collection.run(source, context)?;
|
||||||
|
|
||||||
match collection {
|
match collection {
|
||||||
@ -97,15 +118,6 @@ impl AbstractTree for Index {
|
|||||||
_ => Err(Error::ExpectedCollection { actual: collection }),
|
_ => Err(Error::ExpectedCollection { actual: collection }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
|
||||||
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 {
|
impl Format for Index {
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AbstractTree, AssignmentOperator, Error, Format, Index, IndexExpression, Map, Result,
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
Statement, SyntaxNode, Type, Value,
|
AbstractTree, AssignmentOperator, Error, Format, Index, IndexExpression, Map, Statement,
|
||||||
|
SyntaxNode, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
@ -13,7 +14,7 @@ pub struct IndexAssignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for IndexAssignment {
|
impl AbstractTree for IndexAssignment {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "index_assignment", node)?;
|
Error::expect_syntax_node(source, "index_assignment", node)?;
|
||||||
|
|
||||||
let index_node = node.child(0).unwrap();
|
let index_node = node.child(0).unwrap();
|
||||||
@ -32,7 +33,16 @@ impl AbstractTree for IndexAssignment {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn expected_type(&self, _context: &Map) -> Result<Type, ValidationError> {
|
||||||
|
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<Value, RuntimeError> {
|
||||||
let index_collection = self.index.collection.run(source, context)?;
|
let index_collection = self.index.collection.run(source, context)?;
|
||||||
let index_context = index_collection.as_map().unwrap_or(context);
|
let index_context = index_collection.as_map().unwrap_or(context);
|
||||||
let index_key = if let IndexExpression::Identifier(identifier) = &self.index.index {
|
let index_key = if let IndexExpression::Identifier(identifier) = &self.index.index {
|
||||||
@ -73,10 +83,6 @@ impl AbstractTree for IndexAssignment {
|
|||||||
|
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
|
||||||
Ok(Type::None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format for IndexAssignment {
|
impl Format for IndexAssignment {
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
value_node::ValueNode, AbstractTree, Error, Format, FunctionCall, Identifier, Index, Map,
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
Result, SyntaxNode, Type, Value,
|
value_node::ValueNode,
|
||||||
|
AbstractTree, Error, Format, FunctionCall, Identifier, Index, Map, SyntaxNode, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
@ -14,7 +15,7 @@ pub enum IndexExpression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for IndexExpression {
|
impl AbstractTree for IndexExpression {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "index_expression", node)?;
|
Error::expect_syntax_node(source, "index_expression", node)?;
|
||||||
|
|
||||||
let first_child = node.child(0).unwrap();
|
let first_child = node.child(0).unwrap();
|
||||||
@ -48,16 +49,7 @@ impl AbstractTree for IndexExpression {
|
|||||||
Ok(abstract_node)
|
Ok(abstract_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn expected_type(&self, context: &Map) -> Result<Type, ValidationError> {
|
||||||
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<Type> {
|
|
||||||
match self {
|
match self {
|
||||||
IndexExpression::Value(value_node) => value_node.expected_type(context),
|
IndexExpression::Value(value_node) => value_node.expected_type(context),
|
||||||
IndexExpression::Identifier(identifier) => identifier.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),
|
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<Value, RuntimeError> {
|
||||||
|
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 {
|
impl Format for IndexExpression {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
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.
|
/// Abstract representation of a logic expression.
|
||||||
@ -13,7 +14,7 @@ pub struct Logic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Logic {
|
impl AbstractTree for Logic {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "logic", node)?;
|
Error::expect_syntax_node(source, "logic", node)?;
|
||||||
|
|
||||||
let first_node = node.child(0).unwrap();
|
let first_node = node.child(0).unwrap();
|
||||||
@ -39,7 +40,16 @@ impl AbstractTree for Logic {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn expected_type(&self, _context: &Map) -> Result<Type, ValidationError> {
|
||||||
|
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<Value, RuntimeError> {
|
||||||
let left = self.left.run(source, context)?;
|
let left = self.left.run(source, context)?;
|
||||||
let right = self.right.run(source, context)?;
|
let right = self.right.run(source, context)?;
|
||||||
let result = match self.operator {
|
let result = match self.operator {
|
||||||
@ -67,10 +77,6 @@ impl AbstractTree for Logic {
|
|||||||
|
|
||||||
Ok(Value::Boolean(result))
|
Ok(Value::Boolean(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
|
||||||
Ok(Type::Boolean)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format for Logic {
|
impl Format for Logic {
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
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)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum LogicOperator {
|
pub enum LogicOperator {
|
||||||
@ -15,7 +18,7 @@ pub enum LogicOperator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for LogicOperator {
|
impl AbstractTree for LogicOperator {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, _context: &Map) -> crate::Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, _context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "logic_operator", node)?;
|
Error::expect_syntax_node(source, "logic_operator", node)?;
|
||||||
|
|
||||||
let operator_node = node.child(0).unwrap();
|
let operator_node = node.child(0).unwrap();
|
||||||
@ -41,12 +44,16 @@ impl AbstractTree for LogicOperator {
|
|||||||
Ok(operator)
|
Ok(operator)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
fn expected_type(&self, _context: &Map) -> Result<Type, ValidationError> {
|
||||||
Ok(Value::none())
|
Ok(Type::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> {
|
||||||
Ok(Type::None)
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, _source: &str, _context: &Map) -> Result<Value, RuntimeError> {
|
||||||
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
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.
|
/// Abstract representation of a match statement.
|
||||||
@ -17,7 +18,7 @@ pub struct Match {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Match {
|
impl AbstractTree for Match {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "match", node)?;
|
Error::expect_syntax_node(source, "match", node)?;
|
||||||
|
|
||||||
let matcher_node = node.child(1).unwrap();
|
let matcher_node = node.child(1).unwrap();
|
||||||
@ -58,7 +59,28 @@ impl AbstractTree for Match {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn expected_type(&self, context: &Map) -> Result<Type, ValidationError> {
|
||||||
|
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<Value, RuntimeError> {
|
||||||
let matcher_value = self.matcher.run(source, context)?;
|
let matcher_value = self.matcher.run(source, context)?;
|
||||||
|
|
||||||
for (expression, statement) in &self.options {
|
for (expression, statement) in &self.options {
|
||||||
@ -75,12 +97,6 @@ impl AbstractTree for Match {
|
|||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
|
||||||
let (_, first_statement) = self.options.first().unwrap();
|
|
||||||
|
|
||||||
first_statement.expected_type(context)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format for Match {
|
impl Format for Match {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
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.
|
/// Abstract representation of a math operation.
|
||||||
@ -16,7 +17,7 @@ pub struct Math {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Math {
|
impl AbstractTree for Math {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "math", node)?;
|
Error::expect_syntax_node(source, "math", node)?;
|
||||||
|
|
||||||
let left_node = node.child(0).unwrap();
|
let left_node = node.child(0).unwrap();
|
||||||
@ -35,7 +36,16 @@ impl AbstractTree for Math {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn expected_type(&self, context: &Map) -> Result<Type, ValidationError> {
|
||||||
|
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<Value, RuntimeError> {
|
||||||
let left = self.left.run(source, context)?;
|
let left = self.left.run(source, context)?;
|
||||||
let right = self.right.run(source, context)?;
|
let right = self.right.run(source, context)?;
|
||||||
let value = match self.operator {
|
let value = match self.operator {
|
||||||
@ -48,10 +58,6 @@ impl AbstractTree for Math {
|
|||||||
|
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
|
||||||
self.left.expected_type(context)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format for Math {
|
impl Format for Math {
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
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)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum MathOperator {
|
pub enum MathOperator {
|
||||||
@ -12,7 +15,7 @@ pub enum MathOperator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for MathOperator {
|
impl AbstractTree for MathOperator {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, _context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, _context: &Map) -> Result<Self, SyntaxError> {
|
||||||
let operator_node = node.child(0).unwrap();
|
let operator_node = node.child(0).unwrap();
|
||||||
let operator = match operator_node.kind() {
|
let operator = match operator_node.kind() {
|
||||||
"+" => MathOperator::Add,
|
"+" => MathOperator::Add,
|
||||||
@ -33,12 +36,16 @@ impl AbstractTree for MathOperator {
|
|||||||
Ok(operator)
|
Ok(operator)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
fn expected_type(&self, _context: &Map) -> Result<Type, ValidationError> {
|
||||||
Ok(Value::none())
|
Ok(Type::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> {
|
||||||
Ok(Type::None)
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, _source: &str, _context: &Map) -> Result<Value, RuntimeError> {
|
||||||
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +44,10 @@ pub use {
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
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)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct SyntaxPosition {
|
pub struct SyntaxPosition {
|
||||||
@ -78,7 +81,7 @@ pub struct Root {
|
|||||||
// instead of indexes. This will be more performant when there are a lot of
|
// instead of indexes. This will be more performant when there are a lot of
|
||||||
// top-level statements in the tree.
|
// top-level statements in the tree.
|
||||||
impl AbstractTree for Root {
|
impl AbstractTree for Root {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "root", node)?;
|
Error::expect_syntax_node(source, "root", node)?;
|
||||||
|
|
||||||
let statement_count = node.child_count();
|
let statement_count = node.child_count();
|
||||||
@ -94,7 +97,7 @@ impl AbstractTree for Root {
|
|||||||
Ok(Root { statements })
|
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 {
|
for statement in &self.statements {
|
||||||
if let Statement::Return(inner_statement) = statement {
|
if let Statement::Return(inner_statement) = statement {
|
||||||
return inner_statement.check_type(_source, _context);
|
return inner_statement.check_type(_source, _context);
|
||||||
@ -106,7 +109,7 @@ impl AbstractTree for Root {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &Map) -> Result<Value, RuntimeError> {
|
||||||
let mut value = Value::none();
|
let mut value = Value::none();
|
||||||
|
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
@ -120,7 +123,7 @@ impl AbstractTree for Root {
|
|||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type, ValidationError> {
|
||||||
self.statements.last().unwrap().expected_type(context)
|
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
|
/// If necessary, the source code can be accessed directly by getting the
|
||||||
/// node's byte range.
|
/// node's byte range.
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self>;
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError>;
|
||||||
|
|
||||||
/// Verify the type integrity of the node.
|
/// Verify the type integrity of the node.
|
||||||
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError>;
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Execute dust code by traversing the tree.
|
/// Execute dust code by traversing the tree.
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value>;
|
fn run(&self, source: &str, context: &Map) -> Result<Value, RuntimeError>;
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type>;
|
fn expected_type(&self, context: &Map) -> Result<Type, ValidationError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Format {
|
pub trait Format {
|
||||||
|
@ -2,7 +2,8 @@ use serde::{Deserialize, Serialize};
|
|||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{
|
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)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
@ -12,7 +13,7 @@ pub struct New {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for New {
|
impl AbstractTree for New {
|
||||||
fn from_syntax(node: Node, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(node: Node, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
let identifier_node = node.child(1).unwrap();
|
let identifier_node = node.child(1).unwrap();
|
||||||
let identifier = Identifier::from_syntax(identifier_node, source, context)?;
|
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<Value> {
|
fn expected_type(&self, _context: &Map) -> Result<Type, ValidationError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &crate::Map) -> crate::Result<Type> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, _source: &str, _context: &Map) -> Result<Value, RuntimeError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
AbstractTree, Assignment, Block, Error, Expression, For, Format, IfElse, IndexAssignment, Map,
|
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.
|
/// Abstract representation of a statement.
|
||||||
@ -20,7 +21,7 @@ pub enum Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Statement {
|
impl AbstractTree for Statement {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "statement", node)?;
|
Error::expect_syntax_node(source, "statement", node)?;
|
||||||
|
|
||||||
let child = node.child(0).unwrap();
|
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<Type, ValidationError> {
|
||||||
|
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 {
|
match self {
|
||||||
Statement::Assignment(assignment) => assignment.check_type(_source, _context),
|
Statement::Assignment(assignment) => assignment.check_type(_source, _context),
|
||||||
Statement::Expression(expression) => expression.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<Value> {
|
fn run(&self, source: &str, context: &Map) -> Result<Value, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Assignment(assignment) => assignment.run(source, context),
|
Statement::Assignment(assignment) => assignment.run(source, context),
|
||||||
Statement::Expression(expression) => expression.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),
|
Statement::Return(statement) => statement.run(source, context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
|
||||||
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 {
|
impl Format for Statement {
|
||||||
|
@ -2,7 +2,10 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
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)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
@ -41,7 +44,7 @@ impl Type {
|
|||||||
Type::Option(Box::new(optional_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}.");
|
log::info!("Checking type {self} against {other}.");
|
||||||
|
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
@ -153,7 +156,7 @@ impl Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Type {
|
impl AbstractTree for Type {
|
||||||
fn from_syntax(node: SyntaxNode, _source: &str, _context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, _source: &str, _context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(_source, "type", node)?;
|
Error::expect_syntax_node(_source, "type", node)?;
|
||||||
|
|
||||||
let type_node = node.child(0).unwrap();
|
let type_node = node.child(0).unwrap();
|
||||||
@ -219,12 +222,16 @@ impl AbstractTree for Type {
|
|||||||
Ok(r#type)
|
Ok(r#type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
fn expected_type(&self, _context: &Map) -> Result<Type, ValidationError> {
|
||||||
Ok(Value::none())
|
Ok(Type::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> {
|
||||||
Ok(Type::None)
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, _source: &str, _context: &Map) -> Result<Value, RuntimeError> {
|
||||||
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
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)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct TypeSpecification {
|
pub struct TypeSpecification {
|
||||||
@ -22,7 +25,7 @@ impl TypeSpecification {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for TypeSpecification {
|
impl AbstractTree for TypeSpecification {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "type_specification", node)?;
|
Error::expect_syntax_node(source, "type_specification", node)?;
|
||||||
|
|
||||||
let type_node = node.child(1).unwrap();
|
let type_node = node.child(1).unwrap();
|
||||||
@ -31,12 +34,16 @@ impl AbstractTree for TypeSpecification {
|
|||||||
Ok(TypeSpecification { r#type })
|
Ok(TypeSpecification { r#type })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn expected_type(&self, context: &Map) -> Result<Type, ValidationError> {
|
||||||
self.r#type.run(source, context)
|
self.r#type.expected_type(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> {
|
||||||
self.r#type.expected_type(context)
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, source: &str, context: &Map) -> Result<Value, RuntimeError> {
|
||||||
|
self.r#type.run(source, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
use std::{
|
use std::{cmp::Ordering, collections::BTreeMap, ops::RangeInclusive};
|
||||||
cmp::Ordering,
|
|
||||||
collections::BTreeMap,
|
|
||||||
ops::{Range, RangeInclusive},
|
|
||||||
};
|
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
AbstractTree, BuiltInValue, Error, Expression, Format, Function, FunctionNode, Identifier,
|
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)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
@ -27,7 +24,7 @@ pub enum ValueNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for ValueNode {
|
impl AbstractTree for ValueNode {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "value", node)?;
|
Error::expect_syntax_node(source, "value", node)?;
|
||||||
|
|
||||||
let child = node.child(0).unwrap();
|
let child = node.child(0).unwrap();
|
||||||
@ -189,7 +186,59 @@ impl AbstractTree for ValueNode {
|
|||||||
Ok(value_node)
|
Ok(value_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
fn expected_type(&self, context: &Map) -> Result<Type, ValidationError> {
|
||||||
|
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 {
|
match self {
|
||||||
ValueNode::Function(function) => {
|
ValueNode::Function(function) => {
|
||||||
if let Function::ContextDefined(function_node) = function {
|
if let Function::ContextDefined(function_node) = function {
|
||||||
@ -202,7 +251,7 @@ impl AbstractTree for ValueNode {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &Map) -> Result<Value, RuntimeError> {
|
||||||
let value = match self {
|
let value = match self {
|
||||||
ValueNode::Boolean(value_source) => Value::Boolean(value_source.parse().unwrap()),
|
ValueNode::Boolean(value_source) => Value::Boolean(value_source.parse().unwrap()),
|
||||||
ValueNode::Float(value_source) => {
|
ValueNode::Float(value_source) => {
|
||||||
@ -267,58 +316,6 @@ impl AbstractTree for ValueNode {
|
|||||||
|
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
|
||||||
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 {
|
impl Format for ValueNode {
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
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.
|
/// Abstract representation of a while loop.
|
||||||
///
|
///
|
||||||
@ -12,7 +15,7 @@ pub struct While {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for While {
|
impl AbstractTree for While {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> crate::Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "while", node)?;
|
Error::expect_syntax_node(source, "while", node)?;
|
||||||
|
|
||||||
let expression_node = node.child(1).unwrap();
|
let expression_node = node.child(1).unwrap();
|
||||||
@ -24,17 +27,22 @@ impl AbstractTree for While {
|
|||||||
Ok(While { expression, block })
|
Ok(While { expression, block })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn expected_type(&self, context: &Map) -> Result<Type, ValidationError> {
|
||||||
|
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<Value, RuntimeError> {
|
||||||
while self.expression.run(source, context)?.as_boolean()? {
|
while self.expression.run(source, context)?.as_boolean()? {
|
||||||
self.block.run(source, context)?;
|
self.block.run(source, context)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
|
||||||
self.block.expected_type(context)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format for While {
|
impl Format for While {
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
function_expression::FunctionExpression, AbstractTree, Error, Expression, Format, FunctionCall,
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
Map, Result, SyntaxNode, Type, Value,
|
function_expression::FunctionExpression,
|
||||||
|
AbstractTree, Error, Expression, Format, FunctionCall, Map, SyntaxNode, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Abstract representation of a yield expression.
|
/// Abstract representation of a yield expression.
|
||||||
@ -14,7 +15,7 @@ pub struct Yield {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Yield {
|
impl AbstractTree for Yield {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Map) -> Result<Self, SyntaxError> {
|
||||||
Error::expect_syntax_node(source, "yield", node)?;
|
Error::expect_syntax_node(source, "yield", node)?;
|
||||||
|
|
||||||
let input_node = node.child(0).unwrap();
|
let input_node = node.child(0).unwrap();
|
||||||
@ -42,12 +43,16 @@ impl AbstractTree for Yield {
|
|||||||
Ok(Yield { call })
|
Ok(Yield { call })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn expected_type(&self, context: &Map) -> Result<Type, ValidationError> {
|
||||||
self.call.run(source, context)
|
self.call.expected_type(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<(), ValidationError> {
|
||||||
self.call.expected_type(context)
|
self.call.check_type(_source, _context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, source: &str, context: &Map) -> Result<Value, RuntimeError> {
|
||||||
|
self.call.run(source, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ use std::fs::read_to_string;
|
|||||||
use enum_iterator::{all, Sequence};
|
use enum_iterator::{all, Sequence};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{Error, Map, Result, Type, Value};
|
use crate::{error::RuntimeError, Error, Map, Type, Value};
|
||||||
|
|
||||||
use super::Callable;
|
use super::Callable;
|
||||||
|
|
||||||
@ -35,7 +35,12 @@ impl Callable for Fs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&self, arguments: &[Value], _source: &str, _outer_context: &Map) -> Result<Value> {
|
fn call(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_source: &str,
|
||||||
|
_outer_context: &Map,
|
||||||
|
) -> Result<Value, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Fs::ReadFile => {
|
Fs::ReadFile => {
|
||||||
Error::expect_argument_amount(self.name(), 1, arguments.len())?;
|
Error::expect_argument_amount(self.name(), 1, arguments.len())?;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use enum_iterator::Sequence;
|
use enum_iterator::Sequence;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{Error, Map, Result, Type, Value};
|
use crate::{error::RuntimeError, Error, Map, Type, Value};
|
||||||
|
|
||||||
use super::Callable;
|
use super::Callable;
|
||||||
|
|
||||||
@ -41,7 +41,12 @@ impl Callable for Json {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&self, arguments: &[Value], _source: &str, _outer_context: &Map) -> Result<Value> {
|
fn call(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_source: &str,
|
||||||
|
_outer_context: &Map,
|
||||||
|
) -> Result<Value, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Json::Create => {
|
Json::Create => {
|
||||||
Error::expect_argument_amount(self.name(), 1, arguments.len())?;
|
Error::expect_argument_amount(self.name(), 1, arguments.len())?;
|
||||||
|
@ -7,7 +7,7 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
use rand::{random, thread_rng, Rng};
|
use rand::{random, thread_rng, Rng};
|
||||||
use serde::{Deserialize, Serialize};
|
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};
|
use self::{fs::Fs, json::Json, str::StrFunction};
|
||||||
|
|
||||||
@ -15,7 +15,12 @@ pub trait Callable {
|
|||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
fn description(&self) -> &'static str;
|
fn description(&self) -> &'static str;
|
||||||
fn r#type(&self) -> Type;
|
fn r#type(&self) -> Type;
|
||||||
fn call(&self, arguments: &[Value], source: &str, outer_context: &Map) -> Result<Value>;
|
fn call(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
source: &str,
|
||||||
|
outer_context: &Map,
|
||||||
|
) -> Result<Value, RuntimeError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
#[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<Value> {
|
fn call(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_source: &str,
|
||||||
|
_outer_context: &Map,
|
||||||
|
) -> Result<Value, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
BuiltInFunction::AssertEqual => {
|
BuiltInFunction::AssertEqual => {
|
||||||
Error::expect_argument_amount(self.name(), 2, arguments.len())?;
|
Error::expect_argument_amount(self.name(), 2, arguments.len())?;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use enum_iterator::Sequence;
|
use enum_iterator::Sequence;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{Error, List, Map, Result, Type, Value};
|
use crate::{error::RuntimeError, Error, List, Map, Type, Value};
|
||||||
|
|
||||||
use super::Callable;
|
use super::Callable;
|
||||||
|
|
||||||
@ -198,7 +198,12 @@ impl Callable for StrFunction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&self, arguments: &[Value], _source: &str, _outer_context: &Map) -> Result<Value> {
|
fn call(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_source: &str,
|
||||||
|
_outer_context: &Map,
|
||||||
|
) -> Result<Value, RuntimeError> {
|
||||||
let value = match self {
|
let value = match self {
|
||||||
StrFunction::AsBytes => {
|
StrFunction::AsBytes => {
|
||||||
Error::expect_argument_amount(self.name(), 1, arguments.len())?;
|
Error::expect_argument_amount(self.name(), 1, arguments.len())?;
|
||||||
|
468
src/error.rs
468
src/error.rs
@ -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<T> = std::result::Result<T, Error>;
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub enum Error {
|
|
||||||
AtSourcePosition {
|
|
||||||
error: Box<Error>,
|
|
||||||
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<LanguageError> for Error {
|
|
||||||
fn from(error: LanguageError) -> Self {
|
|
||||||
Error::External(error.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> From<PoisonError<T>> for Error {
|
|
||||||
fn from(error: PoisonError<T>) -> Self {
|
|
||||||
Error::External(error.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<FromUtf8Error> for Error {
|
|
||||||
fn from(error: FromUtf8Error) -> Self {
|
|
||||||
Error::External(error.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ParseFloatError> for Error {
|
|
||||||
fn from(error: ParseFloatError) -> Self {
|
|
||||||
Error::ParseFloat {
|
|
||||||
reason: error.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<csv::Error> for Error {
|
|
||||||
fn from(error: csv::Error) -> Self {
|
|
||||||
Error::External(error.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<io::Error> for Error {
|
|
||||||
fn from(error: std::io::Error) -> Self {
|
|
||||||
Error::External(error.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<reqwest::Error> for Error {
|
|
||||||
fn from(error: reqwest::Error) -> Self {
|
|
||||||
Error::External(error.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<serde_json::Error> for Error {
|
|
||||||
fn from(error: serde_json::Error) -> Self {
|
|
||||||
Error::SerdeJson(error.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<time::SystemTimeError> for Error {
|
|
||||||
fn from(error: time::SystemTimeError) -> Self {
|
|
||||||
Error::External(error.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<toml::de::Error> 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)
|
|
||||||
}
|
|
247
src/error/mod.rs
Normal file
247
src/error/mod.rs
Normal file
@ -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<Error>,
|
||||||
|
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<LanguageError> for Error {
|
||||||
|
fn from(error: LanguageError) -> Self {
|
||||||
|
Error::External(error.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<PoisonError<T>> for Error {
|
||||||
|
fn from(error: PoisonError<T>) -> Self {
|
||||||
|
Error::External(error.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<FromUtf8Error> for Error {
|
||||||
|
fn from(error: FromUtf8Error) -> Self {
|
||||||
|
Error::External(error.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParseFloatError> for Error {
|
||||||
|
fn from(error: ParseFloatError) -> Self {
|
||||||
|
Error::ParseFloat {
|
||||||
|
reason: error.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<csv::Error> for Error {
|
||||||
|
fn from(error: csv::Error) -> Self {
|
||||||
|
Error::External(error.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for Error {
|
||||||
|
fn from(error: std::io::Error) -> Self {
|
||||||
|
Error::External(error.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<reqwest::Error> for Error {
|
||||||
|
fn from(error: reqwest::Error) -> Self {
|
||||||
|
Error::External(error.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<serde_json::Error> for Error {
|
||||||
|
fn from(error: serde_json::Error) -> Self {
|
||||||
|
Error::SerdeJson(error.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<time::SystemTimeError> for Error {
|
||||||
|
fn from(error: time::SystemTimeError) -> Self {
|
||||||
|
Error::External(error.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<toml::de::Error> 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)
|
||||||
|
}
|
181
src/error/runtime_error.rs
Normal file
181
src/error/runtime_error.rs
Normal file
@ -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!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
src/error/syntax_error.rs
Normal file
15
src/error/syntax_error.rs
Normal file
@ -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,
|
||||||
|
},
|
||||||
|
}
|
27
src/error/validation_error.rs
Normal file
27
src/error/validation_error.rs
Normal file
@ -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),
|
||||||
|
}
|
@ -37,13 +37,16 @@
|
|||||||
//! ```
|
//! ```
|
||||||
use tree_sitter::{Node as SyntaxNode, Parser, Tree as SyntaxTree, TreeCursor};
|
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
|
/// Interpret the given source code. Returns the value of last statement or the
|
||||||
/// first error encountered.
|
/// first error encountered.
|
||||||
///
|
///
|
||||||
/// See the [module-level docs][self] for more info.
|
/// See the [module-level docs][self] for more info.
|
||||||
pub fn interpret(source: &str) -> Result<Value> {
|
pub fn interpret(source: &str) -> Result<Value, Error> {
|
||||||
interpret_with_context(source, Map::new())
|
interpret_with_context(source, Map::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +58,7 @@ pub fn interpret(source: &str) -> Result<Value> {
|
|||||||
/// maps.
|
/// maps.
|
||||||
///
|
///
|
||||||
/// See the [module-level docs][self] for more info.
|
/// See the [module-level docs][self] for more info.
|
||||||
pub fn interpret_with_context(source: &str, context: Map) -> Result<Value> {
|
pub fn interpret_with_context(source: &str, context: Map) -> Result<Value, Error> {
|
||||||
let mut interpreter = Interpreter::new(context);
|
let mut interpreter = Interpreter::new(context);
|
||||||
let value = interpreter.run(source)?;
|
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
|
/// Tree sitter is designed to be run on every keystroke, so this is generally a lightweight
|
||||||
/// function to call.
|
/// function to call.
|
||||||
pub fn parse(&mut self, source: &str) -> Result<SyntaxTree> {
|
pub fn parse(&mut self, source: &str) -> Result<SyntaxTree, Error> {
|
||||||
if let Some(tree) = self.parser.parse(source, None) {
|
if let Some(tree) = self.parser.parse(source, None) {
|
||||||
Ok(tree)
|
Ok(tree)
|
||||||
} else {
|
} else {
|
||||||
@ -109,8 +112,12 @@ impl Interpreter {
|
|||||||
/// - check the syntax tree for errors
|
/// - check the syntax tree for errors
|
||||||
/// - generate an abstract tree from the source and syntax tree
|
/// - generate an abstract tree from the source and syntax tree
|
||||||
/// - check the abstract tree for type errors
|
/// - check the abstract tree for type errors
|
||||||
pub fn verify(&mut self, source: &str) -> Result<Root> {
|
pub fn verify(&mut self, source: &str) -> Result<Root, Error> {
|
||||||
fn check_for_error(node: SyntaxNode, source: &str, cursor: &mut TreeCursor) -> Result<()> {
|
fn check_for_error(
|
||||||
|
node: SyntaxNode,
|
||||||
|
source: &str,
|
||||||
|
cursor: &mut TreeCursor,
|
||||||
|
) -> Result<(), ValidationError> {
|
||||||
if node.is_error() {
|
if node.is_error() {
|
||||||
Err(Error::Syntax {
|
Err(Error::Syntax {
|
||||||
source: source[node.byte_range()].to_string(),
|
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
|
/// This function [parses][Self::parse], [verifies][Self::verify] and [runs][Root::run] using
|
||||||
/// the same source code.
|
/// the same source code.
|
||||||
pub fn run(&mut self, source: &str) -> Result<Value> {
|
pub fn run(&mut self, source: &str) -> Result<Value, Error> {
|
||||||
self.verify(source)?.run(source, &self.context)
|
self.verify(source)?.run(source, &self.context)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return an s-expression displaying a syntax tree of the source, or the ParserCancelled error
|
/// Return an s-expression displaying a syntax tree of the source, or the ParserCancelled error
|
||||||
/// if the parser takes too long.
|
/// if the parser takes too long.
|
||||||
pub fn syntax_tree(&mut self, source: &str) -> Result<String> {
|
pub fn syntax_tree(&mut self, source: &str) -> Result<String, Error> {
|
||||||
Ok(self.parse(source)?.root_node().to_sexp())
|
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
|
/// You should call [verify][Interpreter::verify] before calling this function. You can only
|
||||||
/// create formatted source from a valid abstract tree.
|
/// create formatted source from a valid abstract tree.
|
||||||
pub fn format(&mut self, source: &str) -> Result<String> {
|
pub fn format(&mut self, source: &str) -> Result<String, Error> {
|
||||||
let mut formatted_output = String::new();
|
let mut formatted_output = String::new();
|
||||||
|
|
||||||
self.verify(source)?.format(&mut formatted_output, 0);
|
self.verify(source)?.format(&mut formatted_output, 0);
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
//! You can use this library externally by calling either of the "interpret"
|
//! You can use this library externally by calling either of the "interpret"
|
||||||
//! functions or by constructing your own Interpreter.
|
//! functions or by constructing your own Interpreter.
|
||||||
pub use crate::{
|
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;
|
pub use tree_sitter::Node as SyntaxNode;
|
||||||
|
@ -3,7 +3,8 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
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)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
@ -13,7 +14,12 @@ pub enum Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Function {
|
impl Function {
|
||||||
pub fn call(&self, arguments: &[Value], source: &str, outer_context: &Map) -> Result<Value> {
|
pub fn call(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
source: &str,
|
||||||
|
outer_context: &Map,
|
||||||
|
) -> Result<Value, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Function::BuiltIn(built_in_function) => {
|
Function::BuiltIn(built_in_function) => {
|
||||||
built_in_function.call(arguments, source, outer_context)
|
built_in_function.call(arguments, source, outer_context)
|
||||||
|
@ -13,10 +13,12 @@ use std::{
|
|||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
marker::PhantomData,
|
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<RwLockReadGuard<'a, BTreeMap<String, (Value, Type)>>>;
|
||||||
|
|
||||||
/// A collection dust variables comprised of key-value pairs.
|
/// A collection dust variables comprised of key-value pairs.
|
||||||
///
|
///
|
||||||
@ -63,7 +65,7 @@ impl Map {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clone_from(other: &Self) -> Result<Self> {
|
pub fn clone_from(other: &Self) -> Result<Self, ()> {
|
||||||
let mut new_map = BTreeMap::new();
|
let mut new_map = BTreeMap::new();
|
||||||
|
|
||||||
for (key, (value, r#type)) in other.variables()?.iter() {
|
for (key, (value, r#type)) in other.variables()?.iter() {
|
||||||
@ -76,11 +78,13 @@ impl Map {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn variables(&self) -> Result<RwLockReadGuard<BTreeMap<String, (Value, Type)>>> {
|
pub fn variables(
|
||||||
Ok(self.variables.read()?)
|
&self,
|
||||||
|
) -> Result<RwLockReadGuard<BTreeMap<String, (Value, Type)>>, MapAccessError> {
|
||||||
|
self.variables.read()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&self, key: String, value: Value) -> Result<Option<(Value, Type)>> {
|
pub fn set(&self, key: String, value: Value) -> Result<Option<(Value, Type)>, MapAccessError> {
|
||||||
log::info!("Setting variable {key} = {value}");
|
log::info!("Setting variable {key} = {value}");
|
||||||
|
|
||||||
let value_type = value.r#type();
|
let value_type = value.r#type();
|
||||||
@ -92,7 +96,7 @@ impl Map {
|
|||||||
Ok(previous)
|
Ok(previous)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_type(&self, key: String, r#type: Type) -> Result<Option<(Value, Type)>> {
|
pub fn set_type(&self, key: String, r#type: Type) -> Result<Option<(Value, Type)>, ()> {
|
||||||
log::info!("Setting type {key} = {}", r#type);
|
log::info!("Setting type {key} = {}", r#type);
|
||||||
|
|
||||||
let previous = self.variables.write()?.insert(key, (Value::none(), r#type));
|
let previous = self.variables.write()?.insert(key, (Value::none(), r#type));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Types that represent runtime values.
|
//! Types that represent runtime values.
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{Error, Result},
|
error::{Error, RuntimeError},
|
||||||
Identifier, Type, TypeSpecification,
|
Identifier, Type, TypeSpecification,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ use std::{
|
|||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
marker::PhantomData,
|
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};
|
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`.
|
/// 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 {
|
match self {
|
||||||
Value::String(string) => Ok(string),
|
Value::String(string) => Ok(string),
|
||||||
value => Err(Error::ExpectedString {
|
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`
|
/// Copies the value stored in `self` as `i64`, or returns `Err` if `self` is not a `Value::Int`
|
||||||
pub fn as_integer(&self) -> Result<i64> {
|
pub fn as_integer(&self) -> Result<i64, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Value::Integer(i) => Ok(*i),
|
Value::Integer(i) => Ok(*i),
|
||||||
value => Err(Error::ExpectedInteger {
|
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`.
|
/// Copies the value stored in `self` as `f64`, or returns `Err` if `self` is not a `Primitive::Float`.
|
||||||
pub fn as_float(&self) -> Result<f64> {
|
pub fn as_float(&self) -> Result<f64, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Value::Float(f) => Ok(*f),
|
Value::Float(f) => Ok(*f),
|
||||||
value => Err(Error::ExpectedFloat {
|
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`.
|
/// 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`.
|
/// Note that this method silently converts `i64` to `f64`, if `self` is a `Value::Int`.
|
||||||
pub fn as_number(&self) -> Result<f64> {
|
pub fn as_number(&self) -> Result<f64, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Value::Float(f) => Ok(*f),
|
Value::Float(f) => Ok(*f),
|
||||||
Value::Integer(i) => Ok(*i as f64),
|
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`.
|
/// Copies the value stored in `self` as `bool`, or returns `Err` if `self` is not a `Primitive::Boolean`.
|
||||||
pub fn as_boolean(&self) -> Result<bool> {
|
pub fn as_boolean(&self) -> Result<bool, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Value::Boolean(boolean) => Ok(*boolean),
|
Value::Boolean(boolean) => Ok(*boolean),
|
||||||
value => Err(Error::ExpectedBoolean {
|
value => Err(Error::ExpectedBoolean {
|
||||||
@ -216,7 +216,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Borrows the value stored in `self` as `Vec<Value>`, or returns `Err` if `self` is not a `Value::List`.
|
/// Borrows the value stored in `self` as `Vec<Value>`, 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 {
|
match self {
|
||||||
Value::List(list) => Ok(list),
|
Value::List(list) => Ok(list),
|
||||||
value => Err(Error::ExpectedList {
|
value => Err(Error::ExpectedList {
|
||||||
@ -226,7 +226,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Takes ownership of the value stored in `self` as `Vec<Value>`, or returns `Err` if `self` is not a `Value::List`.
|
/// Takes ownership of the value stored in `self` as `Vec<Value>`, or returns `Err` if `self` is not a `Value::List`.
|
||||||
pub fn into_inner_list(self) -> Result<List> {
|
pub fn into_inner_list(self) -> Result<List, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Value::List(list) => Ok(list),
|
Value::List(list) => Ok(list),
|
||||||
value => Err(Error::ExpectedList {
|
value => Err(Error::ExpectedList {
|
||||||
@ -236,7 +236,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Borrows the value stored in `self` as `Vec<Value>`, or returns `Err` if `self` is not a `Value::Map`.
|
/// Borrows the value stored in `self` as `Vec<Value>`, 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 {
|
match self {
|
||||||
Value::Map(map) => Ok(map),
|
Value::Map(map) => Ok(map),
|
||||||
value => Err(Error::ExpectedMap {
|
value => Err(Error::ExpectedMap {
|
||||||
@ -247,7 +247,7 @@ impl Value {
|
|||||||
|
|
||||||
/// Borrows the value stored in `self` as `Function`, or returns `Err` if
|
/// Borrows the value stored in `self` as `Function`, or returns `Err` if
|
||||||
/// `self` is not a `Value::Function`.
|
/// `self` is not a `Value::Function`.
|
||||||
pub fn as_function(&self) -> Result<&Function> {
|
pub fn as_function(&self) -> Result<&Function, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Value::Function(function) => Ok(function),
|
Value::Function(function) => Ok(function),
|
||||||
value => Err(Error::ExpectedFunction {
|
value => Err(Error::ExpectedFunction {
|
||||||
@ -257,7 +257,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `Option`, or returns `Err` if `self` is not a `Value::Option`.
|
/// Returns `Option`, or returns `Err` if `self` is not a `Value::Option`.
|
||||||
pub fn as_option(&self) -> Result<&Option<Box<Value>>> {
|
pub fn as_option(&self) -> Result<&Option<Box<Value>>, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Value::Option(option) => Ok(option),
|
Value::Option(option) => Ok(option),
|
||||||
value => Err(Error::ExpectedOption {
|
value => Err(Error::ExpectedOption {
|
||||||
@ -267,7 +267,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `()`, or returns `Err` if `self` is not a `Value::none()`.
|
/// 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 {
|
match self {
|
||||||
Value::Option(option) => {
|
Value::Option(option) => {
|
||||||
if option.is_none() {
|
if option.is_none() {
|
||||||
@ -292,7 +292,7 @@ impl Default for &Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Add for Value {
|
impl Add for Value {
|
||||||
type Output = Result<Value>;
|
type Output = Result<Value, RuntimeError>;
|
||||||
|
|
||||||
fn add(self, other: Self) -> Self::Output {
|
fn add(self, other: Self) -> Self::Output {
|
||||||
if let (Ok(left), Ok(right)) = (self.as_integer(), other.as_integer()) {
|
if let (Ok(left), Ok(right)) = (self.as_integer(), other.as_integer()) {
|
||||||
@ -326,7 +326,7 @@ impl Add for Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Sub for Value {
|
impl Sub for Value {
|
||||||
type Output = Result<Self>;
|
type Output = Result<Self, RuntimeError>;
|
||||||
|
|
||||||
fn sub(self, other: Self) -> Self::Output {
|
fn sub(self, other: Self) -> Self::Output {
|
||||||
if let (Ok(left), Ok(right)) = (self.as_integer(), other.as_integer()) {
|
if let (Ok(left), Ok(right)) = (self.as_integer(), other.as_integer()) {
|
||||||
@ -346,7 +346,7 @@ impl Sub for Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Mul for Value {
|
impl Mul for Value {
|
||||||
type Output = Result<Self>;
|
type Output = Result<Self, RuntimeError>;
|
||||||
|
|
||||||
fn mul(self, other: Self) -> Self::Output {
|
fn mul(self, other: Self) -> Self::Output {
|
||||||
if let (Ok(left), Ok(right)) = (self.as_integer(), other.as_integer()) {
|
if let (Ok(left), Ok(right)) = (self.as_integer(), other.as_integer()) {
|
||||||
@ -362,7 +362,7 @@ impl Mul for Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Div for Value {
|
impl Div for Value {
|
||||||
type Output = Result<Self>;
|
type Output = Result<Self, RuntimeError>;
|
||||||
|
|
||||||
fn div(self, other: Self) -> Self::Output {
|
fn div(self, other: Self) -> Self::Output {
|
||||||
if let (Ok(left), Ok(right)) = (self.as_number(), other.as_number()) {
|
if let (Ok(left), Ok(right)) = (self.as_number(), other.as_number()) {
|
||||||
@ -383,7 +383,7 @@ impl Div for Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Rem for Value {
|
impl Rem for Value {
|
||||||
type Output = Result<Self>;
|
type Output = Result<Self, RuntimeError>;
|
||||||
|
|
||||||
fn rem(self, other: Self) -> Self::Output {
|
fn rem(self, other: Self) -> Self::Output {
|
||||||
let left = self.as_integer()?;
|
let left = self.as_integer()?;
|
||||||
@ -583,7 +583,7 @@ impl From<Vec<Value>> for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Value> for Result<Value> {
|
impl From<Value> for Result<Value, RuntimeError> {
|
||||||
fn from(value: Value) -> Self {
|
fn from(value: Value) -> Self {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user