1
0

Update error variants

This commit is contained in:
Jeff 2023-10-13 12:26:44 -04:00
parent f20f69afa4
commit c6675e87ba
5 changed files with 99 additions and 294 deletions

View File

@ -34,7 +34,8 @@ impl AbstractTree for FunctionCall {
"assert_equal" => Tool::AssertEqual,
"output" => Tool::Output,
"read" => Tool::Read,
_ => panic!(""),
"help" => Tool::Help,
_ => panic!("Tool name not recognized."),
};
FunctionName::Tool(tool)

View File

@ -2,7 +2,7 @@ use std::fs::read_to_string;
use serde::{Deserialize, Serialize};
use crate::{Error, Result, Value};
use crate::{Error, Result, Table, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub enum Tool {
@ -10,6 +10,7 @@ pub enum Tool {
AssertEqual,
Output,
Read,
Help,
}
impl Tool {
@ -27,10 +28,7 @@ impl Tool {
if values[0].as_boolean()? {
Value::Empty
} else {
return Err(Error::AssertEqualFailed {
expected: Value::Boolean(true),
actual: values[0].clone(),
});
return Err(Error::AssertFailed);
}
}
Tool::AssertEqual => {
@ -77,6 +75,41 @@ impl Tool {
Value::String(file_contents)
}
Tool::Help => {
if values.len() > 1 {
return Err(Error::ExpectedToolArgumentAmount {
tool_name: "help",
expected: 1,
actual: values.len(),
});
}
let mut help_table =
Table::new(vec!["name".to_string(), "description".to_string()]);
help_table.insert(vec![
Value::String("help".to_string()),
Value::String("List available tools.".to_string()),
])?;
help_table.insert(vec![
Value::String("assert".to_string()),
Value::String("Panic if an expression is false.".to_string()),
])?;
help_table.insert(vec![
Value::String("assert_equal".to_string()),
Value::String("Panic if two values are not equal.".to_string()),
])?;
help_table.insert(vec![
Value::String("output".to_string()),
Value::String("Emit a value to stdout.".to_string()),
])?;
help_table.insert(vec![
Value::String("read".to_string()),
Value::String("Get a file's content.".to_string()),
])?;
Value::Table(help_table)
}
};
Ok(value)

View File

@ -3,14 +3,13 @@
//! To deal with errors from dependencies, either create a new error variant
//! or use the MacroFailure variant if the error can only occur inside a macro.
use crate::{value::value_type::ValueType, value::Value, Identifier};
use crate::{value::Value, Identifier};
use std::{fmt, io, time::SystemTimeError};
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Clone, PartialEq)]
#[non_exhaustive]
pub enum Error {
UnexpectedSyntaxNode {
expected: &'static str,
@ -19,8 +18,6 @@ pub enum Error {
relevant_source: String,
},
ExpectedFieldName,
ExpectedChildNode {
empty_node_sexp: String,
},
@ -116,113 +113,14 @@ pub enum Error {
actual: Value,
},
/// Tried to append a child to a node such that the precedence of the child
/// is not higher. This error should never occur. If it does, please file a
/// bug report.
PrecedenceViolation,
/// A `VariableIdentifier` operation did not find its value in the context.
VariableIdentifierNotFound(String),
/// A `FunctionIdentifier` operation did not find its value in the context.
FunctionIdentifierNotFound(Identifier),
/// A value has the wrong type.
/// Only use this if there is no other error that describes the expected and
/// provided types in more detail.
TypeError {
/// The expected types.
expected: &'static [ValueType],
/// The actual value.
actual: Value,
},
/// An operator is used with a wrong combination of types.
WrongTypeCombination {
/// The operator that whose evaluation caused the error.
expected: ValueType,
/// The types that were used in the operator causing it to fail.
actual: ValueType,
},
/// An opening brace without a matching closing brace was found.
UnmatchedLBrace,
/// A closing brace without a matching opening brace was found.
UnmatchedRBrace,
/// Left of an opening brace or right of a closing brace is a token that does not expect the brace next to it.
/// For example, writing `4(5)` would yield this error, as the `4` does not have any operands.
MissingOperatorOutsideOfBrace,
/// An addition operation performed by Rust failed.
AdditionError {
/// The first argument of the addition.
augend: Value,
/// The second argument of the addition.
addend: Value,
},
/// A subtraction operation performed by Rust failed.
SubtractionError {
/// The first argument of the subtraction.
minuend: Value,
/// The second argument of the subtraction.
subtrahend: Value,
},
/// A negation operation performed by Rust failed.
NegationError {
/// The argument of the negation.
argument: Value,
},
/// A multiplication operation performed by Rust failed.
MultiplicationError {
/// The first argument of the multiplication.
multiplicand: Value,
/// The second argument of the multiplication.
multiplier: Value,
},
/// A division operation performed by Rust failed.
DivisionError {
/// The first argument of the division.
dividend: Value,
/// The second argument of the division.
divisor: Value,
},
/// A modulation operation performed by Rust failed.
ModulationError {
/// The first argument of the modulation.
dividend: Value,
/// The second argument of the modulation.
divisor: Value,
},
/// A regular expression could not be parsed
InvalidRegex {
/// The invalid regular expression
regex: String,
/// Failure message from the regex engine
message: String,
},
/// A modification was attempted on a `Context` that does not allow modifications.
ContextNotMutable,
/// An escape sequence within a string literal is illegal.
IllegalEscapeSequence(String),
/// This context does not allow enabling builtin functions.
BuiltinFunctionsCannotBeEnabled,
/// This context does not allow disabling builtin functions.
BuiltinFunctionsCannotBeDisabled,
/// The function failed due to an external error.
MacroFailure(String),
ToolFailure(String),
/// A custom error explained by its message.
CustomMessage(String),
@ -230,129 +128,55 @@ pub enum Error {
impl From<csv::Error> for Error {
fn from(value: csv::Error) -> Self {
Error::MacroFailure(value.to_string())
Error::ToolFailure(value.to_string())
}
}
impl From<json::Error> for Error {
fn from(value: json::Error) -> Self {
Error::MacroFailure(value.to_string())
Error::ToolFailure(value.to_string())
}
}
impl From<io::Error> for Error {
fn from(value: std::io::Error) -> Self {
Error::MacroFailure(value.to_string())
Error::ToolFailure(value.to_string())
}
}
impl From<git2::Error> for Error {
fn from(value: git2::Error) -> Self {
Error::MacroFailure(value.to_string())
Error::ToolFailure(value.to_string())
}
}
impl From<reqwest::Error> for Error {
fn from(value: reqwest::Error) -> Self {
Error::MacroFailure(value.to_string())
Error::ToolFailure(value.to_string())
}
}
impl From<serde_json::Error> for Error {
fn from(value: serde_json::Error) -> Self {
Error::MacroFailure(value.to_string())
Error::ToolFailure(value.to_string())
}
}
impl From<SystemTimeError> for Error {
fn from(value: SystemTimeError) -> Self {
Error::MacroFailure(value.to_string())
Error::ToolFailure(value.to_string())
}
}
impl From<trash::Error> for Error {
fn from(value: trash::Error) -> Self {
Error::MacroFailure(value.to_string())
Error::ToolFailure(value.to_string())
}
}
impl From<toml::de::Error> for Error {
fn from(value: toml::de::Error) -> Self {
Error::MacroFailure(value.to_string())
}
}
impl Error {
pub fn type_error(actual: Value, expected: &'static [ValueType]) -> Self {
Error::TypeError { actual, expected }
}
pub fn expected_string(actual: Value) -> Self {
Error::ExpectedString { actual }
}
pub fn expected_int(actual: Value) -> Self {
Error::ExpectedInt { actual }
}
pub fn expected_float(actual: Value) -> Self {
Error::ExpectedFloat { actual }
}
pub fn expected_number(actual: Value) -> Self {
Error::ExpectedNumber { actual }
}
pub fn expected_number_or_string(actual: Value) -> Self {
Error::ExpectedNumberOrString { actual }
}
pub fn expected_boolean(actual: Value) -> Self {
Error::ExpectedBoolean { actual }
}
pub fn expected_list(actual: Value) -> Self {
Error::ExpectedList { actual }
}
pub fn expected_fixed_len_list(expected_len: usize, actual: Value) -> Self {
Error::ExpectedFixedLenList {
expected_len,
actual,
}
}
pub fn expected_empty(actual: Value) -> Self {
Error::ExpectedEmpty { actual }
}
pub fn expected_map(actual: Value) -> Self {
Error::ExpectedMap { actual }
}
pub fn expected_table(actual: Value) -> Self {
Error::ExpectedTable { actual }
}
pub fn expected_function(actual: Value) -> Self {
Error::ExpectedFunction { actual }
}
pub fn expected_collection(actual: Value) -> Self {
Error::ExpectedCollection { actual }
}
/// Constructs `EvalexprError::InvalidRegex(regex)`
pub fn invalid_regex(regex: String, message: String) -> Self {
Error::InvalidRegex { regex, message }
}
}
/// Returns `Ok(())` if the given value is a string or a numeric.
pub fn expect_number_or_string(actual: &Value) -> Result<()> {
match actual {
Value::String(_) | Value::Float(_) | Value::Integer(_) => Ok(()),
_ => Err(Error::expected_number_or_string(actual.clone())),
Error::ToolFailure(value.to_string())
}
}
@ -438,10 +262,6 @@ impl fmt::Display for Error {
actual
)
}
PrecedenceViolation => write!(
f,
"Tried to append a node to another node with higher precedence."
),
VariableIdentifierNotFound(identifier) => write!(
f,
"Variable identifier is not bound to anything by context: {}.",
@ -452,75 +272,16 @@ impl fmt::Display for Error {
"Function identifier is not bound to anything by context: {}.",
identifier.inner()
),
TypeError { expected, actual } => {
write!(
f,
"Type Error. The value {actual} is not one of the following: {expected:?}.",
)
}
UnmatchedLBrace => write!(f, "Found an unmatched opening parenthesis '('."),
UnmatchedRBrace => write!(f, "Found an unmatched closing parenthesis ')'."),
MissingOperatorOutsideOfBrace { .. } => write!(
f,
"Found an opening parenthesis that is preceded by something that does not take \
any arguments on the right, or found a closing parenthesis that is succeeded by \
something that does not take any arguments on the left."
),
AdditionError { augend, addend } => write!(f, "Error adding {} + {}", augend, addend),
SubtractionError {
minuend,
subtrahend,
} => write!(f, "Error subtracting {} - {}", minuend, subtrahend),
NegationError { argument } => write!(f, "Error negating -{}", argument),
MultiplicationError {
multiplicand,
multiplier,
} => write!(f, "Error multiplying {} * {}", multiplicand, multiplier),
DivisionError { dividend, divisor } => {
write!(f, "Error dividing {} / {}", dividend, divisor)
}
ModulationError { dividend, divisor } => {
write!(f, "Error modulating {} % {}", dividend, divisor)
}
InvalidRegex { regex, message } => write!(
f,
"Regular expression {:?} is invalid: {:?}",
regex, message
),
ContextNotMutable => write!(f, "Cannot manipulate context"),
BuiltinFunctionsCannotBeEnabled => {
write!(f, "This context does not allow enabling builtin functions")
}
BuiltinFunctionsCannotBeDisabled => {
write!(f, "This context does not allow disabling builtin functions")
}
IllegalEscapeSequence(string) => write!(f, "Illegal escape sequence: {}", string),
MacroFailure(message) => write!(f, "Function failure: {}", message),
CustomMessage(message) => write!(f, "Error: {}", message),
WrongColumnAmount { expected, actual } => write!(
f,
"Wrong number of columns for this table. Expected {expected}, found {actual}."
),
UnexpectedSyntaxNode {
expected,
actual,
location,
relevant_source
} => write!(
f,
"Unexpected syntax at {location}. Expected {expected}, but found {actual}. {relevant_source}"
),
ExpectedFieldName => write!(
f,
"Expected a field name for this node, but none was found."
),
WrongTypeCombination { expected, actual } => write!(
f,
"Wrong type combination. Expected {expected}, found {actual}."
),
ExpectedChildNode { empty_node_sexp } => {
write!(f, "Expected this node to have a child, {empty_node_sexp}.")
}
relevant_source,
} => todo!(),
ExpectedChildNode { empty_node_sexp } => todo!(),
WrongColumnAmount { expected, actual } => todo!(),
ToolFailure(_) => todo!(),
CustomMessage(_) => todo!(),
}
}
}

View File

@ -92,7 +92,9 @@ impl Value {
pub fn as_string(&self) -> Result<&String> {
match self {
Value::String(string) => Ok(string),
value => Err(Error::expected_string(value.clone())),
value => Err(Error::ExpectedString {
actual: value.clone(),
}),
}
}
@ -100,7 +102,9 @@ impl Value {
pub fn as_int(&self) -> Result<i64> {
match self {
Value::Integer(i) => Ok(*i),
value => Err(Error::expected_int(value.clone())),
value => Err(Error::ExpectedInt {
actual: value.clone(),
}),
}
}
@ -108,7 +112,9 @@ impl Value {
pub fn as_float(&self) -> Result<f64> {
match self {
Value::Float(f) => Ok(*f),
value => Err(Error::expected_float(value.clone())),
value => Err(Error::ExpectedFloat {
actual: value.clone(),
}),
}
}
@ -118,7 +124,9 @@ impl Value {
match self {
Value::Float(f) => Ok(*f),
Value::Integer(i) => Ok(*i as f64),
value => Err(Error::expected_number(value.clone())),
value => Err(Error::ExpectedNumber {
actual: value.clone(),
}),
}
}
@ -126,7 +134,9 @@ impl Value {
pub fn as_boolean(&self) -> Result<bool> {
match self {
Value::Boolean(boolean) => Ok(*boolean),
value => Err(Error::expected_boolean(value.clone())),
value => Err(Error::ExpectedBoolean {
actual: value.clone(),
}),
}
}
@ -134,7 +144,9 @@ impl Value {
pub fn as_list(&self) -> Result<&Vec<Value>> {
match self {
Value::List(list) => Ok(list),
value => Err(Error::expected_list(value.clone())),
value => Err(Error::ExpectedList {
actual: value.clone(),
}),
}
}
@ -142,21 +154,9 @@ impl Value {
pub fn into_inner_list(self) -> Result<Vec<Value>> {
match self {
Value::List(list) => Ok(list),
value => Err(Error::expected_list(value.clone())),
}
}
/// Borrows the value stored in `self` as `Vec<Value>` or returns `Err` if `self` is not a `Value::Map` of the required length.
pub fn as_fixed_len_list(&self, len: usize) -> Result<&Vec<Value>> {
match self {
Value::List(tuple) => {
if tuple.len() == len {
Ok(tuple)
} else {
Err(Error::expected_fixed_len_list(len, self.clone()))
}
}
value => Err(Error::expected_list(value.clone())),
value => Err(Error::ExpectedList {
actual: value.clone(),
}),
}
}
@ -164,7 +164,9 @@ impl Value {
pub fn as_map(&self) -> Result<&VariableMap> {
match self {
Value::Map(map) => Ok(map),
value => Err(Error::expected_map(value.clone())),
value => Err(Error::ExpectedMap {
actual: value.clone(),
}),
}
}
@ -172,7 +174,9 @@ impl Value {
pub fn as_table(&self) -> Result<&Table> {
match self {
Value::Table(table) => Ok(table),
value => Err(Error::expected_table(value.clone())),
value => Err(Error::ExpectedTable {
actual: value.clone(),
}),
}
}
@ -181,7 +185,9 @@ impl Value {
pub fn as_function(&self) -> Result<&Function> {
match self {
Value::Function(function) => Ok(function),
value => Err(Error::expected_function(value.clone())),
value => Err(Error::ExpectedFunction {
actual: value.clone(),
}),
}
}
@ -189,7 +195,9 @@ impl Value {
pub fn as_empty(&self) -> Result<()> {
match self {
Value::Empty => Ok(()),
value => Err(Error::expected_empty(value.clone())),
value => Err(Error::ExpectedEmpty {
actual: value.clone(),
}),
}
}
@ -199,7 +207,9 @@ impl Value {
Value::Table(table) => Ok(table.clone()),
Value::List(list) => Ok(Table::from(list)),
Value::Map(map) => Ok(Table::from(map)),
value => Err(Error::expected_table(value.clone())),
value => Err(Error::ExpectedTable {
actual: value.clone(),
}),
}
}
}

View File

@ -41,9 +41,9 @@ impl VariableMap {
let index = if let Ok(index) = next_identifier.parse::<usize>() {
index
} else {
return Err(Error::expected_int(Value::String(
next_identifier.to_string(),
)));
return Err(Error::ExpectedInt {
actual: Value::String(next_identifier.to_string()),
});
};
Ok(list.get(index).cloned())
@ -70,9 +70,9 @@ impl VariableMap {
let index = if let Ok(index) = next_identifier.parse::<usize>() {
index
} else {
return Err(Error::expected_int(Value::String(
next_identifier.to_string(),
)));
return Err(Error::ExpectedInt {
actual: Value::String(next_identifier.to_string()),
});
};
let mut missing_elements = index.saturating_sub(list.len()) + 1;