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 {
|
||||
AssignmentOperator::PlusEqual => {
|
||||
if let Some(left) = context.get_value(&self.identifier)? {
|
||||
left.add(right)?
|
||||
left.add(right, self.syntax_position)?
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::VariableIdentifierNotFound(self.identifier.clone()),
|
||||
@ -143,7 +143,7 @@ impl AbstractTree for Assignment {
|
||||
}
|
||||
AssignmentOperator::MinusEqual => {
|
||||
if let Some(left) = context.get_value(&self.identifier)? {
|
||||
left.subtract(right)?
|
||||
left.subtract(right, self.syntax_position)?
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::VariableIdentifierNotFound(self.identifier.clone()),
|
||||
|
@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
error::{RuntimeError, SyntaxError, ValidationError},
|
||||
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)]
|
||||
@ -11,6 +11,7 @@ pub struct IndexAssignment {
|
||||
index: Index,
|
||||
operator: AssignmentOperator,
|
||||
statement: Statement,
|
||||
position: SourcePosition,
|
||||
}
|
||||
|
||||
impl AbstractTree for IndexAssignment {
|
||||
@ -30,6 +31,7 @@ impl AbstractTree for IndexAssignment {
|
||||
index,
|
||||
operator,
|
||||
statement,
|
||||
position: node.range().into(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -60,7 +62,7 @@ impl AbstractTree for IndexAssignment {
|
||||
let new_value = match self.operator {
|
||||
AssignmentOperator::PlusEqual => {
|
||||
if let Some(previous_value) = context.get_value(index_identifier)? {
|
||||
previous_value.add(value)?
|
||||
previous_value.add(value, self.position)?
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::VariableIdentifierNotFound(index_identifier.clone()),
|
||||
@ -69,7 +71,7 @@ impl AbstractTree for IndexAssignment {
|
||||
}
|
||||
AssignmentOperator::MinusEqual => {
|
||||
if let Some(previous_value) = context.get_value(index_identifier)? {
|
||||
previous_value.subtract(value)?
|
||||
previous_value.subtract(value, self.position)?
|
||||
} else {
|
||||
Value::none()
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
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.
|
||||
@ -14,6 +15,7 @@ pub struct Math {
|
||||
left: Expression,
|
||||
operator: MathOperator,
|
||||
right: Expression,
|
||||
position: SourcePosition,
|
||||
}
|
||||
|
||||
impl AbstractTree for Math {
|
||||
@ -33,6 +35,7 @@ impl AbstractTree for Math {
|
||||
left,
|
||||
operator,
|
||||
right,
|
||||
position: node.range().into(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -49,11 +52,11 @@ impl AbstractTree for Math {
|
||||
let left = self.left.run(source, context)?;
|
||||
let right = self.right.run(source, context)?;
|
||||
let value = match self.operator {
|
||||
MathOperator::Add => left.add(right)?,
|
||||
MathOperator::Subtract => left.subtract(right)?,
|
||||
MathOperator::Multiply => left.multiply(right)?,
|
||||
MathOperator::Divide => left.divide(right)?,
|
||||
MathOperator::Modulo => left.modulo(right)?,
|
||||
MathOperator::Add => left.add(right, self.position)?,
|
||||
MathOperator::Subtract => left.subtract(right, self.position)?,
|
||||
MathOperator::Multiply => left.multiply(right, self.position)?,
|
||||
MathOperator::Divide => left.divide(right, self.position)?,
|
||||
MathOperator::Modulo => left.modulo(right, self.position)?,
|
||||
};
|
||||
|
||||
Ok(value)
|
||||
|
@ -45,7 +45,15 @@ impl Error {
|
||||
"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) => {
|
||||
let report = runtime_error.create_report(source);
|
||||
|
||||
|
@ -7,7 +7,6 @@ use std::{
|
||||
time,
|
||||
};
|
||||
|
||||
use colored::Colorize;
|
||||
use lyneate::Report;
|
||||
|
||||
use crate::{SourcePosition, Type, Value};
|
||||
|
@ -1,5 +1,6 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use lyneate::Report;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Identifier, SourcePosition, Type, TypeDefinition, Value};
|
||||
@ -12,24 +13,28 @@ pub enum ValidationError {
|
||||
CannotAdd {
|
||||
left: Value,
|
||||
right: Value,
|
||||
position: SourcePosition,
|
||||
},
|
||||
|
||||
/// Two value are incompatible for subtraction.
|
||||
CannotSubtract {
|
||||
left: Value,
|
||||
right: Value,
|
||||
position: SourcePosition,
|
||||
},
|
||||
|
||||
/// Two value are incompatible for multiplication.
|
||||
CannotMultiply {
|
||||
left: Value,
|
||||
right: Value,
|
||||
position: SourcePosition,
|
||||
},
|
||||
|
||||
/// Two value are incompatible for dividing.
|
||||
CannotDivide {
|
||||
left: Value,
|
||||
right: Value,
|
||||
position: SourcePosition,
|
||||
},
|
||||
|
||||
/// The attempted conversion is impossible.
|
||||
@ -146,6 +151,91 @@ pub enum 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(
|
||||
function_name: &str,
|
||||
expected: usize,
|
||||
|
@ -2,7 +2,7 @@
|
||||
use crate::{
|
||||
built_in_values::BuiltInValue,
|
||||
error::{rw_lock_error::RwLockError, RuntimeError, ValidationError},
|
||||
Identifier, Type, TypeSpecification,
|
||||
Identifier, SourcePosition, Type, TypeSpecification,
|
||||
};
|
||||
|
||||
use serde::{
|
||||
@ -258,7 +258,7 @@ impl Value {
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left + right)),
|
||||
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left + right as f64)),
|
||||
@ -270,51 +270,71 @@ impl Value {
|
||||
Ok(Value::List(list))
|
||||
}
|
||||
(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`.
|
||||
pub fn subtract(self, other: Self) -> Result<Value, ValidationError> {
|
||||
pub fn subtract(self, other: Self, position: SourcePosition) -> Result<Value, ValidationError> {
|
||||
match (self, other) {
|
||||
(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::Integer(left), Value::Float(right)) => Ok(Value::Float(left as f64 - 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`.
|
||||
pub fn multiply(self, other: Self) -> Result<Value, ValidationError> {
|
||||
pub fn multiply(self, other: Self, position: SourcePosition) -> Result<Value, ValidationError> {
|
||||
match (self, other) {
|
||||
(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::Integer(left), Value::Float(right)) => Ok(Value::Float(left as f64 * 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`.
|
||||
pub fn divide(self, other: Self) -> Result<Value, ValidationError> {
|
||||
pub fn divide(self, other: Self, position: SourcePosition) -> Result<Value, ValidationError> {
|
||||
match (self, other) {
|
||||
(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::Integer(left), Value::Float(right)) => Ok(Value::Float(left as f64 / 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`.
|
||||
pub fn modulo(self, other: Self) -> Result<Value, ValidationError> {
|
||||
pub fn modulo(self, other: Self, position: SourcePosition) -> Result<Value, ValidationError> {
|
||||
match (self, other) {
|
||||
(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::Integer(left), Value::Float(right)) => Ok(Value::Float(left as f64 % 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