Update error variants
This commit is contained in:
parent
f20f69afa4
commit
c6675e87ba
@ -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)
|
||||
|
@ -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)
|
||||
|
273
src/error.rs
273
src/error.rs
@ -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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user