Use reference for method call parameters, add position info.

This commit is contained in:
Stephen Chung 2021-03-09 00:07:05 +08:00
parent fefa5a7dc7
commit 795a3afa81
2 changed files with 88 additions and 57 deletions

View File

@ -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,
) )
} }

View File

@ -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((
if call_args.is_empty() {
fn_ptr.clone()
} else {
FnPtr::new_unchecked( FnPtr::new_unchecked(
fn_ptr.get_fn_name().clone(), fn_ptr.get_fn_name().clone(),
fn_ptr fn_ptr
.curry() .curry()
.iter() .iter()
.cloned() .cloned()
.chain(call_args.into_iter()) .chain(call_args.iter_mut().map(|v| mem::take(v).0))
.collect(), .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();