From 1094a5662c77fc88e090c2cf5d8147d74a0c9157 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 16 Feb 2024 19:57:24 -0500 Subject: [PATCH] Simplify errors and make them fancier --- src/abstract_tree/index.rs | 4 +- src/built_in_functions/mod.rs | 13 +++-- src/error/mod.rs | 21 +++++++- src/error/runtime_error.rs | 95 ++--------------------------------- src/error/validation_error.rs | 81 ++++++++++++++++++++++++++--- src/value/mod.rs | 52 +++++++++++-------- 6 files changed, 139 insertions(+), 127 deletions(-) diff --git a/src/abstract_tree/index.rs b/src/abstract_tree/index.rs index ac564af..5a927c3 100644 --- a/src/abstract_tree/index.rs +++ b/src/abstract_tree/index.rs @@ -91,7 +91,9 @@ impl AbstractTree for Index { Ok(Value::string(item.to_string())) } - _ => Err(RuntimeError::ExpectedCollection { actual: value }), + _ => Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedCollection { actual: value }, + )), } } } diff --git a/src/built_in_functions/mod.rs b/src/built_in_functions/mod.rs index f31dc5b..ec4cdd8 100644 --- a/src/built_in_functions/mod.rs +++ b/src/built_in_functions/mod.rs @@ -7,7 +7,10 @@ use std::fmt::{self, Display, Formatter}; use rand::{random, thread_rng, Rng}; 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}; @@ -128,9 +131,11 @@ impl Callable for BuiltInFunction { } else if let Ok(str) = value.as_string() { str.chars().count() } else { - return Err(RuntimeError::ExpectedCollection { - actual: value.clone(), - }); + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedCollection { + actual: value.clone(), + }, + )); }; Ok(Value::Integer(length as i64)) diff --git a/src/error/mod.rs b/src/error/mod.rs index 96a15d7..5c88de5 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -7,6 +7,7 @@ pub(crate) mod rw_lock_error; mod syntax_error; mod validation_error; +use colored::Colorize; pub use runtime_error::RuntimeError; pub use syntax_error::SyntaxError; pub use validation_error::ValidationError; @@ -35,9 +36,25 @@ impl Error { /// used to create this error. pub fn create_report(&self, source: &str) -> String { 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::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::Language(_) => todo!(), } diff --git a/src/error/runtime_error.rs b/src/error/runtime_error.rs index c24cbd0..2878700 100644 --- a/src/error/runtime_error.rs +++ b/src/error/runtime_error.rs @@ -46,71 +46,6 @@ pub enum RuntimeError { 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. /// /// See the [MapError] docs for more info. @@ -140,17 +75,14 @@ impl RuntimeError { vec![( 0..source.len(), format!("\"assert_equal\" failed. {} != {}", expected, actual), - (200, 100, 100), + (200, 0, 0), )] } RuntimeError::AssertFailed { assertion } => todo!(), RuntimeError::ConversionImpossible { from, to, position } => vec![( position.start_byte..position.end_byte, - format!( - "Impossible conversion. {}", - format!("Cannot convert from {from} to {to}.").dimmed() - ), - (255, 100, 100), + format!("Cannot convert from {from} to {to}."), + (255, 64, 112), )], RuntimeError::Csv(_) => todo!(), RuntimeError::Io(_) => todo!(), @@ -158,27 +90,6 @@ impl RuntimeError { RuntimeError::Json(_) => todo!(), RuntimeError::SystemTime(_) => 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::ParseFloat(_) => todo!(), RuntimeError::Utf8(_) => todo!(), diff --git a/src/error/validation_error.rs b/src/error/validation_error.rs index a1a4808..aafa44e 100644 --- a/src/error/validation_error.rs +++ b/src/error/validation_error.rs @@ -9,16 +9,28 @@ use super::rw_lock_error::RwLockError; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum ValidationError { /// Two value are incompatible for addition. - CannotAdd { left: Value, right: Value }, + CannotAdd { + left: Value, + right: Value, + }, /// Two value are incompatible for subtraction. - CannotSubtract { left: Value, right: Value }, + CannotSubtract { + left: Value, + right: Value, + }, /// Two value are incompatible for multiplication. - CannotMultiply { left: Value, right: Value }, + CannotMultiply { + left: Value, + right: Value, + }, /// Two value are incompatible for dividing. - CannotDivide { left: Value, right: Value }, + CannotDivide { + left: Value, + right: Value, + }, /// The attempted conversion is impossible. ConversionImpossible { @@ -26,6 +38,59 @@ pub enum ValidationError { 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. ExpectedBuiltInFunctionArgumentAmount { function_name: String, @@ -70,10 +135,14 @@ pub enum ValidationError { TypeDefinitionNotFound(Identifier), /// Failed to find an enum definition with this key. - ExpectedEnumDefintion { actual: TypeDefinition }, + ExpectedEnumDefintion { + actual: TypeDefinition, + }, /// Failed to find a struct definition with this key. - ExpectedStructDefintion { actual: TypeDefinition }, + ExpectedStructDefintion { + actual: TypeDefinition, + }, } impl ValidationError { diff --git a/src/value/mod.rs b/src/value/mod.rs index c481fdf..fcbac3f 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -156,10 +156,10 @@ impl Value { /// Borrows the value stored in `self` as `&String`, or returns `Err` if /// `self` is not a `Value::String`. - pub fn as_string(&self) -> Result<&String, RuntimeError> { + pub fn as_string(&self) -> Result<&String, ValidationError> { match self { Value::String(string) => Ok(string), - value => Err(RuntimeError::ExpectedString { + value => Err(ValidationError::ExpectedString { actual: value.clone(), }), } @@ -167,10 +167,10 @@ impl Value { /// Copies the value stored in `self` as `i64`, or returns `Err` if `self` /// is not a `Value::Int` - pub fn as_integer(&self) -> Result { + pub fn as_integer(&self) -> Result { match self { Value::Integer(i) => Ok(*i), - value => Err(RuntimeError::ExpectedInteger { + value => Err(ValidationError::ExpectedInteger { actual: value.clone(), }), } @@ -178,10 +178,10 @@ impl Value { /// Copies the value stored in `self` as `f64`, or returns `Err` if `self` /// is not a `Primitive::Float`. - pub fn as_float(&self) -> Result { + pub fn as_float(&self) -> Result { match self { Value::Float(f) => Ok(*f), - value => Err(RuntimeError::ExpectedFloat { + value => Err(ValidationError::ExpectedFloat { actual: value.clone(), }), } @@ -192,11 +192,11 @@ impl Value { /// /// Note that this method silently converts `i64` to `f64`, if `self` is /// a `Value::Int`. - pub fn as_number(&self) -> Result { + pub fn as_number(&self) -> Result { match self { Value::Float(f) => Ok(*f), Value::Integer(i) => Ok(*i as f64), - value => Err(RuntimeError::ExpectedNumber { + value => Err(ValidationError::ExpectedNumber { actual: value.clone(), }), } @@ -204,10 +204,10 @@ impl Value { /// Copies the value stored in `self` as `bool`, or returns `Err` if `self` /// is not a `Primitive::Boolean`. - pub fn as_boolean(&self) -> Result { + pub fn as_boolean(&self) -> Result { match self { Value::Boolean(boolean) => Ok(*boolean), - value => Err(RuntimeError::ExpectedBoolean { + value => Err(ValidationError::ExpectedBoolean { actual: value.clone(), }), } @@ -215,10 +215,10 @@ impl Value { /// Borrows the value stored in `self` as `Vec`, or returns `Err` if /// `self` is not a `Value::List`. - pub fn as_list(&self) -> Result<&List, RuntimeError> { + pub fn as_list(&self) -> Result<&List, ValidationError> { match self { Value::List(list) => Ok(list), - value => Err(RuntimeError::ExpectedList { + value => Err(ValidationError::ExpectedList { actual: value.clone(), }), } @@ -226,10 +226,10 @@ impl Value { /// Takes ownership of the value stored in `self` as `Vec`, or /// returns `Err` if `self` is not a `Value::List`. - pub fn into_inner_list(self) -> Result { + pub fn into_inner_list(self) -> Result { match self { Value::List(list) => Ok(list), - value => Err(RuntimeError::ExpectedList { + value => Err(ValidationError::ExpectedList { actual: value.clone(), }), } @@ -237,10 +237,10 @@ impl Value { /// Borrows the value stored in `self` as `Vec`, or returns `Err` if /// `self` is not a `Value::Map`. - pub fn as_map(&self) -> Result<&Map, RuntimeError> { + pub fn as_map(&self) -> Result<&Map, ValidationError> { match self { Value::Map(map) => Ok(map), - value => Err(RuntimeError::ExpectedMap { + value => Err(ValidationError::ExpectedMap { actual: value.clone(), }), } @@ -248,10 +248,10 @@ impl Value { /// Borrows the value stored in `self` as `Function`, or returns `Err` if /// `self` is not a `Value::Function`. - pub fn as_function(&self) -> Result<&Function, RuntimeError> { + pub fn as_function(&self) -> Result<&Function, ValidationError> { match self { Value::Function(function) => Ok(function), - value => Err(RuntimeError::ExpectedFunction { + value => Err(ValidationError::ExpectedFunction { actual: value.clone(), }), } @@ -506,7 +506,9 @@ impl TryFrom for String { if let Value::String(string) = value { Ok(string) } else { - Err(RuntimeError::ExpectedString { actual: value }) + Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedString { actual: value }, + )) } } } @@ -518,7 +520,9 @@ impl TryFrom for f64 { if let Value::Float(value) = value { Ok(value) } else { - Err(RuntimeError::ExpectedFloat { actual: value }) + Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedFloat { actual: value }, + )) } } } @@ -530,7 +534,9 @@ impl TryFrom for i64 { if let Value::Integer(value) = value { Ok(value) } else { - Err(RuntimeError::ExpectedInteger { actual: value }) + Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedInteger { actual: value }, + )) } } } @@ -542,7 +548,9 @@ impl TryFrom for bool { if let Value::Boolean(value) = value { Ok(value) } else { - Err(RuntimeError::ExpectedBoolean { actual: value }) + Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedBoolean { actual: value }, + )) } } }