Use object map as catch error value.
This commit is contained in:
parent
66b557692b
commit
8eee21ff38
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user