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