Better error messages.
This commit is contained in:
parent
9664ae42a7
commit
23d0f52284
@ -11,6 +11,7 @@ Breaking changes
|
|||||||
* `Module::iter_script_fn_info` is removed and merged into `Module::iter_script_fn`.
|
* `Module::iter_script_fn_info` is removed and merged into `Module::iter_script_fn`.
|
||||||
* The `merge_namespaces` parameter to `Module::eval_ast_as_new` is removed and now defaults to `true`.
|
* The `merge_namespaces` parameter to `Module::eval_ast_as_new` is removed and now defaults to `true`.
|
||||||
* `GlobalFileModuleResolver` is removed because its performance gain over the `FileModuleResolver` is no longer very significant.
|
* `GlobalFileModuleResolver` is removed because its performance gain over the `FileModuleResolver` is no longer very significant.
|
||||||
|
* `EvalAltResult::ErrorCharMismatch` is renamed to `EvalAltResult::ErrorMismatchDataType`.
|
||||||
|
|
||||||
New features
|
New features
|
||||||
------------
|
------------
|
||||||
|
195
src/engine.rs
195
src/engine.rs
@ -229,24 +229,32 @@ impl Target<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Update the value of the `Target`.
|
/// Update the value of the `Target`.
|
||||||
/// Position in `EvalAltResult` is `None` and must be set afterwards.
|
pub fn set_value(
|
||||||
pub fn set_value(&mut self, new_val: Dynamic) -> Result<(), Box<EvalAltResult>> {
|
&mut self,
|
||||||
|
new_val: Dynamic,
|
||||||
|
target_pos: Position,
|
||||||
|
new_pos: Position,
|
||||||
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
match self {
|
match self {
|
||||||
Self::Ref(r) => **r = new_val,
|
Self::Ref(r) => **r = new_val,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Self::LockGuard((r, _)) => **r = new_val,
|
Self::LockGuard((r, _)) => **r = new_val,
|
||||||
Self::Value(_) => {
|
Self::Value(_) => {
|
||||||
return EvalAltResult::ErrorAssignmentToUnknownLHS(Position::none()).into();
|
return EvalAltResult::ErrorAssignmentToUnknownLHS(target_pos).into();
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Self::StringChar(string, index, _) if string.is::<ImmutableString>() => {
|
Self::StringChar(string, index, _) if string.is::<ImmutableString>() => {
|
||||||
let mut s = string.write_lock::<ImmutableString>().unwrap();
|
let mut s = string.write_lock::<ImmutableString>().unwrap();
|
||||||
|
|
||||||
// Replace the character at the specified index position
|
// Replace the character at the specified index position
|
||||||
let new_ch = new_val
|
let new_ch = new_val.as_char().map_err(|err| {
|
||||||
.as_char()
|
Box::new(EvalAltResult::ErrorMismatchDataType(
|
||||||
.map_err(|_| EvalAltResult::ErrorCharMismatch(Position::none()))?;
|
err.to_string(),
|
||||||
|
"char".to_string(),
|
||||||
|
new_pos,
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
let mut chars = s.chars().collect::<StaticVec<_>>();
|
let mut chars = s.chars().collect::<StaticVec<_>>();
|
||||||
let ch = chars[*index];
|
let ch = chars[*index];
|
||||||
@ -413,56 +421,7 @@ impl fmt::Debug for Engine {
|
|||||||
|
|
||||||
impl Default for Engine {
|
impl Default for Engine {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
// Create the new scripting Engine
|
Self::new()
|
||||||
let mut engine = Self {
|
|
||||||
id: None,
|
|
||||||
|
|
||||||
packages: Default::default(),
|
|
||||||
global_module: Default::default(),
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
module_resolver: Some(Box::new(resolvers::FileModuleResolver::new())),
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
#[cfg(any(feature = "no_std", target_arch = "wasm32",))]
|
|
||||||
module_resolver: None,
|
|
||||||
|
|
||||||
type_names: None,
|
|
||||||
disabled_symbols: None,
|
|
||||||
custom_keywords: None,
|
|
||||||
custom_syntax: None,
|
|
||||||
|
|
||||||
// default print/debug implementations
|
|
||||||
print: Box::new(default_print),
|
|
||||||
debug: Box::new(default_print),
|
|
||||||
|
|
||||||
// progress callback
|
|
||||||
progress: None,
|
|
||||||
|
|
||||||
// optimization level
|
|
||||||
optimization_level: if cfg!(feature = "no_optimize") {
|
|
||||||
OptimizationLevel::None
|
|
||||||
} else {
|
|
||||||
OptimizationLevel::Simple
|
|
||||||
},
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
limits: Limits {
|
|
||||||
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
|
||||||
max_expr_depth: MAX_EXPR_DEPTH,
|
|
||||||
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
|
||||||
max_operations: 0,
|
|
||||||
max_modules: usize::MAX,
|
|
||||||
max_string_size: 0,
|
|
||||||
max_array_size: 0,
|
|
||||||
max_map_size: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
engine.load_package(StandardPackage::new().get());
|
|
||||||
|
|
||||||
engine
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,7 +587,56 @@ pub fn search_scope_only<'s, 'a>(
|
|||||||
impl Engine {
|
impl Engine {
|
||||||
/// Create a new `Engine`
|
/// Create a new `Engine`
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
// Create the new scripting Engine
|
||||||
|
let mut engine = Self {
|
||||||
|
id: None,
|
||||||
|
|
||||||
|
packages: Default::default(),
|
||||||
|
global_module: Default::default(),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
#[cfg(not(feature = "no_std"))]
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
module_resolver: Some(Box::new(resolvers::FileModuleResolver::new())),
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
#[cfg(any(feature = "no_std", target_arch = "wasm32",))]
|
||||||
|
module_resolver: None,
|
||||||
|
|
||||||
|
type_names: None,
|
||||||
|
disabled_symbols: None,
|
||||||
|
custom_keywords: None,
|
||||||
|
custom_syntax: None,
|
||||||
|
|
||||||
|
// default print/debug implementations
|
||||||
|
print: Box::new(default_print),
|
||||||
|
debug: Box::new(default_print),
|
||||||
|
|
||||||
|
// progress callback
|
||||||
|
progress: None,
|
||||||
|
|
||||||
|
// optimization level
|
||||||
|
optimization_level: if cfg!(feature = "no_optimize") {
|
||||||
|
OptimizationLevel::None
|
||||||
|
} else {
|
||||||
|
OptimizationLevel::Simple
|
||||||
|
},
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
limits: Limits {
|
||||||
|
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
||||||
|
max_expr_depth: MAX_EXPR_DEPTH,
|
||||||
|
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
||||||
|
max_operations: 0,
|
||||||
|
max_modules: usize::MAX,
|
||||||
|
max_string_size: 0,
|
||||||
|
max_array_size: 0,
|
||||||
|
max_map_size: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
engine.load_package(StandardPackage::new().get());
|
||||||
|
|
||||||
|
engine
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `Engine` with minimal built-in functions.
|
/// Create a new `Engine` with minimal built-in functions.
|
||||||
@ -686,6 +694,7 @@ impl Engine {
|
|||||||
chain_type: ChainType,
|
chain_type: ChainType,
|
||||||
level: usize,
|
level: usize,
|
||||||
new_val: Option<Dynamic>,
|
new_val: Option<Dynamic>,
|
||||||
|
new_pos: Position,
|
||||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||||
if chain_type == ChainType::None {
|
if chain_type == ChainType::None {
|
||||||
panic!();
|
panic!();
|
||||||
@ -718,7 +727,7 @@ impl Engine {
|
|||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, this_ptr, obj_ptr, expr, idx_values, next_chain, level,
|
state, lib, this_ptr, obj_ptr, expr, idx_values, next_chain, level,
|
||||||
new_val,
|
new_val, new_pos,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.new_position(*pos))
|
.map_err(|err| err.new_position(*pos))
|
||||||
}
|
}
|
||||||
@ -732,10 +741,7 @@ impl Engine {
|
|||||||
{
|
{
|
||||||
// Indexed value is a reference - update directly
|
// Indexed value is a reference - update directly
|
||||||
Ok(ref mut obj_ptr) => {
|
Ok(ref mut obj_ptr) => {
|
||||||
obj_ptr
|
obj_ptr.set_value(new_val.unwrap(), rhs.position(), new_pos)?;
|
||||||
.set_value(new_val.unwrap())
|
|
||||||
.map_err(|err| err.new_position(rhs.position()))?;
|
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Err(err) => match *err {
|
Err(err) => match *err {
|
||||||
@ -799,8 +805,7 @@ impl Engine {
|
|||||||
let mut val = self
|
let mut val = self
|
||||||
.get_indexed_mut(state, lib, target, index, *pos, true, false, level)?;
|
.get_indexed_mut(state, lib, target, index, *pos, true, false, level)?;
|
||||||
|
|
||||||
val.set_value(new_val.unwrap())
|
val.set_value(new_val.unwrap(), rhs.position(), new_pos)?;
|
||||||
.map_err(|err| err.new_position(rhs.position()))?;
|
|
||||||
Ok((Default::default(), true))
|
Ok((Default::default(), true))
|
||||||
}
|
}
|
||||||
// {xxx:map}.id
|
// {xxx:map}.id
|
||||||
@ -868,7 +873,7 @@ impl Engine {
|
|||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, this_ptr, &mut val, expr, idx_values, next_chain, level,
|
state, lib, this_ptr, &mut val, expr, idx_values, next_chain, level,
|
||||||
new_val,
|
new_val, new_pos,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.new_position(*pos))
|
.map_err(|err| err.new_position(*pos))
|
||||||
}
|
}
|
||||||
@ -902,6 +907,7 @@ impl Engine {
|
|||||||
next_chain,
|
next_chain,
|
||||||
level,
|
level,
|
||||||
new_val,
|
new_val,
|
||||||
|
new_pos,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.new_position(*pos))?;
|
.map_err(|err| err.new_position(*pos))?;
|
||||||
|
|
||||||
@ -941,7 +947,7 @@ impl Engine {
|
|||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, this_ptr, target, expr, idx_values, next_chain,
|
state, lib, this_ptr, target, expr, idx_values, next_chain,
|
||||||
level, new_val,
|
level, new_val, new_pos,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.new_position(*pos))
|
.map_err(|err| err.new_position(*pos))
|
||||||
}
|
}
|
||||||
@ -972,6 +978,7 @@ impl Engine {
|
|||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
level: usize,
|
level: usize,
|
||||||
new_val: Option<Dynamic>,
|
new_val: Option<Dynamic>,
|
||||||
|
new_pos: Position,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
let ((dot_lhs, dot_rhs, op_pos), chain_type) = match expr {
|
let ((dot_lhs, dot_rhs, op_pos), chain_type) = match expr {
|
||||||
Expr::Index(x) => (x.as_ref(), ChainType::Index),
|
Expr::Index(x) => (x.as_ref(), ChainType::Index),
|
||||||
@ -1007,7 +1014,8 @@ impl Engine {
|
|||||||
|
|
||||||
let obj_ptr = &mut target.into();
|
let obj_ptr = &mut target.into();
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, &mut None, obj_ptr, dot_rhs, idx_values, chain_type, level, new_val,
|
state, lib, &mut None, obj_ptr, dot_rhs, idx_values, chain_type, level,
|
||||||
|
new_val, new_pos,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| v)
|
.map(|(v, _)| v)
|
||||||
.map_err(|err| err.new_position(*op_pos))
|
.map_err(|err| err.new_position(*op_pos))
|
||||||
@ -1022,6 +1030,7 @@ impl Engine {
|
|||||||
let obj_ptr = &mut val.into();
|
let obj_ptr = &mut val.into();
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, this_ptr, obj_ptr, dot_rhs, idx_values, chain_type, level, new_val,
|
state, lib, this_ptr, obj_ptr, dot_rhs, idx_values, chain_type, level, new_val,
|
||||||
|
new_pos,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| v)
|
.map(|(v, _)| v)
|
||||||
.map_err(|err| err.new_position(*op_pos))
|
.map_err(|err| err.new_position(*op_pos))
|
||||||
@ -1409,9 +1418,9 @@ impl Engine {
|
|||||||
let mut rhs_val =
|
let mut rhs_val =
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)?;
|
self.eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)?;
|
||||||
|
|
||||||
let _new_val = Some(if op.is_empty() {
|
let (_new_val, _new_pos) = if op.is_empty() {
|
||||||
// Normal assignment
|
// Normal assignment
|
||||||
rhs_val
|
(Some(rhs_val), rhs_expr.position())
|
||||||
} else {
|
} else {
|
||||||
// Op-assignment - always map to `lhs = lhs op rhs`
|
// Op-assignment - always map to `lhs = lhs op rhs`
|
||||||
let op = &op[..op.len() - 1]; // extract operator without =
|
let op = &op[..op.len() - 1]; // extract operator without =
|
||||||
@ -1419,12 +1428,16 @@ impl Engine {
|
|||||||
&mut self.eval_expr(scope, mods, state, lib, this_ptr, lhs_expr, level)?,
|
&mut self.eval_expr(scope, mods, state, lib, this_ptr, lhs_expr, level)?,
|
||||||
&mut rhs_val,
|
&mut rhs_val,
|
||||||
];
|
];
|
||||||
self.exec_fn_call(
|
|
||||||
state, lib, op, 0, args, false, false, false, None, &None, level,
|
let result = self
|
||||||
)
|
.exec_fn_call(
|
||||||
.map(|(v, _)| v)
|
state, lib, op, 0, args, false, false, false, None, &None, level,
|
||||||
.map_err(|err| err.new_position(*op_pos))?
|
)
|
||||||
});
|
.map(|(v, _)| v)
|
||||||
|
.map_err(|err| err.new_position(*op_pos))?;
|
||||||
|
|
||||||
|
(Some(result), rhs_expr.position())
|
||||||
|
};
|
||||||
|
|
||||||
match lhs_expr {
|
match lhs_expr {
|
||||||
// name op= rhs
|
// name op= rhs
|
||||||
@ -1433,7 +1446,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(_) => {
|
Expr::Index(_) => {
|
||||||
self.eval_dot_index_chain(
|
self.eval_dot_index_chain(
|
||||||
scope, mods, state, lib, this_ptr, lhs_expr, level, _new_val,
|
scope, mods, state, lib, this_ptr, lhs_expr, level, _new_val, _new_pos,
|
||||||
)?;
|
)?;
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
}
|
}
|
||||||
@ -1441,7 +1454,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Dot(_) => {
|
Expr::Dot(_) => {
|
||||||
self.eval_dot_index_chain(
|
self.eval_dot_index_chain(
|
||||||
scope, mods, state, lib, this_ptr, lhs_expr, level, _new_val,
|
scope, mods, state, lib, this_ptr, lhs_expr, level, _new_val, _new_pos,
|
||||||
)?;
|
)?;
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
}
|
}
|
||||||
@ -1458,15 +1471,31 @@ impl Engine {
|
|||||||
|
|
||||||
// lhs[idx_expr]
|
// lhs[idx_expr]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(_) => {
|
Expr::Index(_) => self.eval_dot_index_chain(
|
||||||
self.eval_dot_index_chain(scope, mods, state, lib, this_ptr, expr, level, None)
|
scope,
|
||||||
}
|
mods,
|
||||||
|
state,
|
||||||
|
lib,
|
||||||
|
this_ptr,
|
||||||
|
expr,
|
||||||
|
level,
|
||||||
|
None,
|
||||||
|
Position::none(),
|
||||||
|
),
|
||||||
|
|
||||||
// lhs.dot_rhs
|
// lhs.dot_rhs
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Dot(_) => {
|
Expr::Dot(_) => self.eval_dot_index_chain(
|
||||||
self.eval_dot_index_chain(scope, mods, state, lib, this_ptr, expr, level, None)
|
scope,
|
||||||
}
|
mods,
|
||||||
|
state,
|
||||||
|
lib,
|
||||||
|
this_ptr,
|
||||||
|
expr,
|
||||||
|
level,
|
||||||
|
None,
|
||||||
|
Position::none(),
|
||||||
|
),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Array(x) => Ok(Dynamic(Union::Array(Box::new(
|
Expr::Array(x) => Ok(Dynamic(Union::Array(Box::new(
|
||||||
|
104
src/fn_call.rs
104
src/fn_call.rs
@ -614,7 +614,7 @@ impl Engine {
|
|||||||
mods: &mut Imports,
|
mods: &mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &Module,
|
||||||
script_expr: &Dynamic,
|
script: &str,
|
||||||
_level: usize,
|
_level: usize,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
self.inc_operations(state)?;
|
self.inc_operations(state)?;
|
||||||
@ -628,14 +628,6 @@ impl Engine {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let script = script_expr.as_str().map_err(|typ| {
|
|
||||||
EvalAltResult::ErrorMismatchOutputType(
|
|
||||||
self.map_type_name(type_name::<ImmutableString>()).into(),
|
|
||||||
typ.into(),
|
|
||||||
Position::none(),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Compile the script text
|
// Compile the script text
|
||||||
// No optimizations because we only run it once
|
// No optimizations because we only run it once
|
||||||
let mut ast = self.compile_with_scope_and_optimization_level(
|
let mut ast = self.compile_with_scope_and_optimization_level(
|
||||||
@ -804,7 +796,7 @@ impl Engine {
|
|||||||
// Feed the changed temp value back
|
// Feed the changed temp value back
|
||||||
if updated && !is_ref && !is_value {
|
if updated && !is_ref && !is_value {
|
||||||
let new_val = target.as_mut().clone();
|
let new_val = target.as_mut().clone();
|
||||||
target.set_value(new_val)?;
|
target.set_value(new_val, Position::none(), Position::none())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((result, updated))
|
Ok((result, updated))
|
||||||
@ -828,6 +820,15 @@ impl Engine {
|
|||||||
capture: bool,
|
capture: bool,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
|
fn make_type_err<T>(engine: &Engine, typ: &str, pos: Position) -> Box<EvalAltResult> {
|
||||||
|
EvalAltResult::ErrorMismatchDataType(
|
||||||
|
typ.into(),
|
||||||
|
engine.map_type_name(type_name::<T>()).into(),
|
||||||
|
pos,
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
// Handle Fn()
|
// Handle Fn()
|
||||||
if name == KEYWORD_FN_PTR && args_expr.len() == 1 {
|
if name == KEYWORD_FN_PTR && args_expr.len() == 1 {
|
||||||
let hash_fn = calc_fn_hash(empty(), name, 1, once(TypeId::of::<ImmutableString>()));
|
let hash_fn = calc_fn_hash(empty(), name, 1, once(TypeId::of::<ImmutableString>()));
|
||||||
@ -839,14 +840,7 @@ impl Engine {
|
|||||||
|
|
||||||
return arg_value
|
return arg_value
|
||||||
.take_immutable_string()
|
.take_immutable_string()
|
||||||
.map_err(|typ| {
|
.map_err(|typ| make_type_err::<ImmutableString>(self, typ, expr.position()))
|
||||||
EvalAltResult::ErrorMismatchOutputType(
|
|
||||||
self.map_type_name(type_name::<ImmutableString>()).into(),
|
|
||||||
typ.into(),
|
|
||||||
expr.position(),
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
})
|
|
||||||
.and_then(|s| FnPtr::try_from(s))
|
.and_then(|s| FnPtr::try_from(s))
|
||||||
.map(Into::<Dynamic>::into)
|
.map(Into::<Dynamic>::into)
|
||||||
.map_err(|err| err.new_position(expr.position()));
|
.map_err(|err| err.new_position(expr.position()));
|
||||||
@ -856,18 +850,17 @@ impl Engine {
|
|||||||
// Handle curry()
|
// Handle curry()
|
||||||
if name == KEYWORD_FN_PTR_CURRY && args_expr.len() > 1 {
|
if name == KEYWORD_FN_PTR_CURRY && args_expr.len() > 1 {
|
||||||
let expr = args_expr.get(0).unwrap();
|
let expr = args_expr.get(0).unwrap();
|
||||||
let fn_ptr = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
let arg_value = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||||
|
|
||||||
if !fn_ptr.is::<FnPtr>() {
|
if !arg_value.is::<FnPtr>() {
|
||||||
return EvalAltResult::ErrorMismatchOutputType(
|
return Err(make_type_err::<FnPtr>(
|
||||||
self.map_type_name(type_name::<FnPtr>()).into(),
|
self,
|
||||||
self.map_type_name(fn_ptr.type_name()).into(),
|
self.map_type_name(arg_value.type_name()),
|
||||||
expr.position(),
|
expr.position(),
|
||||||
)
|
));
|
||||||
.into();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (fn_name, fn_curry) = fn_ptr.cast::<FnPtr>().take_data();
|
let (fn_name, fn_curry) = arg_value.cast::<FnPtr>().take_data();
|
||||||
|
|
||||||
let curry: StaticVec<_> = args_expr
|
let curry: StaticVec<_> = args_expr
|
||||||
.iter()
|
.iter()
|
||||||
@ -902,10 +895,10 @@ impl Engine {
|
|||||||
&& !self.has_override(lib, 0, hash_script, pub_only)
|
&& !self.has_override(lib, 0, hash_script, pub_only)
|
||||||
{
|
{
|
||||||
let expr = args_expr.get(0).unwrap();
|
let expr = args_expr.get(0).unwrap();
|
||||||
let fn_name = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
let arg_value = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||||
|
|
||||||
if fn_name.is::<FnPtr>() {
|
if arg_value.is::<FnPtr>() {
|
||||||
let fn_ptr = fn_name.cast::<FnPtr>();
|
let fn_ptr = arg_value.cast::<FnPtr>();
|
||||||
curry = fn_ptr.curry().iter().cloned().collect();
|
curry = fn_ptr.curry().iter().cloned().collect();
|
||||||
// Redirect function name
|
// Redirect function name
|
||||||
redirected = fn_ptr.take_data().0;
|
redirected = fn_ptr.take_data().0;
|
||||||
@ -915,12 +908,11 @@ impl Engine {
|
|||||||
// Recalculate hash
|
// Recalculate hash
|
||||||
hash_script = calc_fn_hash(empty(), name, curry.len() + args_expr.len(), empty());
|
hash_script = calc_fn_hash(empty(), name, curry.len() + args_expr.len(), empty());
|
||||||
} else {
|
} else {
|
||||||
return EvalAltResult::ErrorMismatchOutputType(
|
return Err(make_type_err::<FnPtr>(
|
||||||
self.map_type_name(type_name::<FnPtr>()).into(),
|
self,
|
||||||
fn_name.type_name().into(),
|
self.map_type_name(arg_value.type_name()),
|
||||||
expr.position(),
|
expr.position(),
|
||||||
)
|
));
|
||||||
.into();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -930,10 +922,13 @@ impl Engine {
|
|||||||
|
|
||||||
if !self.has_override(lib, hash_fn, hash_script, pub_only) {
|
if !self.has_override(lib, hash_fn, hash_script, pub_only) {
|
||||||
let expr = args_expr.get(0).unwrap();
|
let expr = args_expr.get(0).unwrap();
|
||||||
if let Ok(var_name) = self
|
let arg_value = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
let var_name = arg_value
|
||||||
.as_str()
|
.as_str()
|
||||||
{
|
.map_err(|err| make_type_err::<ImmutableString>(self, err, expr.position()))?;
|
||||||
|
if var_name.is_empty() {
|
||||||
|
return Ok(false.into());
|
||||||
|
} else {
|
||||||
return Ok(scope.contains(var_name).into());
|
return Ok(scope.contains(var_name).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -954,12 +949,21 @@ impl Engine {
|
|||||||
let fn_name_expr = args_expr.get(0).unwrap();
|
let fn_name_expr = args_expr.get(0).unwrap();
|
||||||
let num_params_expr = args_expr.get(1).unwrap();
|
let num_params_expr = args_expr.get(1).unwrap();
|
||||||
|
|
||||||
if let (Ok(fn_name), Ok(num_params)) = (
|
let arg0_value =
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, fn_name_expr, level)?
|
self.eval_expr(scope, mods, state, lib, this_ptr, fn_name_expr, level)?;
|
||||||
.as_str(),
|
let arg1_value =
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, num_params_expr, level)?
|
self.eval_expr(scope, mods, state, lib, this_ptr, num_params_expr, level)?;
|
||||||
.as_int(),
|
|
||||||
) {
|
let fn_name = arg0_value.as_str().map_err(|err| {
|
||||||
|
make_type_err::<ImmutableString>(self, err, fn_name_expr.position())
|
||||||
|
})?;
|
||||||
|
let num_params = arg1_value
|
||||||
|
.as_int()
|
||||||
|
.map_err(|err| make_type_err::<INT>(self, err, num_params_expr.position()))?;
|
||||||
|
|
||||||
|
if fn_name.is_empty() || num_params < 0 {
|
||||||
|
return Ok(false.into());
|
||||||
|
} else {
|
||||||
let hash = calc_fn_hash(empty(), fn_name, num_params as usize, empty());
|
let hash = calc_fn_hash(empty(), fn_name, num_params as usize, empty());
|
||||||
return Ok(lib.contains_fn(hash, false).into());
|
return Ok(lib.contains_fn(hash, false).into());
|
||||||
}
|
}
|
||||||
@ -974,10 +978,16 @@ impl Engine {
|
|||||||
// eval - only in function call style
|
// eval - only in function call style
|
||||||
let prev_len = scope.len();
|
let prev_len = scope.len();
|
||||||
let expr = args_expr.get(0).unwrap();
|
let expr = args_expr.get(0).unwrap();
|
||||||
let script = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
let arg_value = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||||
let result = self
|
let script = arg_value
|
||||||
.eval_script_expr(scope, mods, state, lib, &script, level + 1)
|
.as_str()
|
||||||
.map_err(|err| err.new_position(expr.position()));
|
.map_err(|typ| make_type_err::<ImmutableString>(self, typ, expr.position()))?;
|
||||||
|
let result = if !script.is_empty() {
|
||||||
|
self.eval_script_expr(scope, mods, state, lib, script, level + 1)
|
||||||
|
.map_err(|err| err.new_position(expr.position()))
|
||||||
|
} else {
|
||||||
|
Ok(().into())
|
||||||
|
};
|
||||||
|
|
||||||
// IMPORTANT! If the eval defines new variables in the current scope,
|
// IMPORTANT! If the eval defines new variables in the current scope,
|
||||||
// all variable offsets from this point on will be mis-aligned.
|
// all variable offsets from this point on will be mis-aligned.
|
||||||
|
@ -46,8 +46,9 @@ pub enum EvalAltResult {
|
|||||||
ErrorUnboundThis(Position),
|
ErrorUnboundThis(Position),
|
||||||
/// Non-boolean operand encountered for boolean operator. Wrapped value is the operator.
|
/// Non-boolean operand encountered for boolean operator. Wrapped value is the operator.
|
||||||
ErrorBooleanArgMismatch(String, Position),
|
ErrorBooleanArgMismatch(String, Position),
|
||||||
/// Non-character value encountered where a character is required.
|
/// Data is not of the required type.
|
||||||
ErrorCharMismatch(Position),
|
/// Wrapped values are the type requested and type of the actual result.
|
||||||
|
ErrorMismatchDataType(String, String, Position),
|
||||||
/// Array access out-of-bounds.
|
/// Array access out-of-bounds.
|
||||||
/// Wrapped values are the current number of elements in the array and the index number.
|
/// Wrapped values are the current number of elements in the array and the index number.
|
||||||
ErrorArrayBounds(usize, INT, Position),
|
ErrorArrayBounds(usize, INT, Position),
|
||||||
@ -120,7 +121,7 @@ impl EvalAltResult {
|
|||||||
Self::ErrorFunctionNotFound(_, _) => "Function not found",
|
Self::ErrorFunctionNotFound(_, _) => "Function not found",
|
||||||
Self::ErrorUnboundThis(_) => "'this' is not bound",
|
Self::ErrorUnboundThis(_) => "'this' is not bound",
|
||||||
Self::ErrorBooleanArgMismatch(_, _) => "Boolean operator expects boolean operands",
|
Self::ErrorBooleanArgMismatch(_, _) => "Boolean operator expects boolean operands",
|
||||||
Self::ErrorCharMismatch(_) => "Character expected",
|
Self::ErrorMismatchDataType(_, _, _) => "Data type is incorrect",
|
||||||
Self::ErrorNumericIndexExpr(_) => {
|
Self::ErrorNumericIndexExpr(_) => {
|
||||||
"Indexing into an array or string expects an integer index"
|
"Indexing into an array or string expects an integer index"
|
||||||
}
|
}
|
||||||
@ -215,7 +216,10 @@ impl fmt::Display for EvalAltResult {
|
|||||||
|
|
||||||
Self::ErrorAssignmentToConstant(s, _) => write!(f, "{}: '{}'", desc, s)?,
|
Self::ErrorAssignmentToConstant(s, _) => write!(f, "{}: '{}'", desc, s)?,
|
||||||
Self::ErrorMismatchOutputType(r, s, _) => {
|
Self::ErrorMismatchOutputType(r, s, _) => {
|
||||||
write!(f, "{} (expecting {}): {}", desc, s, r)?
|
write!(f, "Output type is incorrect: {} (expecting {})", r, s)?
|
||||||
|
}
|
||||||
|
Self::ErrorMismatchDataType(r, s, _) => {
|
||||||
|
write!(f, "Data type is incorrect: {} (expecting {})", r, s)?
|
||||||
}
|
}
|
||||||
Self::ErrorArithmetic(s, _) => f.write_str(s)?,
|
Self::ErrorArithmetic(s, _) => f.write_str(s)?,
|
||||||
|
|
||||||
@ -225,7 +229,6 @@ impl fmt::Display for EvalAltResult {
|
|||||||
Self::ErrorBooleanArgMismatch(op, _) => {
|
Self::ErrorBooleanArgMismatch(op, _) => {
|
||||||
write!(f, "{} operator expects boolean operands", op)?
|
write!(f, "{} operator expects boolean operands", op)?
|
||||||
}
|
}
|
||||||
Self::ErrorCharMismatch(_) => write!(f, "string indexing expects a character value")?,
|
|
||||||
Self::ErrorArrayBounds(_, index, _) if *index < 0 => {
|
Self::ErrorArrayBounds(_, index, _) if *index < 0 => {
|
||||||
write!(f, "{}: {} < 0", desc, index)?
|
write!(f, "{}: {} < 0", desc, index)?
|
||||||
}
|
}
|
||||||
@ -291,7 +294,7 @@ impl EvalAltResult {
|
|||||||
| Self::ErrorInModule(_, _, pos)
|
| Self::ErrorInModule(_, _, pos)
|
||||||
| Self::ErrorUnboundThis(pos)
|
| Self::ErrorUnboundThis(pos)
|
||||||
| Self::ErrorBooleanArgMismatch(_, pos)
|
| Self::ErrorBooleanArgMismatch(_, pos)
|
||||||
| Self::ErrorCharMismatch(pos)
|
| Self::ErrorMismatchDataType(_, _, pos)
|
||||||
| Self::ErrorArrayBounds(_, _, pos)
|
| Self::ErrorArrayBounds(_, _, pos)
|
||||||
| Self::ErrorStringBounds(_, _, pos)
|
| Self::ErrorStringBounds(_, _, pos)
|
||||||
| Self::ErrorIndexingType(_, pos)
|
| Self::ErrorIndexingType(_, pos)
|
||||||
@ -333,7 +336,7 @@ impl EvalAltResult {
|
|||||||
| Self::ErrorInModule(_, _, pos)
|
| Self::ErrorInModule(_, _, pos)
|
||||||
| Self::ErrorUnboundThis(pos)
|
| Self::ErrorUnboundThis(pos)
|
||||||
| Self::ErrorBooleanArgMismatch(_, pos)
|
| Self::ErrorBooleanArgMismatch(_, pos)
|
||||||
| Self::ErrorCharMismatch(pos)
|
| Self::ErrorMismatchDataType(_, _, pos)
|
||||||
| Self::ErrorArrayBounds(_, _, pos)
|
| Self::ErrorArrayBounds(_, _, pos)
|
||||||
| Self::ErrorStringBounds(_, _, pos)
|
| Self::ErrorStringBounds(_, _, pos)
|
||||||
| Self::ErrorIndexingType(_, pos)
|
| Self::ErrorIndexingType(_, pos)
|
||||||
|
Loading…
Reference in New Issue
Block a user