1
0

Add fancy validation errors

This commit is contained in:
Jeff 2024-02-16 20:18:07 -05:00
parent 1094a5662c
commit a46d5bb4ea
7 changed files with 146 additions and 24 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -7,7 +7,6 @@ use std::{
time,
};
use colored::Colorize;
use lyneate::Report;
use crate::{SourcePosition, Type, Value};

View File

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

View File

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