Simplify errors and make them fancier

This commit is contained in:
Jeff 2024-02-16 19:57:24 -05:00
parent fd33f330f7
commit 1094a5662c
6 changed files with 139 additions and 127 deletions

View File

@ -91,7 +91,9 @@ impl AbstractTree for Index {
Ok(Value::string(item.to_string())) Ok(Value::string(item.to_string()))
} }
_ => Err(RuntimeError::ExpectedCollection { actual: value }), _ => Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedCollection { actual: value },
)),
} }
} }
} }

View File

@ -7,7 +7,10 @@ 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, Context, EnumInstance, Format, Identifier, Type, Value}; use crate::{
error::{RuntimeError, ValidationError},
Context, EnumInstance, Format, Identifier, Type, Value,
};
use self::{fs::Fs, json::Json, str::StrFunction}; use self::{fs::Fs, json::Json, str::StrFunction};
@ -128,9 +131,11 @@ 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(RuntimeError::ExpectedCollection { return Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedCollection {
actual: value.clone(), actual: value.clone(),
}); },
));
}; };
Ok(Value::Integer(length as i64)) Ok(Value::Integer(length as i64))

View File

@ -7,6 +7,7 @@ pub(crate) mod rw_lock_error;
mod syntax_error; mod syntax_error;
mod validation_error; mod validation_error;
use colored::Colorize;
pub use runtime_error::RuntimeError; 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;
@ -35,9 +36,25 @@ impl Error {
/// used to create this error. /// used to create this error.
pub fn create_report(&self, source: &str) -> String { pub fn create_report(&self, source: &str) -> String {
match self { match self {
Error::Syntax(syntax_error) => syntax_error.create_report(source), Error::Syntax(syntax_error) => {
let report = syntax_error.create_report(source);
format!(
"{}\n{}\n{report}",
"Syntax Error".bold().yellow().underline(),
"Dust does not recognize this syntax.".dimmed()
)
}
Error::Validation(_) => todo!(), Error::Validation(_) => todo!(),
Error::Runtime(runtime_error) => runtime_error.create_report(source), Error::Runtime(runtime_error) => {
let report = runtime_error.create_report(source);
format!(
"{}\n{}\n{report}",
"Runtime Error".bold().red().underline(),
"This error occured while the program was running.".dimmed()
)
}
Error::ParserCancelled => todo!(), Error::ParserCancelled => todo!(),
Error::Language(_) => todo!(), Error::Language(_) => todo!(),
} }

View File

@ -46,71 +46,6 @@ pub enum RuntimeError {
Toml(toml::de::Error), Toml(toml::de::Error),
ExpectedString {
actual: Value,
},
ExpectedInteger {
actual: Value,
},
ExpectedFloat {
actual: Value,
},
/// An integer, floating point or value was expected.
ExpectedNumber {
actual: Value,
},
/// An integer, floating point or string value was expected.
ExpectedNumberOrString {
actual: Value,
},
ExpectedBoolean {
actual: Value,
},
ExpectedList {
actual: Value,
},
ExpectedMinLengthList {
minimum_len: usize,
actual_len: usize,
},
ExpectedFixedLenList {
expected_len: usize,
actual: Value,
},
ExpectedNone {
actual: Value,
},
ExpectedMap {
actual: Value,
},
ExpectedTable {
actual: Value,
},
ExpectedFunction {
actual: Value,
},
ExpectedOption {
actual: Value,
},
/// A string, list, map or table value was expected.
ExpectedCollection {
actual: Value,
},
/// Failed to read or write a map. /// Failed to read or write a map.
/// ///
/// See the [MapError] docs for more info. /// See the [MapError] docs for more info.
@ -140,17 +75,14 @@ impl RuntimeError {
vec![( vec![(
0..source.len(), 0..source.len(),
format!("\"assert_equal\" failed. {} != {}", expected, actual), format!("\"assert_equal\" failed. {} != {}", expected, actual),
(200, 100, 100), (200, 0, 0),
)] )]
} }
RuntimeError::AssertFailed { assertion } => todo!(), RuntimeError::AssertFailed { assertion } => todo!(),
RuntimeError::ConversionImpossible { from, to, position } => vec![( RuntimeError::ConversionImpossible { from, to, position } => vec![(
position.start_byte..position.end_byte, position.start_byte..position.end_byte,
format!( format!("Cannot convert from {from} to {to}."),
"Impossible conversion. {}", (255, 64, 112),
format!("Cannot convert from {from} to {to}.").dimmed()
),
(255, 100, 100),
)], )],
RuntimeError::Csv(_) => todo!(), RuntimeError::Csv(_) => todo!(),
RuntimeError::Io(_) => todo!(), RuntimeError::Io(_) => todo!(),
@ -158,27 +90,6 @@ impl RuntimeError {
RuntimeError::Json(_) => todo!(), RuntimeError::Json(_) => todo!(),
RuntimeError::SystemTime(_) => todo!(), RuntimeError::SystemTime(_) => todo!(),
RuntimeError::Toml(_) => todo!(), RuntimeError::Toml(_) => todo!(),
RuntimeError::ExpectedString { actual } => todo!(),
RuntimeError::ExpectedInteger { actual } => todo!(),
RuntimeError::ExpectedFloat { actual } => todo!(),
RuntimeError::ExpectedNumber { actual } => todo!(),
RuntimeError::ExpectedNumberOrString { actual } => todo!(),
RuntimeError::ExpectedBoolean { actual } => todo!(),
RuntimeError::ExpectedList { actual } => todo!(),
RuntimeError::ExpectedMinLengthList {
minimum_len,
actual_len,
} => todo!(),
RuntimeError::ExpectedFixedLenList {
expected_len,
actual,
} => todo!(),
RuntimeError::ExpectedNone { actual } => todo!(),
RuntimeError::ExpectedMap { actual } => todo!(),
RuntimeError::ExpectedTable { actual } => todo!(),
RuntimeError::ExpectedFunction { actual } => todo!(),
RuntimeError::ExpectedOption { actual } => todo!(),
RuntimeError::ExpectedCollection { actual } => todo!(),
RuntimeError::RwLock(_) => todo!(), RuntimeError::RwLock(_) => todo!(),
RuntimeError::ParseFloat(_) => todo!(), RuntimeError::ParseFloat(_) => todo!(),
RuntimeError::Utf8(_) => todo!(), RuntimeError::Utf8(_) => todo!(),

View File

@ -9,16 +9,28 @@ use super::rw_lock_error::RwLockError;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum ValidationError { pub enum ValidationError {
/// Two value are incompatible for addition. /// Two value are incompatible for addition.
CannotAdd { left: Value, right: Value }, CannotAdd {
left: Value,
right: Value,
},
/// Two value are incompatible for subtraction. /// Two value are incompatible for subtraction.
CannotSubtract { left: Value, right: Value }, CannotSubtract {
left: Value,
right: Value,
},
/// Two value are incompatible for multiplication. /// Two value are incompatible for multiplication.
CannotMultiply { left: Value, right: Value }, CannotMultiply {
left: Value,
right: Value,
},
/// Two value are incompatible for dividing. /// Two value are incompatible for dividing.
CannotDivide { left: Value, right: Value }, CannotDivide {
left: Value,
right: Value,
},
/// The attempted conversion is impossible. /// The attempted conversion is impossible.
ConversionImpossible { ConversionImpossible {
@ -26,6 +38,59 @@ pub enum ValidationError {
target_type: Type, target_type: Type,
}, },
ExpectedString {
actual: Value,
},
ExpectedInteger {
actual: Value,
},
ExpectedFloat {
actual: Value,
},
/// An integer, floating point or value was expected.
ExpectedNumber {
actual: Value,
},
/// An integer, floating point or string value was expected.
ExpectedNumberOrString {
actual: Value,
},
ExpectedBoolean {
actual: Value,
},
ExpectedList {
actual: Value,
},
ExpectedMinLengthList {
minimum_len: usize,
actual_len: usize,
},
ExpectedFixedLenList {
expected_len: usize,
actual: Value,
},
ExpectedMap {
actual: Value,
},
ExpectedFunction {
actual: Value,
},
/// A string, list, map or table value was expected.
ExpectedCollection {
actual: Value,
},
/// A built-in function was called with the wrong amount of arguments. /// A built-in function was called with the wrong amount of arguments.
ExpectedBuiltInFunctionArgumentAmount { ExpectedBuiltInFunctionArgumentAmount {
function_name: String, function_name: String,
@ -70,10 +135,14 @@ pub enum ValidationError {
TypeDefinitionNotFound(Identifier), TypeDefinitionNotFound(Identifier),
/// Failed to find an enum definition with this key. /// Failed to find an enum definition with this key.
ExpectedEnumDefintion { actual: TypeDefinition }, ExpectedEnumDefintion {
actual: TypeDefinition,
},
/// Failed to find a struct definition with this key. /// Failed to find a struct definition with this key.
ExpectedStructDefintion { actual: TypeDefinition }, ExpectedStructDefintion {
actual: TypeDefinition,
},
} }
impl ValidationError { impl ValidationError {

View File

@ -156,10 +156,10 @@ impl Value {
/// Borrows the value stored in `self` as `&String`, or returns `Err` if /// Borrows the value stored in `self` as `&String`, or returns `Err` if
/// `self` is not a `Value::String`. /// `self` is not a `Value::String`.
pub fn as_string(&self) -> Result<&String, RuntimeError> { pub fn as_string(&self) -> Result<&String, ValidationError> {
match self { match self {
Value::String(string) => Ok(string), Value::String(string) => Ok(string),
value => Err(RuntimeError::ExpectedString { value => Err(ValidationError::ExpectedString {
actual: value.clone(), actual: value.clone(),
}), }),
} }
@ -167,10 +167,10 @@ impl Value {
/// Copies the value stored in `self` as `i64`, or returns `Err` if `self` /// Copies the value stored in `self` as `i64`, or returns `Err` if `self`
/// is not a `Value::Int` /// is not a `Value::Int`
pub fn as_integer(&self) -> Result<i64, RuntimeError> { pub fn as_integer(&self) -> Result<i64, ValidationError> {
match self { match self {
Value::Integer(i) => Ok(*i), Value::Integer(i) => Ok(*i),
value => Err(RuntimeError::ExpectedInteger { value => Err(ValidationError::ExpectedInteger {
actual: value.clone(), actual: value.clone(),
}), }),
} }
@ -178,10 +178,10 @@ impl Value {
/// Copies the value stored in `self` as `f64`, or returns `Err` if `self` /// Copies the value stored in `self` as `f64`, or returns `Err` if `self`
/// is not a `Primitive::Float`. /// is not a `Primitive::Float`.
pub fn as_float(&self) -> Result<f64, RuntimeError> { pub fn as_float(&self) -> Result<f64, ValidationError> {
match self { match self {
Value::Float(f) => Ok(*f), Value::Float(f) => Ok(*f),
value => Err(RuntimeError::ExpectedFloat { value => Err(ValidationError::ExpectedFloat {
actual: value.clone(), actual: value.clone(),
}), }),
} }
@ -192,11 +192,11 @@ impl Value {
/// ///
/// Note that this method silently converts `i64` to `f64`, if `self` is /// Note that this method silently converts `i64` to `f64`, if `self` is
/// a `Value::Int`. /// a `Value::Int`.
pub fn as_number(&self) -> Result<f64, RuntimeError> { pub fn as_number(&self) -> Result<f64, ValidationError> {
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(RuntimeError::ExpectedNumber { value => Err(ValidationError::ExpectedNumber {
actual: value.clone(), actual: value.clone(),
}), }),
} }
@ -204,10 +204,10 @@ impl Value {
/// Copies the value stored in `self` as `bool`, or returns `Err` if `self` /// Copies the value stored in `self` as `bool`, or returns `Err` if `self`
/// is not a `Primitive::Boolean`. /// is not a `Primitive::Boolean`.
pub fn as_boolean(&self) -> Result<bool, RuntimeError> { pub fn as_boolean(&self) -> Result<bool, ValidationError> {
match self { match self {
Value::Boolean(boolean) => Ok(*boolean), Value::Boolean(boolean) => Ok(*boolean),
value => Err(RuntimeError::ExpectedBoolean { value => Err(ValidationError::ExpectedBoolean {
actual: value.clone(), actual: value.clone(),
}), }),
} }
@ -215,10 +215,10 @@ impl Value {
/// Borrows the value stored in `self` as `Vec<Value>`, or returns `Err` if /// Borrows the value stored in `self` as `Vec<Value>`, or returns `Err` if
/// `self` is not a `Value::List`. /// `self` is not a `Value::List`.
pub fn as_list(&self) -> Result<&List, RuntimeError> { pub fn as_list(&self) -> Result<&List, ValidationError> {
match self { match self {
Value::List(list) => Ok(list), Value::List(list) => Ok(list),
value => Err(RuntimeError::ExpectedList { value => Err(ValidationError::ExpectedList {
actual: value.clone(), actual: value.clone(),
}), }),
} }
@ -226,10 +226,10 @@ impl Value {
/// Takes ownership of the value stored in `self` as `Vec<Value>`, or /// Takes ownership of the value stored in `self` as `Vec<Value>`, or
/// returns `Err` if `self` is not a `Value::List`. /// returns `Err` if `self` is not a `Value::List`.
pub fn into_inner_list(self) -> Result<List, RuntimeError> { pub fn into_inner_list(self) -> Result<List, ValidationError> {
match self { match self {
Value::List(list) => Ok(list), Value::List(list) => Ok(list),
value => Err(RuntimeError::ExpectedList { value => Err(ValidationError::ExpectedList {
actual: value.clone(), actual: value.clone(),
}), }),
} }
@ -237,10 +237,10 @@ impl Value {
/// Borrows the value stored in `self` as `Vec<Value>`, or returns `Err` if /// Borrows the value stored in `self` as `Vec<Value>`, or returns `Err` if
/// `self` is not a `Value::Map`. /// `self` is not a `Value::Map`.
pub fn as_map(&self) -> Result<&Map, RuntimeError> { pub fn as_map(&self) -> Result<&Map, ValidationError> {
match self { match self {
Value::Map(map) => Ok(map), Value::Map(map) => Ok(map),
value => Err(RuntimeError::ExpectedMap { value => Err(ValidationError::ExpectedMap {
actual: value.clone(), actual: value.clone(),
}), }),
} }
@ -248,10 +248,10 @@ impl Value {
/// Borrows the value stored in `self` as `Function`, or returns `Err` if /// Borrows the value stored in `self` as `Function`, or returns `Err` if
/// `self` is not a `Value::Function`. /// `self` is not a `Value::Function`.
pub fn as_function(&self) -> Result<&Function, RuntimeError> { pub fn as_function(&self) -> Result<&Function, ValidationError> {
match self { match self {
Value::Function(function) => Ok(function), Value::Function(function) => Ok(function),
value => Err(RuntimeError::ExpectedFunction { value => Err(ValidationError::ExpectedFunction {
actual: value.clone(), actual: value.clone(),
}), }),
} }
@ -506,7 +506,9 @@ impl TryFrom<Value> for String {
if let Value::String(string) = value { if let Value::String(string) = value {
Ok(string) Ok(string)
} else { } else {
Err(RuntimeError::ExpectedString { actual: value }) Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedString { actual: value },
))
} }
} }
} }
@ -518,7 +520,9 @@ impl TryFrom<Value> for f64 {
if let Value::Float(value) = value { if let Value::Float(value) = value {
Ok(value) Ok(value)
} else { } else {
Err(RuntimeError::ExpectedFloat { actual: value }) Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedFloat { actual: value },
))
} }
} }
} }
@ -530,7 +534,9 @@ impl TryFrom<Value> for i64 {
if let Value::Integer(value) = value { if let Value::Integer(value) = value {
Ok(value) Ok(value)
} else { } else {
Err(RuntimeError::ExpectedInteger { actual: value }) Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedInteger { actual: value },
))
} }
} }
} }
@ -542,7 +548,9 @@ impl TryFrom<Value> for bool {
if let Value::Boolean(value) = value { if let Value::Boolean(value) = value {
Ok(value) Ok(value)
} else { } else {
Err(RuntimeError::ExpectedBoolean { actual: value }) Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedBoolean { actual: value },
))
} }
} }
} }