Introduce IndexChainValue.
This commit is contained in:
parent
fb05e811b7
commit
1e21a7f7e7
122
src/engine.rs
122
src/engine.rs
@ -129,6 +129,54 @@ pub enum ChainType {
|
|||||||
Dot,
|
Dot,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum IndexChainValue {
|
||||||
|
None,
|
||||||
|
FnCallArgs(StaticVec<Dynamic>),
|
||||||
|
Value(Dynamic),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
|
impl IndexChainValue {
|
||||||
|
/// Return the `Dynamic` value.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if not `IndexChainValue::Value`.
|
||||||
|
pub fn as_value(self) -> Dynamic {
|
||||||
|
match self {
|
||||||
|
Self::None | Self::FnCallArgs(_) => panic!("expecting IndexChainValue::Value"),
|
||||||
|
Self::Value(value) => value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Return the `StaticVec<Dynamic>` value.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if not `IndexChainValue::FnCallArgs`.
|
||||||
|
pub fn as_fn_call_args(self) -> StaticVec<Dynamic> {
|
||||||
|
match self {
|
||||||
|
Self::None | Self::Value(_) => panic!("expecting IndexChainValue::FnCallArgs"),
|
||||||
|
Self::FnCallArgs(value) => value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
|
impl From<StaticVec<Dynamic>> for IndexChainValue {
|
||||||
|
fn from(value: StaticVec<Dynamic>) -> Self {
|
||||||
|
Self::FnCallArgs(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
|
impl From<Dynamic> for IndexChainValue {
|
||||||
|
fn from(value: Dynamic) -> Self {
|
||||||
|
Self::Value(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A type that encapsulates a mutation target for an expression with side effects.
|
/// A type that encapsulates a mutation target for an expression with side effects.
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -790,7 +838,7 @@ impl Engine {
|
|||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
target: &mut Target,
|
target: &mut Target,
|
||||||
rhs: &Expr,
|
rhs: &Expr,
|
||||||
idx_values: &mut StaticVec<Dynamic>,
|
mut idx_values: StaticVec<IndexChainValue>,
|
||||||
chain_type: ChainType,
|
chain_type: ChainType,
|
||||||
level: usize,
|
level: usize,
|
||||||
new_val: Option<(Dynamic, Position)>,
|
new_val: Option<(Dynamic, Position)>,
|
||||||
@ -820,6 +868,7 @@ impl Engine {
|
|||||||
Expr::Dot(x) | Expr::Index(x) => {
|
Expr::Dot(x) | Expr::Index(x) => {
|
||||||
let (idx, expr, pos) = x.as_ref();
|
let (idx, expr, pos) = x.as_ref();
|
||||||
let idx_pos = idx.position();
|
let idx_pos = idx.position();
|
||||||
|
let idx_val = idx_val.as_value();
|
||||||
let obj_ptr = &mut self.get_indexed_mut(
|
let obj_ptr = &mut self.get_indexed_mut(
|
||||||
state, lib, target, idx_val, idx_pos, false, true, level,
|
state, lib, target, idx_val, idx_pos, false, true, level,
|
||||||
)?;
|
)?;
|
||||||
@ -832,6 +881,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// xxx[rhs] = new_val
|
// xxx[rhs] = new_val
|
||||||
_ if new_val.is_some() => {
|
_ if new_val.is_some() => {
|
||||||
|
let idx_val = idx_val.as_value();
|
||||||
let mut idx_val2 = idx_val.clone();
|
let mut idx_val2 = idx_val.clone();
|
||||||
|
|
||||||
// `call_setter` is introduced to bypass double mutable borrowing of target
|
// `call_setter` is introduced to bypass double mutable borrowing of target
|
||||||
@ -876,9 +926,11 @@ impl Engine {
|
|||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
}
|
}
|
||||||
// xxx[rhs]
|
// xxx[rhs]
|
||||||
_ => self
|
_ => {
|
||||||
.get_indexed_mut(state, lib, target, idx_val, pos, false, true, level)
|
let idx_val = idx_val.as_value();
|
||||||
.map(|v| (v.take_or_clone(), false)),
|
self.get_indexed_mut(state, lib, target, idx_val, pos, false, true, level)
|
||||||
|
.map(|v| (v.take_or_clone(), false))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -889,9 +941,9 @@ impl Engine {
|
|||||||
Expr::FnCall(x) if x.1.is_none() => {
|
Expr::FnCall(x) if x.1.is_none() => {
|
||||||
let ((name, native, _, pos), _, hash, _, def_val) = x.as_ref();
|
let ((name, native, _, pos), _, hash, _, def_val) = x.as_ref();
|
||||||
let def_val = def_val.map(Into::<Dynamic>::into);
|
let def_val = def_val.map(Into::<Dynamic>::into);
|
||||||
|
let args = idx_val.as_fn_call_args();
|
||||||
self.make_method_call(
|
self.make_method_call(
|
||||||
state, lib, name, *hash, target, idx_val, &def_val, *native, false,
|
state, lib, name, *hash, target, args, &def_val, *native, false, level,
|
||||||
level,
|
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(*pos))
|
.map_err(|err| err.fill_position(*pos))
|
||||||
}
|
}
|
||||||
@ -956,10 +1008,11 @@ impl Engine {
|
|||||||
Expr::FnCall(x) if x.1.is_none() => {
|
Expr::FnCall(x) if x.1.is_none() => {
|
||||||
let ((name, native, _, pos), _, hash, _, def_val) = x.as_ref();
|
let ((name, native, _, pos), _, hash, _, def_val) = x.as_ref();
|
||||||
let def_val = def_val.map(Into::<Dynamic>::into);
|
let def_val = def_val.map(Into::<Dynamic>::into);
|
||||||
|
let args = idx_val.as_fn_call_args();
|
||||||
let (val, _) = self
|
let (val, _) = self
|
||||||
.make_method_call(
|
.make_method_call(
|
||||||
state, lib, name, *hash, target, idx_val, &def_val,
|
state, lib, name, *hash, target, args, &def_val, *native,
|
||||||
*native, false, level,
|
false, level,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(*pos))?;
|
.map_err(|err| err.fill_position(*pos))?;
|
||||||
val.into()
|
val.into()
|
||||||
@ -1034,10 +1087,11 @@ impl Engine {
|
|||||||
Expr::FnCall(x) if x.1.is_none() => {
|
Expr::FnCall(x) if x.1.is_none() => {
|
||||||
let ((name, native, _, pos), _, hash, _, def_val) = x.as_ref();
|
let ((name, native, _, pos), _, hash, _, def_val) = x.as_ref();
|
||||||
let def_val = def_val.map(Into::<Dynamic>::into);
|
let def_val = def_val.map(Into::<Dynamic>::into);
|
||||||
|
let args = idx_val.as_fn_call_args();
|
||||||
let (mut val, _) = self
|
let (mut val, _) = self
|
||||||
.make_method_call(
|
.make_method_call(
|
||||||
state, lib, name, *hash, target, idx_val, &def_val,
|
state, lib, name, *hash, target, args, &def_val, *native,
|
||||||
*native, false, level,
|
false, level,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(*pos))?;
|
.map_err(|err| err.fill_position(*pos))?;
|
||||||
let val = &mut val;
|
let val = &mut val;
|
||||||
@ -1083,10 +1137,19 @@ impl Engine {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let idx_values = &mut StaticVec::new();
|
let mut idx_values = StaticVec::new();
|
||||||
|
|
||||||
self.eval_indexed_chain(
|
self.eval_indexed_chain(
|
||||||
scope, mods, state, lib, this_ptr, dot_rhs, chain_type, idx_values, 0, level,
|
scope,
|
||||||
|
mods,
|
||||||
|
state,
|
||||||
|
lib,
|
||||||
|
this_ptr,
|
||||||
|
dot_rhs,
|
||||||
|
chain_type,
|
||||||
|
&mut idx_values,
|
||||||
|
0,
|
||||||
|
level,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
match dot_lhs {
|
match dot_lhs {
|
||||||
@ -1133,11 +1196,8 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a chain of indexes and store the results in a list.
|
/// Evaluate a chain of indexes and store the results in a StaticVec.
|
||||||
/// The first few results are stored in the array `list` which is of fixed length.
|
/// StaticVec is used to avoid an allocation in the overwhelming cases of just a few levels of indexing.
|
||||||
/// Any spill-overs are stored in `more`, which is dynamic.
|
|
||||||
/// The fixed length array is used to avoid an allocation in the overwhelming cases of just a few levels of indexing.
|
|
||||||
/// The total number of values is returned.
|
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
fn eval_indexed_chain(
|
fn eval_indexed_chain(
|
||||||
&self,
|
&self,
|
||||||
@ -1148,7 +1208,7 @@ impl Engine {
|
|||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
chain_type: ChainType,
|
chain_type: ChainType,
|
||||||
idx_values: &mut StaticVec<Dynamic>,
|
idx_values: &mut StaticVec<IndexChainValue>,
|
||||||
size: usize,
|
size: usize,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> Result<(), Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
@ -1162,31 +1222,30 @@ impl Engine {
|
|||||||
.map(|arg_expr| {
|
.map(|arg_expr| {
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, arg_expr, level)
|
self.eval_expr(scope, mods, state, lib, this_ptr, arg_expr, level)
|
||||||
})
|
})
|
||||||
.collect::<Result<StaticVec<Dynamic>, _>>()?;
|
.collect::<Result<StaticVec<_>, _>>()?;
|
||||||
|
|
||||||
idx_values.push(Dynamic::from(arg_values));
|
idx_values.push(arg_values.into());
|
||||||
}
|
}
|
||||||
Expr::FnCall(_) => unreachable!(),
|
Expr::FnCall(_) => unreachable!(),
|
||||||
Expr::Property(_) => idx_values.push(().into()), // Store a placeholder - no need to copy the property name
|
Expr::Property(_) => idx_values.push(IndexChainValue::None),
|
||||||
Expr::Index(x) | Expr::Dot(x) => {
|
Expr::Index(x) | Expr::Dot(x) => {
|
||||||
let (lhs, rhs, _) = x.as_ref();
|
let (lhs, rhs, _) = x.as_ref();
|
||||||
|
|
||||||
// Evaluate in left-to-right order
|
// Evaluate in left-to-right order
|
||||||
let lhs_val = match lhs {
|
let lhs_val = match lhs {
|
||||||
Expr::Property(_) => Default::default(), // Store a placeholder in case of a property
|
Expr::Property(_) => IndexChainValue::None,
|
||||||
Expr::FnCall(x) if chain_type == ChainType::Dot && x.1.is_none() => {
|
Expr::FnCall(x) if chain_type == ChainType::Dot && x.1.is_none() => {
|
||||||
let arg_values = x
|
x.3.iter()
|
||||||
.3
|
|
||||||
.iter()
|
|
||||||
.map(|arg_expr| {
|
.map(|arg_expr| {
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, arg_expr, level)
|
self.eval_expr(scope, mods, state, lib, this_ptr, arg_expr, level)
|
||||||
})
|
})
|
||||||
.collect::<Result<StaticVec<Dynamic>, _>>()?;
|
.collect::<Result<StaticVec<Dynamic>, _>>()?
|
||||||
|
.into()
|
||||||
Dynamic::from(arg_values)
|
|
||||||
}
|
}
|
||||||
Expr::FnCall(_) => unreachable!(),
|
Expr::FnCall(_) => unreachable!(),
|
||||||
_ => self.eval_expr(scope, mods, state, lib, this_ptr, lhs, level)?,
|
_ => self
|
||||||
|
.eval_expr(scope, mods, state, lib, this_ptr, lhs, level)?
|
||||||
|
.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Push in reverse order
|
// Push in reverse order
|
||||||
@ -1201,7 +1260,10 @@ impl Engine {
|
|||||||
|
|
||||||
idx_values.push(lhs_val);
|
idx_values.push(lhs_val);
|
||||||
}
|
}
|
||||||
_ => idx_values.push(self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?),
|
_ => idx_values.push(
|
||||||
|
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
112
src/fn_call.rs
112
src/fn_call.rs
@ -695,7 +695,7 @@ impl Engine {
|
|||||||
name: &str,
|
name: &str,
|
||||||
hash_script: u64,
|
hash_script: u64,
|
||||||
target: &mut Target,
|
target: &mut Target,
|
||||||
idx_val: Dynamic,
|
mut call_args: StaticVec<Dynamic>,
|
||||||
def_val: &Option<Dynamic>,
|
def_val: &Option<Dynamic>,
|
||||||
native: bool,
|
native: bool,
|
||||||
pub_only: bool,
|
pub_only: bool,
|
||||||
@ -705,7 +705,6 @@ impl Engine {
|
|||||||
|
|
||||||
// Get a reference to the mutation target Dynamic
|
// Get a reference to the mutation target Dynamic
|
||||||
let obj = target.as_mut();
|
let obj = target.as_mut();
|
||||||
let mut idx = idx_val.cast::<StaticVec<Dynamic>>();
|
|
||||||
let mut _fn_name = name;
|
let mut _fn_name = name;
|
||||||
|
|
||||||
let (result, updated) = if _fn_name == KEYWORD_FN_PTR_CALL && obj.is::<FnPtr>() {
|
let (result, updated) = if _fn_name == KEYWORD_FN_PTR_CALL && obj.is::<FnPtr>() {
|
||||||
@ -718,12 +717,12 @@ impl Engine {
|
|||||||
let hash = if native {
|
let hash = if native {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
calc_fn_hash(empty(), fn_name, curry.len() + idx.len(), empty())
|
calc_fn_hash(empty(), fn_name, curry.len() + call_args.len(), empty())
|
||||||
};
|
};
|
||||||
// Arguments are passed as-is, adding the curried arguments
|
// Arguments are passed as-is, adding the curried arguments
|
||||||
let mut arg_values = curry
|
let mut arg_values = curry
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.chain(idx.iter_mut())
|
.chain(call_args.iter_mut())
|
||||||
.collect::<StaticVec<_>>();
|
.collect::<StaticVec<_>>();
|
||||||
let args = arg_values.as_mut();
|
let args = arg_values.as_mut();
|
||||||
|
|
||||||
@ -731,9 +730,12 @@ impl Engine {
|
|||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state, lib, fn_name, hash, args, false, false, pub_only, None, def_val, level,
|
state, lib, fn_name, hash, args, false, false, pub_only, None, def_val, level,
|
||||||
)
|
)
|
||||||
} else if _fn_name == KEYWORD_FN_PTR_CALL && idx.len() > 0 && idx[0].is::<FnPtr>() {
|
} else if _fn_name == KEYWORD_FN_PTR_CALL
|
||||||
|
&& call_args.len() > 0
|
||||||
|
&& call_args[0].is::<FnPtr>()
|
||||||
|
{
|
||||||
// FnPtr call on object
|
// FnPtr call on object
|
||||||
let fn_ptr = idx.remove(0).cast::<FnPtr>();
|
let fn_ptr = call_args.remove(0).cast::<FnPtr>();
|
||||||
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
||||||
// Redirect function name
|
// Redirect function name
|
||||||
let fn_name = fn_ptr.get_fn_name().clone();
|
let fn_name = fn_ptr.get_fn_name().clone();
|
||||||
@ -741,12 +743,12 @@ impl Engine {
|
|||||||
let hash = if native {
|
let hash = if native {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
calc_fn_hash(empty(), &fn_name, curry.len() + idx.len(), empty())
|
calc_fn_hash(empty(), &fn_name, curry.len() + call_args.len(), empty())
|
||||||
};
|
};
|
||||||
// Replace the first argument with the object pointer, adding the curried arguments
|
// Replace the first argument with the object pointer, adding the curried arguments
|
||||||
let mut arg_values = once(obj)
|
let mut arg_values = once(obj)
|
||||||
.chain(curry.iter_mut())
|
.chain(curry.iter_mut())
|
||||||
.chain(idx.iter_mut())
|
.chain(call_args.iter_mut())
|
||||||
.collect::<StaticVec<_>>();
|
.collect::<StaticVec<_>>();
|
||||||
let args = arg_values.as_mut();
|
let args = arg_values.as_mut();
|
||||||
|
|
||||||
@ -764,7 +766,7 @@ impl Engine {
|
|||||||
.curry()
|
.curry()
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.chain(idx.into_iter())
|
.chain(call_args.into_iter())
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
@ -773,7 +775,7 @@ impl Engine {
|
|||||||
} else if {
|
} else if {
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
{
|
{
|
||||||
_fn_name == KEYWORD_IS_SHARED && idx.is_empty()
|
_fn_name == KEYWORD_IS_SHARED && call_args.is_empty()
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_closure")]
|
#[cfg(feature = "no_closure")]
|
||||||
false
|
false
|
||||||
@ -799,13 +801,13 @@ impl Engine {
|
|||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.for_each(|(i, v)| idx.insert(i, v));
|
.for_each(|(i, v)| call_args.insert(i, v));
|
||||||
}
|
}
|
||||||
// Recalculate the hash based on the new function name and new arguments
|
// Recalculate the hash based on the new function name and new arguments
|
||||||
hash = if native {
|
hash = if native {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
calc_fn_hash(empty(), _fn_name, idx.len(), empty())
|
calc_fn_hash(empty(), _fn_name, call_args.len(), empty())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -816,7 +818,9 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attached object pointer in front of the arguments
|
// Attached object pointer in front of the arguments
|
||||||
let mut arg_values = once(obj).chain(idx.iter_mut()).collect::<StaticVec<_>>();
|
let mut arg_values = once(obj)
|
||||||
|
.chain(call_args.iter_mut())
|
||||||
|
.collect::<StaticVec<_>>();
|
||||||
let args = arg_values.as_mut();
|
let args = arg_values.as_mut();
|
||||||
|
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
@ -873,28 +877,29 @@ 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 arg_value = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
let fn_ptr = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||||
|
|
||||||
if !arg_value.is::<FnPtr>() {
|
if !fn_ptr.is::<FnPtr>() {
|
||||||
return Err(self.make_type_mismatch_err::<FnPtr>(
|
return Err(self.make_type_mismatch_err::<FnPtr>(
|
||||||
self.map_type_name(arg_value.type_name()),
|
self.map_type_name(fn_ptr.type_name()),
|
||||||
expr.position(),
|
expr.position(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (fn_name, fn_curry) = arg_value.cast::<FnPtr>().take_data();
|
let (fn_name, fn_curry) = fn_ptr.cast::<FnPtr>().take_data();
|
||||||
|
|
||||||
let curry: StaticVec<_> = args_expr
|
let mut curry = fn_curry.clone();
|
||||||
|
|
||||||
|
// Append the new curried arguments to the existing list.
|
||||||
|
args_expr
|
||||||
.iter()
|
.iter()
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.map(|expr| self.eval_expr(scope, mods, state, lib, this_ptr, expr, level))
|
.try_for_each(|expr| -> Result<(), Box<EvalAltResult>> {
|
||||||
.collect::<Result<_, _>>()?;
|
curry.push(self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?);
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
return Ok(FnPtr::new_unchecked(
|
return Ok(FnPtr::new_unchecked(fn_name, curry).into());
|
||||||
fn_name,
|
|
||||||
fn_curry.into_iter().chain(curry.into_iter()).collect(),
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle is_shared()
|
// Handle is_shared()
|
||||||
@ -917,24 +922,27 @@ 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 arg_value = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
let fn_ptr = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||||
|
|
||||||
if arg_value.is::<FnPtr>() {
|
if !fn_ptr.is::<FnPtr>() {
|
||||||
let fn_ptr = arg_value.cast::<FnPtr>();
|
|
||||||
curry = fn_ptr.curry().iter().cloned().collect();
|
|
||||||
// Redirect function name
|
|
||||||
redirected = fn_ptr.take_data().0;
|
|
||||||
name = &redirected;
|
|
||||||
// Skip the first argument
|
|
||||||
args_expr = &args_expr.as_ref()[1..];
|
|
||||||
// Recalculate hash
|
|
||||||
hash_script = calc_fn_hash(empty(), name, curry.len() + args_expr.len(), empty());
|
|
||||||
} else {
|
|
||||||
return Err(self.make_type_mismatch_err::<FnPtr>(
|
return Err(self.make_type_mismatch_err::<FnPtr>(
|
||||||
self.map_type_name(arg_value.type_name()),
|
self.map_type_name(fn_ptr.type_name()),
|
||||||
expr.position(),
|
expr.position(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let fn_ptr = fn_ptr.cast::<FnPtr>();
|
||||||
|
curry = fn_ptr.curry().iter().cloned().collect();
|
||||||
|
|
||||||
|
// Redirect function name
|
||||||
|
redirected = fn_ptr.take_data().0;
|
||||||
|
name = &redirected;
|
||||||
|
|
||||||
|
// Skip the first argument
|
||||||
|
args_expr = &args_expr.as_ref()[1..];
|
||||||
|
|
||||||
|
// Recalculate hash
|
||||||
|
hash_script = calc_fn_hash(empty(), name, curry.len() + args_expr.len(), empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle is_def_var()
|
// Handle is_def_var()
|
||||||
@ -943,8 +951,8 @@ 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();
|
||||||
let arg_value = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
let var_name = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||||
let var_name = arg_value.as_str().map_err(|err| {
|
let var_name = var_name.as_str().map_err(|err| {
|
||||||
self.make_type_mismatch_err::<ImmutableString>(err, expr.position())
|
self.make_type_mismatch_err::<ImmutableString>(err, expr.position())
|
||||||
})?;
|
})?;
|
||||||
if var_name.is_empty() {
|
if var_name.is_empty() {
|
||||||
@ -967,20 +975,18 @@ 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 fn_name_expr = args_expr.get(0).unwrap();
|
let expr0 = args_expr.get(0).unwrap();
|
||||||
let num_params_expr = args_expr.get(1).unwrap();
|
let expr1 = args_expr.get(1).unwrap();
|
||||||
|
|
||||||
let arg0_value =
|
let fn_name = self.eval_expr(scope, mods, state, lib, this_ptr, expr0, level)?;
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, fn_name_expr, level)?;
|
let num_params = self.eval_expr(scope, mods, state, lib, this_ptr, expr1, level)?;
|
||||||
let arg1_value =
|
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, num_params_expr, level)?;
|
|
||||||
|
|
||||||
let fn_name = arg0_value.as_str().map_err(|err| {
|
let fn_name = fn_name.as_str().map_err(|err| {
|
||||||
self.make_type_mismatch_err::<ImmutableString>(err, fn_name_expr.position())
|
self.make_type_mismatch_err::<ImmutableString>(err, expr0.position())
|
||||||
})?;
|
|
||||||
let num_params = arg1_value.as_int().map_err(|err| {
|
|
||||||
self.make_type_mismatch_err::<INT>(err, num_params_expr.position())
|
|
||||||
})?;
|
})?;
|
||||||
|
let num_params = num_params
|
||||||
|
.as_int()
|
||||||
|
.map_err(|err| self.make_type_mismatch_err::<INT>(err, expr1.position()))?;
|
||||||
|
|
||||||
if fn_name.is_empty() || num_params < 0 {
|
if fn_name.is_empty() || num_params < 0 {
|
||||||
return Ok(false.into());
|
return Ok(false.into());
|
||||||
@ -999,8 +1005,8 @@ 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 arg_value = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
let script = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||||
let script = arg_value.as_str().map_err(|typ| {
|
let script = script.as_str().map_err(|typ| {
|
||||||
self.make_type_mismatch_err::<ImmutableString>(typ, expr.position())
|
self.make_type_mismatch_err::<ImmutableString>(typ, expr.position())
|
||||||
})?;
|
})?;
|
||||||
let result = if !script.is_empty() {
|
let result = if !script.is_empty() {
|
||||||
|
Loading…
Reference in New Issue
Block a user