Use reference for method call parameters, add position info.
This commit is contained in:
parent
fefa5a7dc7
commit
795a3afa81
@ -17,7 +17,6 @@ use crate::stdlib::{
|
|||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
fmt, format,
|
fmt, format,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
iter::empty,
|
|
||||||
num::{NonZeroU64, NonZeroU8, NonZeroUsize},
|
num::{NonZeroU64, NonZeroU8, NonZeroUsize},
|
||||||
ops::DerefMut,
|
ops::DerefMut,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
@ -25,12 +24,12 @@ use crate::stdlib::{
|
|||||||
use crate::syntax::CustomSyntax;
|
use crate::syntax::CustomSyntax;
|
||||||
use crate::utils::{get_hasher, StraightHasherBuilder};
|
use crate::utils::{get_hasher, StraightHasherBuilder};
|
||||||
use crate::{
|
use crate::{
|
||||||
calc_fn_hash, Dynamic, EvalAltResult, FnPtr, ImmutableString, Module, Position, RhaiResult,
|
Dynamic, EvalAltResult, FnPtr, ImmutableString, Module, Position, RhaiResult, Scope, Shared,
|
||||||
Scope, Shared, StaticVec,
|
StaticVec,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
use crate::Array;
|
use crate::{calc_fn_hash, stdlib::iter::empty, Array};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub const TYPICAL_ARRAY_SIZE: usize = 8; // Small arrays are typical
|
pub const TYPICAL_ARRAY_SIZE: usize = 8; // Small arrays are typical
|
||||||
@ -223,11 +222,11 @@ pub enum ChainType {
|
|||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub enum ChainArgument {
|
pub enum ChainArgument {
|
||||||
/// Dot-property access.
|
/// Dot-property access.
|
||||||
Property,
|
Property(Position),
|
||||||
/// Arguments to a dot-function call.
|
/// Arguments to a dot-function call.
|
||||||
FnCallArgs(StaticVec<Dynamic>),
|
FnCallArgs(StaticVec<(Dynamic, Position)>),
|
||||||
/// Index value.
|
/// Index value.
|
||||||
IndexValue(Dynamic),
|
IndexValue(Dynamic, Position),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
@ -241,8 +240,10 @@ impl ChainArgument {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub fn as_index_value(self) -> Dynamic {
|
pub fn as_index_value(self) -> Dynamic {
|
||||||
match self {
|
match self {
|
||||||
Self::Property | Self::FnCallArgs(_) => panic!("expecting ChainArgument::IndexValue"),
|
Self::Property(_) | Self::FnCallArgs(_) => {
|
||||||
Self::IndexValue(value) => value,
|
panic!("expecting ChainArgument::IndexValue")
|
||||||
|
}
|
||||||
|
Self::IndexValue(value, _) => value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Return the `StaticVec<Dynamic>` value.
|
/// Return the `StaticVec<Dynamic>` value.
|
||||||
@ -252,27 +253,29 @@ impl ChainArgument {
|
|||||||
/// Panics if not `ChainArgument::FnCallArgs`.
|
/// Panics if not `ChainArgument::FnCallArgs`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub fn as_fn_call_args(self) -> StaticVec<Dynamic> {
|
pub fn as_fn_call_args(self) -> StaticVec<(Dynamic, Position)> {
|
||||||
match self {
|
match self {
|
||||||
Self::Property | Self::IndexValue(_) => panic!("expecting ChainArgument::FnCallArgs"),
|
Self::Property(_) | Self::IndexValue(_, _) => {
|
||||||
|
panic!("expecting ChainArgument::FnCallArgs")
|
||||||
|
}
|
||||||
Self::FnCallArgs(value) => value,
|
Self::FnCallArgs(value) => value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
impl From<StaticVec<Dynamic>> for ChainArgument {
|
impl From<StaticVec<(Dynamic, Position)>> for ChainArgument {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: StaticVec<Dynamic>) -> Self {
|
fn from(value: StaticVec<(Dynamic, Position)>) -> Self {
|
||||||
Self::FnCallArgs(value)
|
Self::FnCallArgs(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
impl From<Dynamic> for ChainArgument {
|
impl From<(Dynamic, Position)> for ChainArgument {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: Dynamic) -> Self {
|
fn from((value, pos): (Dynamic, Position)) -> Self {
|
||||||
Self::IndexValue(value)
|
Self::IndexValue(value, pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,7 +398,11 @@ impl<'a> Target<'a> {
|
|||||||
}
|
}
|
||||||
/// Update the value of the `Target`.
|
/// Update the value of the `Target`.
|
||||||
#[cfg(any(not(feature = "no_object"), not(feature = "no_index")))]
|
#[cfg(any(not(feature = "no_object"), not(feature = "no_index")))]
|
||||||
pub fn set_value(&mut self, new_val: Dynamic, pos: Position) -> Result<(), Box<EvalAltResult>> {
|
pub fn set_value(
|
||||||
|
&mut self,
|
||||||
|
new_val: Dynamic,
|
||||||
|
_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"))]
|
||||||
@ -411,7 +418,7 @@ impl<'a> Target<'a> {
|
|||||||
Box::new(EvalAltResult::ErrorMismatchDataType(
|
Box::new(EvalAltResult::ErrorMismatchDataType(
|
||||||
"char".to_string(),
|
"char".to_string(),
|
||||||
err.to_string(),
|
err.to_string(),
|
||||||
pos,
|
_pos,
|
||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@ -1152,9 +1159,9 @@ impl Engine {
|
|||||||
// xxx.fn_name(arg_expr_list)
|
// xxx.fn_name(arg_expr_list)
|
||||||
Expr::FnCall(x, pos) if x.namespace.is_none() && new_val.is_none() => {
|
Expr::FnCall(x, pos) if x.namespace.is_none() && new_val.is_none() => {
|
||||||
let FnCallExpr { name, hash, .. } = x.as_ref();
|
let FnCallExpr { name, hash, .. } = x.as_ref();
|
||||||
let args = idx_val.as_fn_call_args();
|
let mut args = idx_val.as_fn_call_args();
|
||||||
self.make_method_call(
|
self.make_method_call(
|
||||||
mods, state, lib, name, *hash, target, args, *pos, level,
|
mods, state, lib, name, *hash, target, &mut args, *pos, level,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// xxx.fn_name(...) = ???
|
// xxx.fn_name(...) = ???
|
||||||
@ -1225,9 +1232,9 @@ impl Engine {
|
|||||||
// {xxx:map}.fn_name(arg_expr_list)[expr] | {xxx:map}.fn_name(arg_expr_list).expr
|
// {xxx:map}.fn_name(arg_expr_list)[expr] | {xxx:map}.fn_name(arg_expr_list).expr
|
||||||
Expr::FnCall(x, pos) if x.namespace.is_none() => {
|
Expr::FnCall(x, pos) if x.namespace.is_none() => {
|
||||||
let FnCallExpr { name, hash, .. } = x.as_ref();
|
let FnCallExpr { name, hash, .. } = x.as_ref();
|
||||||
let args = idx_val.as_fn_call_args();
|
let mut args = idx_val.as_fn_call_args();
|
||||||
let (val, _) = self.make_method_call(
|
let (val, _) = self.make_method_call(
|
||||||
mods, state, lib, name, *hash, target, args, *pos, level,
|
mods, state, lib, name, *hash, target, &mut args, *pos, level,
|
||||||
)?;
|
)?;
|
||||||
val.into()
|
val.into()
|
||||||
}
|
}
|
||||||
@ -1303,9 +1310,9 @@ impl Engine {
|
|||||||
// xxx.fn_name(arg_expr_list)[expr] | xxx.fn_name(arg_expr_list).expr
|
// xxx.fn_name(arg_expr_list)[expr] | xxx.fn_name(arg_expr_list).expr
|
||||||
Expr::FnCall(f, pos) if f.namespace.is_none() => {
|
Expr::FnCall(f, pos) if f.namespace.is_none() => {
|
||||||
let FnCallExpr { name, hash, .. } = f.as_ref();
|
let FnCallExpr { name, hash, .. } = f.as_ref();
|
||||||
let args = idx_val.as_fn_call_args();
|
let mut args = idx_val.as_fn_call_args();
|
||||||
let (mut val, _) = self.make_method_call(
|
let (mut val, _) = self.make_method_call(
|
||||||
mods, state, lib, name, *hash, target, args, *pos, level,
|
mods, state, lib, name, *hash, target, &mut args, *pos, level,
|
||||||
)?;
|
)?;
|
||||||
let val = &mut val;
|
let val = &mut val;
|
||||||
let target = &mut val.into();
|
let target = &mut val.into();
|
||||||
@ -1427,7 +1434,7 @@ impl Engine {
|
|||||||
.iter()
|
.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)
|
||||||
.map(Dynamic::flatten)
|
.map(|v| (v.flatten(), arg_expr.position()))
|
||||||
})
|
})
|
||||||
.collect::<Result<StaticVec<_>, _>>()?;
|
.collect::<Result<StaticVec<_>, _>>()?;
|
||||||
|
|
||||||
@ -1437,8 +1444,8 @@ impl Engine {
|
|||||||
unreachable!("function call in dot chain should not be namespace-qualified")
|
unreachable!("function call in dot chain should not be namespace-qualified")
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Property(_) if parent_chain_type == ChainType::Dot => {
|
Expr::Property(x) if parent_chain_type == ChainType::Dot => {
|
||||||
idx_values.push(ChainArgument::Property)
|
idx_values.push(ChainArgument::Property(x.4.pos))
|
||||||
}
|
}
|
||||||
Expr::Property(_) => unreachable!("unexpected Expr::Property for indexing"),
|
Expr::Property(_) => unreachable!("unexpected Expr::Property for indexing"),
|
||||||
|
|
||||||
@ -1447,8 +1454,8 @@ impl Engine {
|
|||||||
|
|
||||||
// Evaluate in left-to-right order
|
// Evaluate in left-to-right order
|
||||||
let lhs_val = match lhs {
|
let lhs_val = match lhs {
|
||||||
Expr::Property(_) if parent_chain_type == ChainType::Dot => {
|
Expr::Property(x) if parent_chain_type == ChainType::Dot => {
|
||||||
ChainArgument::Property
|
ChainArgument::Property(x.4.pos)
|
||||||
}
|
}
|
||||||
Expr::Property(_) => unreachable!("unexpected Expr::Property for indexing"),
|
Expr::Property(_) => unreachable!("unexpected Expr::Property for indexing"),
|
||||||
Expr::FnCall(x, _)
|
Expr::FnCall(x, _)
|
||||||
@ -1458,18 +1465,17 @@ impl Engine {
|
|||||||
.iter()
|
.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)
|
||||||
.map(Dynamic::flatten)
|
.map(|v| (v.flatten(), arg_expr.position()))
|
||||||
})
|
})
|
||||||
.collect::<Result<StaticVec<Dynamic>, _>>()?
|
.collect::<Result<StaticVec<_>, _>>()?
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
Expr::FnCall(_, _) if parent_chain_type == ChainType::Dot => {
|
Expr::FnCall(_, _) if parent_chain_type == ChainType::Dot => {
|
||||||
unreachable!("function call in dot chain should not be namespace-qualified")
|
unreachable!("function call in dot chain should not be namespace-qualified")
|
||||||
}
|
}
|
||||||
_ => self
|
_ => self
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, lhs, level)?
|
.eval_expr(scope, mods, state, lib, this_ptr, lhs, level)
|
||||||
.flatten()
|
.map(|v| (v.flatten(), lhs.position()).into())?,
|
||||||
.into(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Push in reverse order
|
// Push in reverse order
|
||||||
@ -1486,9 +1492,8 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_ => idx_values.push(
|
_ => idx_values.push(
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)
|
||||||
.flatten()
|
.map(|v| (v.flatten(), expr.position()).into())?,
|
||||||
.into(),
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1745,13 +1750,13 @@ impl Engine {
|
|||||||
Expr::FnCall(x, pos) if x.namespace.is_none() => {
|
Expr::FnCall(x, pos) if x.namespace.is_none() => {
|
||||||
let FnCallExpr {
|
let FnCallExpr {
|
||||||
name,
|
name,
|
||||||
capture: cap_scope,
|
capture,
|
||||||
hash,
|
hash,
|
||||||
args,
|
args,
|
||||||
..
|
..
|
||||||
} = x.as_ref();
|
} = x.as_ref();
|
||||||
self.make_function_call(
|
self.make_function_call(
|
||||||
scope, mods, state, lib, this_ptr, name, args, *hash, *pos, *cap_scope, level,
|
scope, mods, state, lib, this_ptr, name, args, *hash, *pos, *capture, level,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,7 +884,7 @@ impl Engine {
|
|||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
mut hash: FnHash,
|
mut hash: FnHash,
|
||||||
target: &mut crate::engine::Target,
|
target: &mut crate::engine::Target,
|
||||||
mut call_args: StaticVec<Dynamic>,
|
call_args: &mut StaticVec<(Dynamic, Position)>,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||||
@ -907,7 +907,7 @@ impl Engine {
|
|||||||
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
||||||
let mut arg_values = curry
|
let mut arg_values = curry
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.chain(call_args.iter_mut())
|
.chain(call_args.iter_mut().map(|v| &mut v.0))
|
||||||
.collect::<StaticVec<_>>();
|
.collect::<StaticVec<_>>();
|
||||||
let args = arg_values.as_mut();
|
let args = arg_values.as_mut();
|
||||||
|
|
||||||
@ -916,9 +916,23 @@ impl Engine {
|
|||||||
mods, state, lib, fn_name, hash, args, false, false, pos, None, level,
|
mods, state, lib, fn_name, hash, args, false, false, pos, None, level,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
KEYWORD_FN_PTR_CALL if call_args.len() > 0 && call_args[0].is::<FnPtr>() => {
|
KEYWORD_FN_PTR_CALL => {
|
||||||
|
if call_args.len() > 0 {
|
||||||
|
if !call_args[0].0.is::<FnPtr>() {
|
||||||
|
return Err(self.make_type_mismatch_err::<FnPtr>(
|
||||||
|
self.map_type_name(obj.type_name()),
|
||||||
|
call_args[0].1,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(self.make_type_mismatch_err::<FnPtr>(
|
||||||
|
self.map_type_name(obj.type_name()),
|
||||||
|
pos,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// FnPtr call on object
|
// FnPtr call on object
|
||||||
let fn_ptr = call_args.remove(0).cast::<FnPtr>();
|
let fn_ptr = call_args.remove(0).0.cast::<FnPtr>();
|
||||||
// Redirect function name
|
// Redirect function name
|
||||||
let fn_name = fn_ptr.fn_name();
|
let fn_name = fn_ptr.fn_name();
|
||||||
let args_len = call_args.len() + fn_ptr.curry().len();
|
let args_len = call_args.len() + fn_ptr.curry().len();
|
||||||
@ -931,7 +945,7 @@ impl Engine {
|
|||||||
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
||||||
let mut arg_values = once(obj)
|
let mut arg_values = once(obj)
|
||||||
.chain(curry.iter_mut())
|
.chain(curry.iter_mut())
|
||||||
.chain(call_args.iter_mut())
|
.chain(call_args.iter_mut().map(|v| &mut v.0))
|
||||||
.collect::<StaticVec<_>>();
|
.collect::<StaticVec<_>>();
|
||||||
let args = arg_values.as_mut();
|
let args = arg_values.as_mut();
|
||||||
|
|
||||||
@ -940,19 +954,31 @@ impl Engine {
|
|||||||
mods, state, lib, fn_name, hash, args, is_ref, true, pos, None, level,
|
mods, state, lib, fn_name, hash, args, is_ref, true, pos, None, level,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
KEYWORD_FN_PTR_CURRY if obj.is::<FnPtr>() => {
|
KEYWORD_FN_PTR_CURRY => {
|
||||||
// Curry call
|
if !obj.is::<FnPtr>() {
|
||||||
|
return Err(self.make_type_mismatch_err::<FnPtr>(
|
||||||
|
self.map_type_name(obj.type_name()),
|
||||||
|
pos,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let fn_ptr = obj.read_lock::<FnPtr>().unwrap();
|
let fn_ptr = obj.read_lock::<FnPtr>().unwrap();
|
||||||
|
|
||||||
|
// Curry call
|
||||||
Ok((
|
Ok((
|
||||||
FnPtr::new_unchecked(
|
if call_args.is_empty() {
|
||||||
fn_ptr.get_fn_name().clone(),
|
fn_ptr.clone()
|
||||||
fn_ptr
|
} else {
|
||||||
.curry()
|
FnPtr::new_unchecked(
|
||||||
.iter()
|
fn_ptr.get_fn_name().clone(),
|
||||||
.cloned()
|
fn_ptr
|
||||||
.chain(call_args.into_iter())
|
.curry()
|
||||||
.collect(),
|
.iter()
|
||||||
)
|
.cloned()
|
||||||
|
.chain(call_args.iter_mut().map(|v| mem::take(v).0))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
.into(),
|
.into(),
|
||||||
false,
|
false,
|
||||||
))
|
))
|
||||||
@ -981,7 +1007,7 @@ impl Engine {
|
|||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.for_each(|(i, v)| call_args.insert(i, v));
|
.for_each(|(i, v)| call_args.insert(i, (v, Position::NONE)));
|
||||||
// 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 = FnHash::from_script_and_native(
|
hash = FnHash::from_script_and_native(
|
||||||
calc_fn_hash(empty(), fn_name, call_args.len()),
|
calc_fn_hash(empty(), fn_name, call_args.len()),
|
||||||
@ -993,7 +1019,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Attached object pointer in front of the arguments
|
// Attached object pointer in front of the arguments
|
||||||
let mut arg_values = once(obj)
|
let mut arg_values = once(obj)
|
||||||
.chain(call_args.iter_mut())
|
.chain(call_args.iter_mut().map(|v| &mut v.0))
|
||||||
.collect::<StaticVec<_>>();
|
.collect::<StaticVec<_>>();
|
||||||
let args = arg_values.as_mut();
|
let args = arg_values.as_mut();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user