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