Add fancy validation errors
This commit is contained in:
parent
1094a5662c
commit
a46d5bb4ea
@ -134,7 +134,7 @@ impl AbstractTree for Assignment {
|
|||||||
let new_value = match self.operator {
|
let new_value = match self.operator {
|
||||||
AssignmentOperator::PlusEqual => {
|
AssignmentOperator::PlusEqual => {
|
||||||
if let Some(left) = context.get_value(&self.identifier)? {
|
if let Some(left) = context.get_value(&self.identifier)? {
|
||||||
left.add(right)?
|
left.add(right, self.syntax_position)?
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::VariableIdentifierNotFound(self.identifier.clone()),
|
ValidationError::VariableIdentifierNotFound(self.identifier.clone()),
|
||||||
@ -143,7 +143,7 @@ impl AbstractTree for Assignment {
|
|||||||
}
|
}
|
||||||
AssignmentOperator::MinusEqual => {
|
AssignmentOperator::MinusEqual => {
|
||||||
if let Some(left) = context.get_value(&self.identifier)? {
|
if let Some(left) = context.get_value(&self.identifier)? {
|
||||||
left.subtract(right)?
|
left.subtract(right, self.syntax_position)?
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::VariableIdentifierNotFound(self.identifier.clone()),
|
ValidationError::VariableIdentifierNotFound(self.identifier.clone()),
|
||||||
|
@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::{RuntimeError, SyntaxError, ValidationError},
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
AbstractTree, AssignmentOperator, Context, Format, Identifier, Index, IndexExpression,
|
AbstractTree, AssignmentOperator, Context, Format, Identifier, Index, IndexExpression,
|
||||||
Statement, SyntaxNode, Type, Value,
|
SourcePosition, Statement, SyntaxNode, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
@ -11,6 +11,7 @@ pub struct IndexAssignment {
|
|||||||
index: Index,
|
index: Index,
|
||||||
operator: AssignmentOperator,
|
operator: AssignmentOperator,
|
||||||
statement: Statement,
|
statement: Statement,
|
||||||
|
position: SourcePosition,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for IndexAssignment {
|
impl AbstractTree for IndexAssignment {
|
||||||
@ -30,6 +31,7 @@ impl AbstractTree for IndexAssignment {
|
|||||||
index,
|
index,
|
||||||
operator,
|
operator,
|
||||||
statement,
|
statement,
|
||||||
|
position: node.range().into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +62,7 @@ impl AbstractTree for IndexAssignment {
|
|||||||
let new_value = match self.operator {
|
let new_value = match self.operator {
|
||||||
AssignmentOperator::PlusEqual => {
|
AssignmentOperator::PlusEqual => {
|
||||||
if let Some(previous_value) = context.get_value(index_identifier)? {
|
if let Some(previous_value) = context.get_value(index_identifier)? {
|
||||||
previous_value.add(value)?
|
previous_value.add(value, self.position)?
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::VariableIdentifierNotFound(index_identifier.clone()),
|
ValidationError::VariableIdentifierNotFound(index_identifier.clone()),
|
||||||
@ -69,7 +71,7 @@ impl AbstractTree for IndexAssignment {
|
|||||||
}
|
}
|
||||||
AssignmentOperator::MinusEqual => {
|
AssignmentOperator::MinusEqual => {
|
||||||
if let Some(previous_value) = context.get_value(index_identifier)? {
|
if let Some(previous_value) = context.get_value(index_identifier)? {
|
||||||
previous_value.subtract(value)?
|
previous_value.subtract(value, self.position)?
|
||||||
} else {
|
} else {
|
||||||
Value::none()
|
Value::none()
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{RuntimeError, SyntaxError, ValidationError},
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
AbstractTree, Context, Expression, Format, MathOperator, SyntaxNode, Type, Value,
|
AbstractTree, Context, Expression, Format, MathOperator, SourcePosition, SyntaxNode, Type,
|
||||||
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Abstract representation of a math operation.
|
/// Abstract representation of a math operation.
|
||||||
@ -14,6 +15,7 @@ pub struct Math {
|
|||||||
left: Expression,
|
left: Expression,
|
||||||
operator: MathOperator,
|
operator: MathOperator,
|
||||||
right: Expression,
|
right: Expression,
|
||||||
|
position: SourcePosition,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Math {
|
impl AbstractTree for Math {
|
||||||
@ -33,6 +35,7 @@ impl AbstractTree for Math {
|
|||||||
left,
|
left,
|
||||||
operator,
|
operator,
|
||||||
right,
|
right,
|
||||||
|
position: node.range().into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,11 +52,11 @@ impl AbstractTree for Math {
|
|||||||
let left = self.left.run(source, context)?;
|
let left = self.left.run(source, context)?;
|
||||||
let right = self.right.run(source, context)?;
|
let right = self.right.run(source, context)?;
|
||||||
let value = match self.operator {
|
let value = match self.operator {
|
||||||
MathOperator::Add => left.add(right)?,
|
MathOperator::Add => left.add(right, self.position)?,
|
||||||
MathOperator::Subtract => left.subtract(right)?,
|
MathOperator::Subtract => left.subtract(right, self.position)?,
|
||||||
MathOperator::Multiply => left.multiply(right)?,
|
MathOperator::Multiply => left.multiply(right, self.position)?,
|
||||||
MathOperator::Divide => left.divide(right)?,
|
MathOperator::Divide => left.divide(right, self.position)?,
|
||||||
MathOperator::Modulo => left.modulo(right)?,
|
MathOperator::Modulo => left.modulo(right, self.position)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(value)
|
Ok(value)
|
||||||
|
@ -45,7 +45,15 @@ impl Error {
|
|||||||
"Dust does not recognize this syntax.".dimmed()
|
"Dust does not recognize this syntax.".dimmed()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Error::Validation(_) => todo!(),
|
Error::Validation(validation_error) => {
|
||||||
|
let report = validation_error.create_report(source);
|
||||||
|
|
||||||
|
format!(
|
||||||
|
"{}\n{}\n{report}",
|
||||||
|
"Validation Error".bold().yellow().underline(),
|
||||||
|
"Dust prevented the program from running.".dimmed()
|
||||||
|
)
|
||||||
|
}
|
||||||
Error::Runtime(runtime_error) => {
|
Error::Runtime(runtime_error) => {
|
||||||
let report = runtime_error.create_report(source);
|
let report = runtime_error.create_report(source);
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ use std::{
|
|||||||
time,
|
time,
|
||||||
};
|
};
|
||||||
|
|
||||||
use colored::Colorize;
|
|
||||||
use lyneate::Report;
|
use lyneate::Report;
|
||||||
|
|
||||||
use crate::{SourcePosition, Type, Value};
|
use crate::{SourcePosition, Type, Value};
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
|
use lyneate::Report;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{Identifier, SourcePosition, Type, TypeDefinition, Value};
|
use crate::{Identifier, SourcePosition, Type, TypeDefinition, Value};
|
||||||
@ -12,24 +13,28 @@ pub enum ValidationError {
|
|||||||
CannotAdd {
|
CannotAdd {
|
||||||
left: Value,
|
left: Value,
|
||||||
right: Value,
|
right: Value,
|
||||||
|
position: SourcePosition,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Two value are incompatible for subtraction.
|
/// Two value are incompatible for subtraction.
|
||||||
CannotSubtract {
|
CannotSubtract {
|
||||||
left: Value,
|
left: Value,
|
||||||
right: Value,
|
right: Value,
|
||||||
|
position: SourcePosition,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Two value are incompatible for multiplication.
|
/// Two value are incompatible for multiplication.
|
||||||
CannotMultiply {
|
CannotMultiply {
|
||||||
left: Value,
|
left: Value,
|
||||||
right: Value,
|
right: Value,
|
||||||
|
position: SourcePosition,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Two value are incompatible for dividing.
|
/// Two value are incompatible for dividing.
|
||||||
CannotDivide {
|
CannotDivide {
|
||||||
left: Value,
|
left: Value,
|
||||||
right: Value,
|
right: Value,
|
||||||
|
position: SourcePosition,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// The attempted conversion is impossible.
|
/// The attempted conversion is impossible.
|
||||||
@ -146,6 +151,91 @@ pub enum ValidationError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ValidationError {
|
impl ValidationError {
|
||||||
|
pub fn create_report(&self, source: &str) -> String {
|
||||||
|
let messages = match self {
|
||||||
|
ValidationError::CannotAdd {
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
position,
|
||||||
|
} => vec![
|
||||||
|
((
|
||||||
|
position.start_byte..position.end_byte,
|
||||||
|
format!(""),
|
||||||
|
(255, 159, 64),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
ValidationError::CannotSubtract {
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
position,
|
||||||
|
} => todo!(),
|
||||||
|
ValidationError::CannotMultiply {
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
position,
|
||||||
|
} => todo!(),
|
||||||
|
ValidationError::CannotDivide {
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
position,
|
||||||
|
} => todo!(),
|
||||||
|
ValidationError::ConversionImpossible {
|
||||||
|
initial_type,
|
||||||
|
target_type,
|
||||||
|
} => todo!(),
|
||||||
|
ValidationError::ExpectedString { actual } => todo!(),
|
||||||
|
ValidationError::ExpectedInteger { actual } => todo!(),
|
||||||
|
ValidationError::ExpectedFloat { actual } => todo!(),
|
||||||
|
ValidationError::ExpectedNumber { actual } => todo!(),
|
||||||
|
ValidationError::ExpectedNumberOrString { actual } => todo!(),
|
||||||
|
ValidationError::ExpectedBoolean { actual } => todo!(),
|
||||||
|
ValidationError::ExpectedList { actual } => todo!(),
|
||||||
|
ValidationError::ExpectedMinLengthList {
|
||||||
|
minimum_len,
|
||||||
|
actual_len,
|
||||||
|
} => todo!(),
|
||||||
|
ValidationError::ExpectedFixedLenList {
|
||||||
|
expected_len,
|
||||||
|
actual,
|
||||||
|
} => todo!(),
|
||||||
|
ValidationError::ExpectedMap { actual } => todo!(),
|
||||||
|
ValidationError::ExpectedFunction { actual } => todo!(),
|
||||||
|
ValidationError::ExpectedCollection { actual } => todo!(),
|
||||||
|
ValidationError::ExpectedBuiltInFunctionArgumentAmount {
|
||||||
|
function_name,
|
||||||
|
expected,
|
||||||
|
actual,
|
||||||
|
} => todo!(),
|
||||||
|
ValidationError::ExpectedFunctionArgumentAmount {
|
||||||
|
expected,
|
||||||
|
actual,
|
||||||
|
position,
|
||||||
|
} => todo!(),
|
||||||
|
ValidationError::ExpectedFunctionArgumentMinimum {
|
||||||
|
minumum_expected,
|
||||||
|
actual,
|
||||||
|
position,
|
||||||
|
} => todo!(),
|
||||||
|
ValidationError::RwLock(_) => todo!(),
|
||||||
|
ValidationError::TypeCheck {
|
||||||
|
expected,
|
||||||
|
actual,
|
||||||
|
position,
|
||||||
|
} => vec![(
|
||||||
|
position.start_byte..position.end_byte,
|
||||||
|
format!("Type {actual} is incompatible with {expected}."),
|
||||||
|
(200, 200, 200),
|
||||||
|
)],
|
||||||
|
ValidationError::TypeCheckExpectedFunction { actual, position } => todo!(),
|
||||||
|
ValidationError::VariableIdentifierNotFound(_) => todo!(),
|
||||||
|
ValidationError::TypeDefinitionNotFound(_) => todo!(),
|
||||||
|
ValidationError::ExpectedEnumDefintion { actual } => todo!(),
|
||||||
|
ValidationError::ExpectedStructDefintion { actual } => todo!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Report::new_byte_spanned(source, messages).display_str()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn expect_argument_amount(
|
pub fn expect_argument_amount(
|
||||||
function_name: &str,
|
function_name: &str,
|
||||||
expected: usize,
|
expected: usize,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
built_in_values::BuiltInValue,
|
built_in_values::BuiltInValue,
|
||||||
error::{rw_lock_error::RwLockError, RuntimeError, ValidationError},
|
error::{rw_lock_error::RwLockError, RuntimeError, ValidationError},
|
||||||
Identifier, Type, TypeSpecification,
|
Identifier, SourcePosition, Type, TypeSpecification,
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::{
|
use serde::{
|
||||||
@ -258,7 +258,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return the sum of `self` and `other`.
|
/// Return the sum of `self` and `other`.
|
||||||
pub fn add(self, other: Self) -> Result<Value, ValidationError> {
|
pub fn add(self, other: Self, position: SourcePosition) -> Result<Value, ValidationError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left + right)),
|
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left + right)),
|
||||||
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left + right as f64)),
|
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left + right as f64)),
|
||||||
@ -270,51 +270,71 @@ impl Value {
|
|||||||
Ok(Value::List(list))
|
Ok(Value::List(list))
|
||||||
}
|
}
|
||||||
(Value::String(left), Value::String(right)) => Ok(Value::String(left + &right)),
|
(Value::String(left), Value::String(right)) => Ok(Value::String(left + &right)),
|
||||||
(left, right) => Err(ValidationError::CannotAdd { left, right }),
|
(left, right) => Err(ValidationError::CannotAdd {
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
position,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the difference of `self` and `other`.
|
/// Return the difference of `self` and `other`.
|
||||||
pub fn subtract(self, other: Self) -> Result<Value, ValidationError> {
|
pub fn subtract(self, other: Self, position: SourcePosition) -> Result<Value, ValidationError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left - right)),
|
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left - right)),
|
||||||
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left - right as f64)),
|
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left - right as f64)),
|
||||||
(Value::Integer(left), Value::Float(right)) => Ok(Value::Float(left as f64 - right)),
|
(Value::Integer(left), Value::Float(right)) => Ok(Value::Float(left as f64 - right)),
|
||||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left - right)),
|
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left - right)),
|
||||||
(left, right) => Err(ValidationError::CannotSubtract { left, right }),
|
(left, right) => Err(ValidationError::CannotSubtract {
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
position,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the product of `self` and `other`.
|
/// Return the product of `self` and `other`.
|
||||||
pub fn multiply(self, other: Self) -> Result<Value, ValidationError> {
|
pub fn multiply(self, other: Self, position: SourcePosition) -> Result<Value, ValidationError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left * right)),
|
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left * right)),
|
||||||
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left * right as f64)),
|
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left * right as f64)),
|
||||||
(Value::Integer(left), Value::Float(right)) => Ok(Value::Float(left as f64 * right)),
|
(Value::Integer(left), Value::Float(right)) => Ok(Value::Float(left as f64 * right)),
|
||||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left * right)),
|
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left * right)),
|
||||||
(left, right) => Err(ValidationError::CannotMultiply { left, right }),
|
(left, right) => Err(ValidationError::CannotMultiply {
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
position,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the quotient of `self` and `other`.
|
/// Return the quotient of `self` and `other`.
|
||||||
pub fn divide(self, other: Self) -> Result<Value, ValidationError> {
|
pub fn divide(self, other: Self, position: SourcePosition) -> Result<Value, ValidationError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left / right)),
|
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left / right)),
|
||||||
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left / right as f64)),
|
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left / right as f64)),
|
||||||
(Value::Integer(left), Value::Float(right)) => Ok(Value::Float(left as f64 / right)),
|
(Value::Integer(left), Value::Float(right)) => Ok(Value::Float(left as f64 / right)),
|
||||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left / right)),
|
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left / right)),
|
||||||
(left, right) => Err(ValidationError::CannotDivide { left, right }),
|
(left, right) => Err(ValidationError::CannotDivide {
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
position,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the remainder after diving `self` and `other`.
|
/// Return the remainder after diving `self` and `other`.
|
||||||
pub fn modulo(self, other: Self) -> Result<Value, ValidationError> {
|
pub fn modulo(self, other: Self, position: SourcePosition) -> Result<Value, ValidationError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left % right)),
|
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left % right)),
|
||||||
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left % right as f64)),
|
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left % right as f64)),
|
||||||
(Value::Integer(left), Value::Float(right)) => Ok(Value::Float(left as f64 % right)),
|
(Value::Integer(left), Value::Float(right)) => Ok(Value::Float(left as f64 % right)),
|
||||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left % right)),
|
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left % right)),
|
||||||
(left, right) => Err(ValidationError::CannotDivide { left, right }),
|
(left, right) => Err(ValidationError::CannotDivide {
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
position,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user