diff --git a/src/api.rs b/src/api.rs index e5af0c0d..77a870c7 100644 --- a/src/api.rs +++ b/src/api.rs @@ -24,12 +24,7 @@ use crate::stdlib::{fs::File, io::prelude::*, path::PathBuf}; impl<'e> Engine<'e> { /// Register a custom function. - pub(crate) fn register_fn_raw( - &mut self, - fn_name: &str, - args: Option>, - f: Box, - ) { + pub(crate) fn register_fn_raw(&mut self, fn_name: &str, args: Vec, f: Box) { let spec = FnSpec { name: fn_name.to_string().into(), args, @@ -180,8 +175,7 @@ impl<'e> Engine<'e> { name: &str, callback: impl Fn(&mut T) -> U + 'static, ) { - let get_fn_name = make_getter(name); - self.register_fn(&get_fn_name, callback); + self.register_fn(&make_getter(name), callback); } /// Register a setter function for a member of a registered type with the `Engine`. @@ -226,8 +220,7 @@ impl<'e> Engine<'e> { name: &str, callback: impl Fn(&mut T, U) -> () + 'static, ) { - let set_fn_name = make_setter(name); - self.register_fn(&set_fn_name, callback); + self.register_fn(&make_setter(name), callback); } /// Shorthand for registering both getter and setter functions @@ -353,8 +346,9 @@ impl<'e> Engine<'e> { let mut contents = String::new(); f.read_to_string(&mut contents) - .map_err(|err| EvalAltResult::ErrorReadingScriptFile(path.clone(), err)) - .map(|_| contents) + .map_err(|err| EvalAltResult::ErrorReadingScriptFile(path.clone(), err))?; + + Ok(contents) } /// Compile a script file into an `AST`, which can be used later for evaluation. @@ -559,8 +553,7 @@ impl<'e> Engine<'e> { /// # } /// ``` pub fn eval(&mut self, input: &str) -> Result { - let mut scope = Scope::new(); - self.eval_with_scope(&mut scope, input) + self.eval_with_scope(&mut Scope::new(), input) } /// Evaluate a string with own scope. @@ -609,8 +602,7 @@ impl<'e> Engine<'e> { /// # } /// ``` pub fn eval_expression(&mut self, input: &str) -> Result { - let mut scope = Scope::new(); - self.eval_expression_with_scope(&mut scope, input) + self.eval_expression_with_scope(&mut Scope::new(), input) } /// Evaluate a string containing an expression with own scope. @@ -662,8 +654,7 @@ impl<'e> Engine<'e> { /// # } /// ``` pub fn eval_ast(&mut self, ast: &AST) -> Result { - let mut scope = Scope::new(); - self.eval_ast_with_scope(&mut scope, ast) + self.eval_ast_with_scope(&mut Scope::new(), ast) } /// Evaluate an `AST` with own scope. @@ -701,8 +692,8 @@ impl<'e> Engine<'e> { ast: &AST, ) -> Result { self.eval_ast_with_scope_raw(scope, false, ast) - .and_then(|out| { - out.downcast::().map(|v| *v).map_err(|a| { + .and_then(|result| { + result.downcast::().map(|v| *v).map_err(|a| { EvalAltResult::ErrorMismatchOutputType( self.map_type_name((*a).type_name()).to_string(), Position::none(), @@ -717,34 +708,25 @@ impl<'e> Engine<'e> { retain_functions: bool, ast: &AST, ) -> Result { - fn eval_ast_internal( - engine: &mut Engine, - scope: &mut Scope, - retain_functions: bool, - ast: &AST, - ) -> Result { - if !retain_functions { - engine.clear_functions(); - } - - let statements = { - let AST(statements, functions) = ast; - engine.load_script_functions(functions); - statements - }; - - let result = statements.iter().try_fold(().into_dynamic(), |_, stmt| { - engine.eval_stmt(scope, stmt, 0) - })?; - - if !retain_functions { - engine.clear_functions(); - } - - Ok(result) + if !retain_functions { + self.clear_functions(); } - eval_ast_internal(self, scope, retain_functions, ast).or_else(|err| match err { + let statements = { + let AST(statements, functions) = ast; + self.load_script_functions(functions); + statements + }; + + let result = statements + .iter() + .try_fold(().into_dynamic(), |_, stmt| self.eval_stmt(scope, stmt, 0)); + + if !retain_functions { + self.clear_functions(); + } + + result.or_else(|err| match err { EvalAltResult::Return(out, _) => Ok(out), _ => Err(err), }) @@ -834,14 +816,13 @@ impl<'e> Engine<'e> { let result = statements .iter() - .try_fold(().into_dynamic(), |_, stmt| self.eval_stmt(scope, stmt, 0)) - .map(|_| ()); + .try_fold(().into_dynamic(), |_, stmt| self.eval_stmt(scope, stmt, 0)); if !retain_functions { self.clear_functions(); } - result.or_else(|err| match err { + result.map(|_| ()).or_else(|err| match err { EvalAltResult::Return(_, _) => Ok(()), _ => Err(err), }) diff --git a/src/engine.rs b/src/engine.rs index 2b24b099..4cbff988 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -48,17 +48,65 @@ pub(crate) const FUNC_SETTER: &str = "set$"; #[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)] #[cfg(not(feature = "no_index"))] enum IndexSourceType { + Expression, + String, Array, #[cfg(not(feature = "no_object"))] Map, - String, - Expression, +} + +#[derive(Debug, Eq, PartialEq, Hash, Clone)] +enum IndexValue { + Num(usize), + Str(String), +} + +impl IndexValue { + fn from_num(idx: INT) -> Self { + Self::Num(idx as usize) + } + fn from_str(name: String) -> Self { + Self::Str(name) + } + fn as_num(self) -> usize { + match self { + Self::Num(n) => n, + _ => panic!("index value is numeric"), + } + } + fn as_str(self) -> String { + match self { + Self::Str(s) => s, + _ => panic!("index value is string"), + } + } +} + +#[derive(Debug)] +enum Target<'a> { + Scope(ScopeSource<'a>), + Value(&'a mut Variant), +} + +impl<'a> Target<'a> { + fn from(value: &'a mut Variant) -> Self { + Self::Value(value) + } + fn from_src(src: ScopeSource<'a>) -> Self { + Self::Scope(src) + } + fn get_mut(self, scope: &'a mut Scope) -> &'a mut Variant { + match self { + Self::Value(t) => t, + Self::Scope(src) => scope.get_mut(src).as_mut(), + } + } } #[derive(Debug, Eq, PartialEq, Hash, Clone)] pub struct FnSpec<'a> { pub name: Cow<'a, str>, - pub args: Option>, + pub args: Vec, } /// A type that holds a library of script-defined functions. @@ -143,9 +191,9 @@ pub struct Engine<'e> { /// A hashmap mapping type names to pretty-print names. pub(crate) type_names: HashMap, - /// Closure for implementing the print commands. + /// Closure for implementing the `print` command. pub(crate) on_print: Box, - /// Closure for implementing the debug commands. + /// Closure for implementing the `debug` command. pub(crate) on_debug: Box, /// Optimize the AST after compilation. @@ -256,7 +304,7 @@ impl Engine<'_> { ) -> Result, EvalAltResult> { let spec = FnSpec { name: fn_name.into(), - args: Some(args.iter().map(|a| Any::type_id(&**a)).collect()), + args: args.iter().map(|a| Any::type_id(&**a)).collect(), }; // Search built-in's and external functions @@ -303,7 +351,7 @@ impl Engine<'_> { let spec = FnSpec { name: fn_name.into(), - args: Some(args.iter().map(|a| Any::type_id(&**a)).collect()), + args: args.iter().map(|a| Any::type_id(&**a)).collect(), }; // Argument must be a string @@ -386,40 +434,14 @@ impl Engine<'_> { } /// Chain-evaluate a dot setter. - /// - /// Either `src` or `target` should be `Some`. - /// - /// If `target` is `Some`, then it is taken as the reference to use for `this`. - /// - /// Otherwise, if `src` is `Some`, then it holds a name and index into `scope`; using `get_mut` on - /// `scope` can retrieve a mutable reference to the variable's value to use as `this`. #[cfg(not(feature = "no_object"))] fn get_dot_val_helper( &mut self, scope: &mut Scope, - src: Option, - target: Option<&mut Variant>, + target: Target, dot_rhs: &Expr, level: usize, ) -> Result { - // Get the `this` reference. Either `src` or `target` should be `Some`. - fn get_this_ptr<'a>( - scope: &'a mut Scope, - src: Option, - target: Option<&'a mut Variant>, - ) -> &'a mut Variant { - if let Some(t) = target { - // If `target` is `Some`, then it is returned. - t - } else { - // Otherwise, if `src` is `Some`, then it holds a name and index into `scope`; - // using `get_mut` on `scope` to retrieve a mutable reference for return. - scope - .get_mut(src.expect("expected source in scope")) - .as_mut() - } - } - match dot_rhs { // xxx.fn_name(args) Expr::FunctionCall(fn_name, arg_expr_list, def_val, pos) => { @@ -428,7 +450,7 @@ impl Engine<'_> { .map(|arg_expr| self.eval_expr(scope, arg_expr, level)) .collect::, _>>()?; - let this_ptr = get_this_ptr(scope, src, target); + let this_ptr = target.get_mut(scope); let mut arg_values: Vec<_> = once(this_ptr) .chain(values.iter_mut().map(Dynamic::as_mut)) @@ -439,9 +461,8 @@ impl Engine<'_> { // xxx.id Expr::Property(id, pos) => { - let get_fn_name = make_getter(id); - let this_ptr = get_this_ptr(scope, src, target); - self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0) + let this_ptr = target.get_mut(scope); + self.call_fn_raw(&make_getter(id), &mut [this_ptr], None, *pos, 0) } // xxx.idx_lhs[idx_expr] @@ -450,13 +471,12 @@ impl Engine<'_> { let val = match idx_lhs.as_ref() { // xxx.id[idx_expr] Expr::Property(id, pos) => { - let get_fn_name = make_getter(id); - let this_ptr = get_this_ptr(scope, src, target); - self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0)? + let this_ptr = target.get_mut(scope); + self.call_fn_raw(&make_getter(id), &mut [this_ptr], None, *pos, 0)? } // xxx.???[???][idx_expr] Expr::Index(_, _, _) => { - self.get_dot_val_helper(scope, src, target, idx_lhs, level)? + self.get_dot_val_helper(scope, target, idx_lhs, level)? } // Syntax error _ => { @@ -475,12 +495,10 @@ impl Engine<'_> { Expr::Dot(dot_lhs, rhs, _) => match dot_lhs.as_ref() { // xxx.id.rhs Expr::Property(id, pos) => { - let get_fn_name = make_getter(id); - let this_ptr = get_this_ptr(scope, src, target); - - self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0) + let this_ptr = target.get_mut(scope); + self.call_fn_raw(&make_getter(id), &mut [this_ptr], None, *pos, 0) .and_then(|mut v| { - self.get_dot_val_helper(scope, None, Some(v.as_mut()), rhs, level) + self.get_dot_val_helper(scope, Target::from(v.as_mut()), rhs, level) }) } // xxx.idx_lhs[idx_expr].rhs @@ -489,13 +507,12 @@ impl Engine<'_> { let val = match idx_lhs.as_ref() { // xxx.id[idx_expr].rhs Expr::Property(id, pos) => { - let get_fn_name = make_getter(id); - let this_ptr = get_this_ptr(scope, src, target); - self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0)? + let this_ptr = target.get_mut(scope); + self.call_fn_raw(&make_getter(id), &mut [this_ptr], None, *pos, 0)? } // xxx.???[???][idx_expr].rhs Expr::Index(_, _, _) => { - self.get_dot_val_helper(scope, src, target, idx_lhs, level)? + self.get_dot_val_helper(scope, target, idx_lhs, level)? } // Syntax error _ => { @@ -508,7 +525,7 @@ impl Engine<'_> { self.get_indexed_value(scope, &val, idx_expr, *op_pos, level) .and_then(|(mut v, _, _)| { - self.get_dot_val_helper(scope, None, Some(v.as_mut()), rhs, level) + self.get_dot_val_helper(scope, Target::from(v.as_mut()), rhs, level) }) } // Syntax error @@ -545,16 +562,16 @@ impl Engine<'_> { // This is a variable property access (potential function call). // Use a direct index into `scope` to directly mutate the variable value. - self.get_dot_val_helper(scope, Some(entry), None, dot_rhs, level) + self.get_dot_val_helper(scope, Target::from_src(entry), dot_rhs, level) } // idx_lhs[idx_expr].??? #[cfg(not(feature = "no_index"))] Expr::Index(idx_lhs, idx_expr, op_pos) => { - let (idx_src_type, src, idx, mut target) = + let (idx_src_type, src, idx, mut value) = self.eval_index_expr(scope, idx_lhs, idx_expr, *op_pos, level)?; - let this_ptr = target.as_mut(); - let val = self.get_dot_val_helper(scope, None, Some(this_ptr), dot_rhs, level); + let val = + self.get_dot_val_helper(scope, Target::from(value.as_mut()), dot_rhs, level); // In case the expression mutated `target`, we need to update it back into the scope because it is cloned. if let Some(src) = src { @@ -571,7 +588,7 @@ impl Engine<'_> { scope, src, idx, - (target, dot_rhs.position()), + (value, dot_rhs.position()), )?; } } @@ -582,9 +599,8 @@ impl Engine<'_> { // {expr}.??? expr => { - let mut target = self.eval_expr(scope, expr, level)?; - let this_ptr = target.as_mut(); - self.get_dot_val_helper(scope, None, Some(this_ptr), dot_rhs, level) + let mut value = self.eval_expr(scope, expr, level)?; + self.get_dot_val_helper(scope, Target::from(value.as_mut()), dot_rhs, level) } } } @@ -609,7 +625,7 @@ impl Engine<'_> { idx_expr: &Expr, op_pos: Position, level: usize, - ) -> Result<(Dynamic, IndexSourceType, (Option, Option)), EvalAltResult> { + ) -> Result<(Dynamic, IndexSourceType, IndexValue), EvalAltResult> { let idx_pos = idx_expr.position(); if val.is::() { @@ -624,7 +640,7 @@ impl Engine<'_> { return if idx >= 0 { arr.get(idx as usize) .cloned() - .map(|v| (v, IndexSourceType::Array, (Some(idx as usize), None))) + .map(|v| (v, IndexSourceType::Array, IndexValue::from_num(idx))) .ok_or_else(|| EvalAltResult::ErrorArrayBounds(arr.len(), idx, idx_pos)) } else { Err(EvalAltResult::ErrorArrayBounds(arr.len(), idx, idx_pos)) @@ -645,7 +661,7 @@ impl Engine<'_> { return Ok(( map.get(&idx).cloned().unwrap_or_else(|| ().into_dynamic()), IndexSourceType::Map, - (None, Some(idx)), + IndexValue::from_str(idx), )); } } @@ -666,7 +682,7 @@ impl Engine<'_> { ( ch.into_dynamic(), IndexSourceType::String, - (Some(idx as usize), None), + IndexValue::from_num(idx), ) }) .ok_or_else(|| { @@ -701,7 +717,7 @@ impl Engine<'_> { ( IndexSourceType, Option>, - (Option, Option), + IndexValue, Dynamic, ), EvalAltResult, @@ -763,14 +779,14 @@ impl Engine<'_> { idx_src_type: IndexSourceType, scope: &mut Scope, src: ScopeSource, - idx: (Option, Option), + idx: IndexValue, new_val: (Dynamic, Position), ) -> Result { match idx_src_type { // array_id[idx] = val IndexSourceType::Array => { let arr = scope.get_mut_by_type::(src); - arr[idx.0.expect("should be Some")] = new_val.0; + arr[idx.as_num()] = new_val.0; Ok(().into_dynamic()) } @@ -778,7 +794,7 @@ impl Engine<'_> { #[cfg(not(feature = "no_object"))] IndexSourceType::Map => { let arr = scope.get_mut_by_type::(src); - arr.insert(idx.1.expect("should be Some"), new_val.0); + arr.insert(idx.as_str(), new_val.0); Ok(().into_dynamic()) } @@ -791,7 +807,7 @@ impl Engine<'_> { .0 .downcast::() .map_err(|_| EvalAltResult::ErrorCharMismatch(pos))?; - Self::str_replace_char(s, idx.0.expect("should be Some"), ch); + Self::str_replace_char(s, idx.as_num(), ch); Ok(().into_dynamic()) } @@ -803,13 +819,13 @@ impl Engine<'_> { #[cfg(not(feature = "no_index"))] fn update_indexed_value( mut target: Dynamic, - idx: (Option, Option), + idx: IndexValue, new_val: Dynamic, pos: Position, ) -> Result { if target.is::() { let arr = target.downcast_mut::().expect("array expected"); - arr[idx.0.expect("should be Some")] = new_val; + arr[idx.as_num()] = new_val; return Ok(target); } @@ -817,7 +833,7 @@ impl Engine<'_> { { if target.is::() { let map = target.downcast_mut::().expect("array expected"); - map.insert(idx.1.expect("should be Some"), new_val); + map.insert(idx.as_str(), new_val); return Ok(target); } } @@ -828,7 +844,7 @@ impl Engine<'_> { let ch = *new_val .downcast::() .map_err(|_| EvalAltResult::ErrorCharMismatch(pos))?; - Self::str_replace_char(s, idx.0.expect("should be Some"), ch); + Self::str_replace_char(s, idx.as_num(), ch); return Ok(target); } @@ -849,9 +865,8 @@ impl Engine<'_> { match dot_rhs { // xxx.id Expr::Property(id, pos) => { - let set_fn_name = make_setter(id); let mut args = [this_ptr, new_val.0.as_mut()]; - self.call_fn_raw(&set_fn_name, &mut args, None, *pos, 0) + self.call_fn_raw(&make_setter(id), &mut args, None, *pos, 0) } // xxx.lhs[idx_expr] @@ -859,22 +874,18 @@ impl Engine<'_> { #[cfg(not(feature = "no_index"))] Expr::Index(lhs, idx_expr, op_pos) => match lhs.as_ref() { // xxx.id[idx_expr] - Expr::Property(id, pos) => { - let get_fn_name = make_getter(id); + Expr::Property(id, pos) => self + .call_fn_raw(&make_getter(id), &mut [this_ptr], None, *pos, 0) + .and_then(|v| { + let (_, _, idx) = + self.get_indexed_value(scope, &v, idx_expr, *op_pos, level)?; - self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0) - .and_then(|v| { - let (_, _, idx) = - self.get_indexed_value(scope, &v, idx_expr, *op_pos, level)?; - - Self::update_indexed_value(v, idx, new_val.0.clone(), new_val.1) - }) - .and_then(|mut v| { - let set_fn_name = make_setter(id); - let mut args = [this_ptr, v.as_mut()]; - self.call_fn_raw(&set_fn_name, &mut args, None, *pos, 0) - }) - } + Self::update_indexed_value(v, idx, new_val.0.clone(), new_val.1) + }) + .and_then(|mut v| { + let mut args = [this_ptr, v.as_mut()]; + self.call_fn_raw(&make_setter(id), &mut args, None, *pos, 0) + }), // All others - syntax error for setters chain _ => Err(EvalAltResult::ErrorDotExpr( @@ -887,17 +898,14 @@ impl Engine<'_> { Expr::Dot(lhs, rhs, _) => match lhs.as_ref() { // xxx.id.rhs Expr::Property(id, pos) => { - let get_fn_name = make_getter(id); - - self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0) + self.call_fn_raw(&make_getter(id), &mut [this_ptr], None, *pos, 0) .and_then(|mut v| { self.set_dot_val_helper(scope, v.as_mut(), rhs, new_val, level) .map(|_| v) // Discard Ok return value }) .and_then(|mut v| { - let set_fn_name = make_setter(id); let mut args = [this_ptr, v.as_mut()]; - self.call_fn_raw(&set_fn_name, &mut args, None, *pos, 0) + self.call_fn_raw(&make_setter(id), &mut args, None, *pos, 0) }) } @@ -907,24 +915,26 @@ impl Engine<'_> { Expr::Index(lhs, idx_expr, op_pos) => match lhs.as_ref() { // xxx.id[idx_expr].rhs Expr::Property(id, pos) => { - let get_fn_name = make_getter(id); - - self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0) + self.call_fn_raw(&make_getter(id), &mut [this_ptr], None, *pos, 0) .and_then(|v| { - let (mut target, _, idx) = + let (mut value, _, idx) = self.get_indexed_value(scope, &v, idx_expr, *op_pos, level)?; let val_pos = new_val.1; - let this_ptr = target.as_mut(); + let this_ptr = value.as_mut(); self.set_dot_val_helper(scope, this_ptr, rhs, new_val, level)?; // In case the expression mutated `target`, we need to update it back into the scope because it is cloned. - Self::update_indexed_value(v, idx, target, val_pos) + Self::update_indexed_value(v, idx, value, val_pos) }) .and_then(|mut v| { - let set_fn_name = make_setter(id); - let mut args = [this_ptr, v.as_mut()]; - self.call_fn_raw(&set_fn_name, &mut args, None, *pos, 0) + self.call_fn_raw( + &make_setter(id), + &mut [this_ptr, v.as_mut()], + None, + *pos, + 0, + ) }) } @@ -1168,7 +1178,7 @@ impl Engine<'_> { fn has_override(engine: &Engine, name: &str) -> bool { let spec = FnSpec { name: name.into(), - args: Some(vec![TypeId::of::()]), + args: vec![TypeId::of::()], }; engine.functions.contains_key(&spec) || engine.fn_lib.has_function(name, 1) diff --git a/src/fn_register.rs b/src/fn_register.rs index df2d01d0..5e7efd13 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -165,7 +165,7 @@ macro_rules! def_register { let r = f($(($clone)($par)),*); Ok(Box::new(r) as Dynamic) }; - self.register_fn_raw(name, Some(vec![$(TypeId::of::<$par>()),*]), Box::new(fun)); + self.register_fn_raw(name, vec![$(TypeId::of::<$par>()),*], Box::new(fun)); } } @@ -196,7 +196,7 @@ macro_rules! def_register { // potentially clone the value, otherwise pass the reference. Ok(f($(($clone)($par)),*)) }; - self.register_fn_raw(name, Some(vec![$(TypeId::of::<$par>()),*]), Box::new(fun)); + self.register_fn_raw(name, vec![$(TypeId::of::<$par>()),*], Box::new(fun)); } } @@ -229,7 +229,7 @@ macro_rules! def_register { f($(($clone)($par)),*).map(|r| Box::new(r) as Dynamic) .map_err(|err| err.set_position(pos)) }; - self.register_fn_raw(name, Some(vec![$(TypeId::of::<$par>()),*]), Box::new(fun)); + self.register_fn_raw(name, vec![$(TypeId::of::<$par>()),*], Box::new(fun)); } } diff --git a/src/result.rs b/src/result.rs index b0e1ecbd..0c882609 100644 --- a/src/result.rs +++ b/src/result.rs @@ -20,6 +20,11 @@ use crate::stdlib::path::PathBuf; pub enum EvalAltResult { /// Syntax error. ErrorParsing(ParseError), + + /// Error reading from a script file. Wrapped value is the path of the script file. + #[cfg(not(feature = "no_std"))] + ErrorReadingScriptFile(PathBuf, std::io::Error), + /// Call to an unknown function. Wrapped value is the name of the function. ErrorFunctionNotFound(String, Position), /// Function call has incorrect number of arguments. @@ -55,9 +60,6 @@ pub enum EvalAltResult { /// Returned type is not the same as the required output type. /// Wrapped value is the type of the actual result. ErrorMismatchOutputType(String, Position), - /// Error reading from a script file. Wrapped value is the path of the script file. - #[cfg(not(feature = "no_std"))] - ErrorReadingScriptFile(PathBuf, std::io::Error), /// Inappropriate member access. ErrorDotExpr(String, Position), /// Arithmetic error encountered. Wrapped value is the error message. @@ -66,6 +68,7 @@ pub enum EvalAltResult { ErrorStackOverflow(Position), /// Run-time error encountered. Wrapped value is the error message. ErrorRuntime(String, Position), + /// Breaking out of loops - not an error if within a loop. ErrorLoopBreak(Position), /// Not an error: Value returned from a script via the `return` keyword. @@ -76,6 +79,9 @@ pub enum EvalAltResult { impl EvalAltResult { pub(crate) fn desc(&self) -> &str { match self { + #[cfg(not(feature = "no_std"))] + Self::ErrorReadingScriptFile(_, _) => "Cannot read from script file", + Self::ErrorParsing(p) => p.desc(), Self::ErrorFunctionNotFound(_, _) => "Function not found", Self::ErrorFunctionArgsMismatch(_, _, _, _) => { @@ -108,8 +114,6 @@ impl EvalAltResult { } Self::ErrorAssignmentToConstant(_, _) => "Assignment to a constant variable", Self::ErrorMismatchOutputType(_, _) => "Output type is incorrect", - #[cfg(not(feature = "no_std"))] - Self::ErrorReadingScriptFile(_, _) => "Cannot read from script file", Self::ErrorDotExpr(_, _) => "Malformed dot expression", Self::ErrorArithmetic(_, _) => "Arithmetic error", Self::ErrorStackOverflow(_) => "Stack overflow", @@ -127,6 +131,13 @@ impl fmt::Display for EvalAltResult { let desc = self.desc(); match self { + #[cfg(not(feature = "no_std"))] + Self::ErrorReadingScriptFile(path, err) => { + write!(f, "{} '{}': {}", desc, path.display(), err) + } + + Self::ErrorParsing(p) => write!(f, "Syntax error: {}", p), + Self::ErrorFunctionNotFound(s, pos) | Self::ErrorVariableNotFound(s, pos) => { write!(f, "{}: '{}' ({})", desc, s, pos) } @@ -141,33 +152,31 @@ impl fmt::Display for EvalAltResult { | Self::ErrorDotExpr(_, pos) | Self::ErrorStackOverflow(pos) => write!(f, "{} ({})", desc, pos), - Self::ErrorAssignmentToConstant(s, pos) => write!(f, "{}: '{}' ({})", desc, s, pos), - Self::ErrorMismatchOutputType(s, pos) => write!(f, "{}: {} ({})", desc, s, pos), Self::ErrorRuntime(s, pos) => { write!(f, "{} ({})", if s.is_empty() { desc } else { s }, pos) } + + Self::ErrorAssignmentToConstant(s, pos) => write!(f, "{}: '{}' ({})", desc, s, pos), + Self::ErrorMismatchOutputType(s, pos) => write!(f, "{}: {} ({})", desc, s, pos), Self::ErrorArithmetic(s, pos) => write!(f, "{} ({})", s, pos), + Self::ErrorLoopBreak(pos) => write!(f, "{} ({})", desc, pos), Self::Return(_, pos) => write!(f, "{} ({})", desc, pos), - #[cfg(not(feature = "no_std"))] - Self::ErrorReadingScriptFile(path, err) => { - write!(f, "{} '{}': {}", desc, path.display(), err) - } - Self::ErrorParsing(p) => write!(f, "Syntax error: {}", p), - Self::ErrorFunctionArgsMismatch(fun, 0, n, pos) => write!( + + Self::ErrorFunctionArgsMismatch(fn_name, 0, n, pos) => write!( f, "Function '{}' expects no argument but {} found ({})", - fun, n, pos + fn_name, n, pos ), - Self::ErrorFunctionArgsMismatch(fun, 1, n, pos) => write!( + Self::ErrorFunctionArgsMismatch(fn_name, 1, n, pos) => write!( f, "Function '{}' expects one argument but {} found ({})", - fun, n, pos + fn_name, n, pos ), - Self::ErrorFunctionArgsMismatch(fun, need, n, pos) => write!( + Self::ErrorFunctionArgsMismatch(fn_name, need, n, pos) => write!( f, "Function '{}' expects {} argument(s) but {} found ({})", - fun, need, n, pos + fn_name, need, n, pos ), Self::ErrorBooleanArgMismatch(op, pos) => { write!(f, "{} operator expects boolean operands ({})", op, pos)