Use object map as catch error value.

This commit is contained in:
Stephen Chung 2021-02-28 14:38:34 +08:00
parent 66b557692b
commit 8eee21ff38
5 changed files with 117 additions and 13 deletions

View File

@ -8,16 +8,20 @@ Bug fixes
---------
* Errors in native Rust functions now contain the correct function call positions.
* Fixed error types in `EvalAltResult::ErrorMismatchDataType` which were swapped.
Breaking changes
----------------
* Zero step in the `range` function now raises an error instead of creating an infinite stream.
* Error variable captured by `catch` is now an _object map_ containing error fields.
* `EvalAltResult::clear_position` is renamed `EvalAltResult::take_position` and returns the position taken.
Enhancements
------------
* `range` function now supports negative step and decreasing streams (i.e. to < from).
* More information is provided to the error variable captured by the `catch` statement in an _object map_.
Version 0.19.13

View File

@ -13,8 +13,7 @@ use std::{
/// Pretty-print error.
fn print_error(input: &str, mut err: EvalAltResult) {
let lines: Vec<_> = input.trim().split('\n').collect();
let pos = err.position();
err.clear_position();
let pos = err.take_position();
let line_no = if lines.len() > 1 {
if pos.is_none() {

View File

@ -23,8 +23,7 @@ fn eprint_error(input: &str, mut err: EvalAltResult) {
let lines: Vec<_> = input.split('\n').collect();
// Print error
let pos = err.position();
err.clear_position();
let pos = err.take_position();
if pos.is_none() {
// No position

View File

@ -422,8 +422,8 @@ impl<'a> Target<'a> {
// Replace the character at the specified index position
let new_ch = new_val.as_char().map_err(|err| {
Box::new(EvalAltResult::ErrorMismatchDataType(
err.to_string(),
"char".to_string(),
err.to_string(),
pos,
))
})?;
@ -2245,19 +2245,55 @@ impl Engine {
Err(err) if err.is_pseudo_error() => Err(err),
Err(err) if !err.is_catchable() => Err(err),
Err(mut err) => {
let value = match *err {
let err_value = match *err {
EvalAltResult::ErrorRuntime(ref x, _) => x.clone(),
#[cfg(feature = "no_object")]
_ => {
err.set_position(Position::NONE);
err.take_position();
err.to_string().into()
}
#[cfg(not(feature = "no_object"))]
_ => {
use crate::INT;
let mut err_map: Map = Default::default();
let err_pos = err.take_position();
err_map.insert("message".into(), err.to_string().into());
if let Some(ref source) = state.source {
err_map.insert("source".into(), source.clone().into());
}
if err_pos.is_none() {
// No position info
} else {
err_map.insert(
"line".into(),
(err_pos.line().unwrap() as INT).into(),
);
err_map.insert(
"position".into(),
if err_pos.is_beginning_of_line() {
0
} else {
err_pos.position().unwrap() as INT
}
.into(),
);
}
err.dump_fields(&mut err_map);
err_map.into()
}
};
let orig_scope_len = scope.len();
state.scope_level += 1;
if let Some(Ident { name, .. }) = err_var {
scope.push(unsafe_cast_var_name_to_lifetime(&name), value);
scope.push(unsafe_cast_var_name_to_lifetime(&name), err_value);
}
let result =
@ -2589,8 +2625,8 @@ impl Engine {
#[inline(always)]
pub(crate) fn make_type_mismatch_err<T>(&self, typ: &str, pos: Position) -> Box<EvalAltResult> {
EvalAltResult::ErrorMismatchDataType(
typ.into(),
self.map_type_name(type_name::<T>()).into(),
typ.into(),
pos,
)
.into()

View File

@ -274,7 +274,7 @@ impl<T: AsRef<str>> From<T> for Box<EvalAltResult> {
impl EvalAltResult {
/// Is this a pseudo error? A pseudo error is one that does not occur naturally.
///
/// [`LoopBreak`][EvalAltResult::LoopBreak] or [`Return`][EvalAltResult::Return] are pseudo errors.
/// [`LoopBreak`][EvalAltResult::LoopBreak] and [`Return`][EvalAltResult::Return] are pseudo errors.
pub fn is_pseudo_error(&self) -> bool {
match self {
Self::LoopBreak(_, _) | Self::Return(_, _) => true,
@ -344,6 +344,69 @@ impl EvalAltResult {
}
}
/// Get the [position][Position] of this error.
#[cfg(not(feature = "no_object"))]
pub(crate) fn dump_fields(&self, map: &mut crate::Map) {
map.insert(
"error".into(),
format!("{:?}", self).split('(').next().unwrap().into(),
);
match self {
Self::LoopBreak(_, _) | Self::Return(_, _) => (),
Self::ErrorSystem(_, _)
| Self::ErrorParsing(_, _)
| Self::ErrorUnboundThis(_)
| Self::ErrorFor(_)
| Self::ErrorInExpr(_)
| Self::ErrorArithmetic(_, _)
| Self::ErrorTooManyOperations(_)
| Self::ErrorTooManyModules(_)
| Self::ErrorStackOverflow(_)
| Self::ErrorRuntime(_, _) => (),
Self::ErrorFunctionNotFound(f, _) => {
map.insert("function".into(), f.into());
}
Self::ErrorInFunctionCall(f, s, _, _) => {
map.insert("function".into(), f.into());
map.insert("source".into(), s.into());
}
Self::ErrorInModule(m, _, _) => {
map.insert("module".into(), m.into());
}
Self::ErrorMismatchDataType(r, a, _) | Self::ErrorMismatchOutputType(r, a, _) => {
map.insert("requested".into(), r.into());
map.insert("actual".into(), a.into());
}
Self::ErrorArrayBounds(n, i, _) | Self::ErrorStringBounds(n, i, _) => {
map.insert("length".into(), (*n as INT).into());
map.insert("index".into(), (*i as INT).into());
}
Self::ErrorIndexingType(t, _) => {
map.insert("type".into(), t.into());
}
Self::ErrorVariableNotFound(v, _)
| Self::ErrorDataRace(v, _)
| Self::ErrorAssignmentToConstant(v, _) => {
map.insert("variable".into(), v.into());
}
Self::ErrorModuleNotFound(m, _) => {
map.insert("module".into(), m.into());
}
Self::ErrorDotExpr(p, _) => {
map.insert("property".into(), p.into());
}
Self::ErrorDataTooLarge(t, _) => {
map.insert("type".into(), t.into());
}
Self::ErrorTerminated(t, _) => {
map.insert("token".into(), t.clone());
}
};
}
/// Get the [position][Position] of this error.
pub fn position(&self) -> Position {
match self {
Self::ErrorSystem(_, _) => Position::NONE,
@ -376,10 +439,13 @@ impl EvalAltResult {
| Self::Return(_, pos) => *pos,
}
}
/// Clear the [position][Position] information of this error.
pub fn clear_position(&mut self) -> &mut Self {
/// Remove the [position][Position] information from this error and return it.
///
/// The [position][Position] of this error is set to [`NONE`][Position::NONE] afterwards.
pub fn take_position(&mut self) -> Position {
let pos = self.position();
self.set_position(Position::NONE);
self
pos
}
/// Override the [position][Position] of this error.
pub fn set_position(&mut self, new_position: Position) {