Begin error overhaul

This commit is contained in:
Jeff 2024-01-31 13:51:48 -05:00
parent cd4296c941
commit 7f849f13a3
42 changed files with 1085 additions and 839 deletions

View File

@ -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)
}
}

View File

@ -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 {

View File

@ -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

View File

@ -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())
}
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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()))
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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())
}
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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())
}
}

View File

@ -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 {

View File

@ -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!()
}
}

View File

@ -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 {

View File

@ -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())
}
}

View File

@ -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)
}
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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)
}
}

View File

@ -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())?;

View File

@ -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())?;

View File

@ -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())?;

View File

@ -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())?;

View File

@ -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
View 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
View 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
View 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,
},
}

View 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),
}

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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));

View File

@ -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)
}