From fd33f330f7790f2885da6697ea87fc10f2c5710d Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 16 Feb 2024 18:54:00 -0500 Subject: [PATCH] Clean up errors; Add more pretty errors --- src/abstract_tree/as.rs | 17 ++++++- src/built_in_functions/mod.rs | 19 ++++---- src/error/mod.rs | 46 +++---------------- src/error/runtime_error.rs | 83 +++++++++++++++++++++++++++++++++-- src/error/syntax_error.rs | 27 ++++++++++++ src/error/validation_error.rs | 10 ----- tests/as.rs | 12 ++++- 7 files changed, 147 insertions(+), 67 deletions(-) diff --git a/src/abstract_tree/as.rs b/src/abstract_tree/as.rs index cad906e..e13de8f 100644 --- a/src/abstract_tree/as.rs +++ b/src/abstract_tree/as.rs @@ -90,11 +90,24 @@ impl AbstractTree for As { } _ => { return Err(RuntimeError::ConversionImpossible { - value, - target_type: self.r#type.clone(), + from: value.r#type()?, + to: self.r#type.clone(), + position: self.position.clone(), }); } } + } else if let Type::Integer = self.r#type { + match value { + Value::Integer(integer) => Value::Integer(integer), + Value::Float(float) => Value::Integer(float as i64), + _ => { + return Err(RuntimeError::ConversionImpossible { + from: value.r#type()?, + to: self.r#type.clone(), + position: self.position.clone(), + }) + } + } } else { todo!() }; diff --git a/src/built_in_functions/mod.rs b/src/built_in_functions/mod.rs index 8a603c6..f31dc5b 100644 --- a/src/built_in_functions/mod.rs +++ b/src/built_in_functions/mod.rs @@ -102,21 +102,18 @@ impl Callable for BuiltInFunction { let left = arguments.get(0).unwrap(); let right = arguments.get(1).unwrap(); - let result = if left == right { - Value::Enum(EnumInstance::new( + if left == right { + Ok(Value::Enum(EnumInstance::new( Identifier::new("Result"), Identifier::new("Ok"), Some(Value::none()), - )) + ))) } else { - Value::Enum(EnumInstance::new( - Identifier::new("Result"), - Identifier::new("Error"), - Some(Value::none()), - )) - }; - - Ok(result) + Err(RuntimeError::AssertEqualFailed { + left: left.clone(), + right: right.clone(), + }) + } } BuiltInFunction::Fs(fs_function) => fs_function.call(arguments, _source, context), BuiltInFunction::Json(json_function) => json_function.call(arguments, _source, context), diff --git a/src/error/mod.rs b/src/error/mod.rs index 9dd7a5c..96a15d7 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -7,8 +7,6 @@ pub(crate) mod rw_lock_error; mod syntax_error; mod validation_error; -use colored::Colorize; -use lyneate::Report; pub use runtime_error::RuntimeError; pub use syntax_error::SyntaxError; pub use validation_error::ValidationError; @@ -36,43 +34,13 @@ impl Error { /// The `source` argument should be the full source code document that was /// used to create this error. pub fn create_report(&self, source: &str) -> String { - let markers = if let Error::Syntax(SyntaxError::InvalidSource { position }) = self { - vec![( - position.start_byte..position.end_byte, - format!( - "Invalid syntax from ({}, {}) to ({}, {}).", - position.start_row, - position.start_column, - position.end_row, - position.end_column, - ), - (255, 200, 100), - )] - } else if let Error::Syntax(SyntaxError::UnexpectedSyntaxNode { - expected, - actual, - position, - }) = self - { - vec![( - position.start_byte..position.end_byte, - format!( - "Unexpected syntax from ({}, {}) to ({}, {}). {}", - position.start_row, - position.start_column, - position.end_row, - position.end_column, - format!("Expected {} but got {}.", expected, actual).dimmed(), - ), - (255, 100, 100), - )] - } else { - vec![] - }; - - let report = Report::new_byte_spanned(source, markers); - - report.display_str() + match self { + Error::Syntax(syntax_error) => syntax_error.create_report(source), + Error::Validation(_) => todo!(), + Error::Runtime(runtime_error) => runtime_error.create_report(source), + Error::ParserCancelled => todo!(), + Error::Language(_) => todo!(), + } } } diff --git a/src/error/runtime_error.rs b/src/error/runtime_error.rs index 7a483a3..c24cbd0 100644 --- a/src/error/runtime_error.rs +++ b/src/error/runtime_error.rs @@ -7,16 +7,31 @@ use std::{ time, }; -use crate::{Type, Value}; +use colored::Colorize; +use lyneate::Report; + +use crate::{SourcePosition, Type, Value}; use super::{rw_lock_error::RwLockError, ValidationError}; #[derive(Debug, PartialEq)] pub enum RuntimeError { + /// The 'assert' macro did not resolve successfully. + AssertEqualFailed { + left: Value, + right: Value, + }, + + /// The 'assert' macro did not resolve successfully. + AssertFailed { + assertion: Value, + }, + /// The attempted conversion is impossible. ConversionImpossible { - value: Value, - target_type: Type, + from: Type, + to: Type, + position: SourcePosition, }, Csv(String), @@ -116,6 +131,68 @@ pub enum RuntimeError { } impl RuntimeError { + pub fn create_report(&self, source: &str) -> String { + let messages = match self { + RuntimeError::AssertEqualFailed { + left: expected, + right: actual, + } => { + vec![( + 0..source.len(), + format!("\"assert_equal\" failed. {} != {}", expected, actual), + (200, 100, 100), + )] + } + 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), + )], + RuntimeError::Csv(_) => todo!(), + RuntimeError::Io(_) => todo!(), + RuntimeError::Reqwest(_) => todo!(), + 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!(), + RuntimeError::ExpectedBuiltInFunctionArgumentAmount { + function_name, + expected, + actual, + } => todo!(), + RuntimeError::ValidationFailure(_) => todo!(), + }; + + Report::new_byte_spanned(source, messages).display_str() + } + pub fn expect_argument_amount( function_name: &str, expected: usize, diff --git a/src/error/syntax_error.rs b/src/error/syntax_error.rs index c30a2d4..9f3cc76 100644 --- a/src/error/syntax_error.rs +++ b/src/error/syntax_error.rs @@ -1,5 +1,6 @@ use std::fmt::{self, Display, Formatter}; +use lyneate::Report; use serde::{Deserialize, Serialize}; use tree_sitter::Node as SyntaxNode; @@ -24,6 +25,32 @@ pub enum SyntaxError { } impl SyntaxError { + pub fn create_report(&self, source: &str) -> String { + let messages = match self { + SyntaxError::InvalidSource { position } => { + vec![( + position.start_byte..position.end_byte, + format!( + "Invalid syntax from ({}, {}) to ({}, {}).", + position.start_row, + position.start_column, + position.end_row, + position.end_column, + ), + (255, 200, 100), + )] + } + SyntaxError::RwLock(_) => todo!(), + SyntaxError::UnexpectedSyntaxNode { + expected, + actual, + position, + } => todo!(), + }; + + Report::new_byte_spanned(source, messages).display_str() + } + pub fn expect_syntax_node(expected: &str, actual: SyntaxNode) -> Result<(), SyntaxError> { log::info!("Converting {} to abstract node", actual.kind()); diff --git a/src/error/validation_error.rs b/src/error/validation_error.rs index c4d32f5..a1a4808 100644 --- a/src/error/validation_error.rs +++ b/src/error/validation_error.rs @@ -8,16 +8,6 @@ use super::rw_lock_error::RwLockError; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum ValidationError { - /// The 'assert' macro did not resolve successfully. - AssertEqualFailed { - expected: Value, - actual: Value, - position: SourcePosition, - }, - - /// The 'assert' macro did not resolve successfully. - AssertFailed { position: SourcePosition }, - /// Two value are incompatible for addition. CannotAdd { left: Value, right: Value }, diff --git a/tests/as.rs b/tests/as.rs index 5f6a29d..2b3e1fe 100644 --- a/tests/as.rs +++ b/tests/as.rs @@ -38,8 +38,16 @@ fn conversion_runtime_error() { assert_eq!( interpret(&format!("json:parse('{JSON}') as [map]")), Err(Error::Runtime(RuntimeError::ConversionImpossible { - value: json_value, - target_type: Type::List(Box::new(Type::Map)) + from: json_value.r#type().unwrap(), + to: Type::List(Box::new(Type::Map)), + position: SourcePosition { + start_byte: 0, + end_byte: 0, + start_row: 0, + start_column: 0, + end_row: 0, + end_column: 0 + } })) ) }