From 795a3afa8107abb39d17b8d19e749ca0da3d7896 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 9 Mar 2021 00:07:05 +0800 Subject: [PATCH] Use reference for method call parameters, add position info. --- src/engine.rs | 83 ++++++++++++++++++++++++++------------------------ src/fn_call.rs | 62 ++++++++++++++++++++++++++----------- 2 files changed, 88 insertions(+), 57 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index 30f6d1a4..ce6dcb13 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -17,7 +17,6 @@ use crate::stdlib::{ collections::{HashMap, HashSet}, fmt, format, hash::{Hash, Hasher}, - iter::empty, num::{NonZeroU64, NonZeroU8, NonZeroUsize}, ops::DerefMut, string::{String, ToString}, @@ -25,12 +24,12 @@ use crate::stdlib::{ use crate::syntax::CustomSyntax; use crate::utils::{get_hasher, StraightHasherBuilder}; use crate::{ - calc_fn_hash, Dynamic, EvalAltResult, FnPtr, ImmutableString, Module, Position, RhaiResult, - Scope, Shared, StaticVec, + Dynamic, EvalAltResult, FnPtr, ImmutableString, Module, Position, RhaiResult, Scope, Shared, + StaticVec, }; #[cfg(not(feature = "no_index"))] -use crate::Array; +use crate::{calc_fn_hash, stdlib::iter::empty, Array}; #[cfg(not(feature = "no_index"))] pub const TYPICAL_ARRAY_SIZE: usize = 8; // Small arrays are typical @@ -223,11 +222,11 @@ pub enum ChainType { #[derive(Debug, Clone, Hash)] pub enum ChainArgument { /// Dot-property access. - Property, + Property(Position), /// Arguments to a dot-function call. - FnCallArgs(StaticVec), + FnCallArgs(StaticVec<(Dynamic, Position)>), /// Index value. - IndexValue(Dynamic), + IndexValue(Dynamic, Position), } #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] @@ -241,8 +240,10 @@ impl ChainArgument { #[cfg(not(feature = "no_index"))] pub fn as_index_value(self) -> Dynamic { match self { - Self::Property | Self::FnCallArgs(_) => panic!("expecting ChainArgument::IndexValue"), - Self::IndexValue(value) => value, + Self::Property(_) | Self::FnCallArgs(_) => { + panic!("expecting ChainArgument::IndexValue") + } + Self::IndexValue(value, _) => value, } } /// Return the `StaticVec` value. @@ -252,27 +253,29 @@ impl ChainArgument { /// Panics if not `ChainArgument::FnCallArgs`. #[inline(always)] #[cfg(not(feature = "no_object"))] - pub fn as_fn_call_args(self) -> StaticVec { + pub fn as_fn_call_args(self) -> StaticVec<(Dynamic, Position)> { match self { - Self::Property | Self::IndexValue(_) => panic!("expecting ChainArgument::FnCallArgs"), + Self::Property(_) | Self::IndexValue(_, _) => { + panic!("expecting ChainArgument::FnCallArgs") + } Self::FnCallArgs(value) => value, } } } #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] -impl From> for ChainArgument { +impl From> for ChainArgument { #[inline(always)] - fn from(value: StaticVec) -> Self { + fn from(value: StaticVec<(Dynamic, Position)>) -> Self { Self::FnCallArgs(value) } } #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] -impl From for ChainArgument { +impl From<(Dynamic, Position)> for ChainArgument { #[inline(always)] - fn from(value: Dynamic) -> Self { - Self::IndexValue(value) + fn from((value, pos): (Dynamic, Position)) -> Self { + Self::IndexValue(value, pos) } } @@ -395,7 +398,11 @@ impl<'a> Target<'a> { } /// Update the value of the `Target`. #[cfg(any(not(feature = "no_object"), not(feature = "no_index")))] - pub fn set_value(&mut self, new_val: Dynamic, pos: Position) -> Result<(), Box> { + pub fn set_value( + &mut self, + new_val: Dynamic, + _pos: Position, + ) -> Result<(), Box> { match self { Self::Ref(r) => **r = new_val, #[cfg(not(feature = "no_closure"))] @@ -411,7 +418,7 @@ impl<'a> Target<'a> { Box::new(EvalAltResult::ErrorMismatchDataType( "char".to_string(), err.to_string(), - pos, + _pos, )) })?; @@ -1152,9 +1159,9 @@ impl Engine { // xxx.fn_name(arg_expr_list) Expr::FnCall(x, pos) if x.namespace.is_none() && new_val.is_none() => { 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( - mods, state, lib, name, *hash, target, args, *pos, level, + mods, state, lib, name, *hash, target, &mut args, *pos, level, ) } // 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 Expr::FnCall(x, pos) if x.namespace.is_none() => { 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( - mods, state, lib, name, *hash, target, args, *pos, level, + mods, state, lib, name, *hash, target, &mut args, *pos, level, )?; val.into() } @@ -1303,9 +1310,9 @@ impl Engine { // xxx.fn_name(arg_expr_list)[expr] | xxx.fn_name(arg_expr_list).expr Expr::FnCall(f, pos) if f.namespace.is_none() => { 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( - mods, state, lib, name, *hash, target, args, *pos, level, + mods, state, lib, name, *hash, target, &mut args, *pos, level, )?; let val = &mut val; let target = &mut val.into(); @@ -1427,7 +1434,7 @@ impl Engine { .iter() .map(|arg_expr| { self.eval_expr(scope, mods, state, lib, this_ptr, arg_expr, level) - .map(Dynamic::flatten) + .map(|v| (v.flatten(), arg_expr.position())) }) .collect::, _>>()?; @@ -1437,8 +1444,8 @@ impl Engine { unreachable!("function call in dot chain should not be namespace-qualified") } - Expr::Property(_) if parent_chain_type == ChainType::Dot => { - idx_values.push(ChainArgument::Property) + Expr::Property(x) if parent_chain_type == ChainType::Dot => { + idx_values.push(ChainArgument::Property(x.4.pos)) } Expr::Property(_) => unreachable!("unexpected Expr::Property for indexing"), @@ -1447,8 +1454,8 @@ impl Engine { // Evaluate in left-to-right order let lhs_val = match lhs { - Expr::Property(_) if parent_chain_type == ChainType::Dot => { - ChainArgument::Property + Expr::Property(x) if parent_chain_type == ChainType::Dot => { + ChainArgument::Property(x.4.pos) } Expr::Property(_) => unreachable!("unexpected Expr::Property for indexing"), Expr::FnCall(x, _) @@ -1458,18 +1465,17 @@ impl Engine { .iter() .map(|arg_expr| { self.eval_expr(scope, mods, state, lib, this_ptr, arg_expr, level) - .map(Dynamic::flatten) + .map(|v| (v.flatten(), arg_expr.position())) }) - .collect::, _>>()? + .collect::, _>>()? .into() } Expr::FnCall(_, _) if parent_chain_type == ChainType::Dot => { unreachable!("function call in dot chain should not be namespace-qualified") } _ => self - .eval_expr(scope, mods, state, lib, this_ptr, lhs, level)? - .flatten() - .into(), + .eval_expr(scope, mods, state, lib, this_ptr, lhs, level) + .map(|v| (v.flatten(), lhs.position()).into())?, }; // Push in reverse order @@ -1486,9 +1492,8 @@ impl Engine { } _ => idx_values.push( - self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)? - .flatten() - .into(), + self.eval_expr(scope, mods, state, lib, this_ptr, expr, level) + .map(|v| (v.flatten(), expr.position()).into())?, ), } @@ -1745,13 +1750,13 @@ impl Engine { Expr::FnCall(x, pos) if x.namespace.is_none() => { let FnCallExpr { name, - capture: cap_scope, + capture, hash, args, .. } = x.as_ref(); 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, ) } diff --git a/src/fn_call.rs b/src/fn_call.rs index 63fe6079..d4fe037f 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -884,7 +884,7 @@ impl Engine { fn_name: &str, mut hash: FnHash, target: &mut crate::engine::Target, - mut call_args: StaticVec, + call_args: &mut StaticVec<(Dynamic, Position)>, pos: Position, level: usize, ) -> Result<(Dynamic, bool), Box> { @@ -907,7 +907,7 @@ impl Engine { let mut curry = fn_ptr.curry().iter().cloned().collect::>(); let mut arg_values = curry .iter_mut() - .chain(call_args.iter_mut()) + .chain(call_args.iter_mut().map(|v| &mut v.0)) .collect::>(); let args = arg_values.as_mut(); @@ -916,9 +916,23 @@ impl Engine { 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::() => { + KEYWORD_FN_PTR_CALL => { + if call_args.len() > 0 { + if !call_args[0].0.is::() { + return Err(self.make_type_mismatch_err::( + self.map_type_name(obj.type_name()), + call_args[0].1, + )); + } + } else { + return Err(self.make_type_mismatch_err::( + self.map_type_name(obj.type_name()), + pos, + )); + } + // FnPtr call on object - let fn_ptr = call_args.remove(0).cast::(); + let fn_ptr = call_args.remove(0).0.cast::(); // Redirect function name let fn_name = fn_ptr.fn_name(); 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::>(); let mut arg_values = once(obj) .chain(curry.iter_mut()) - .chain(call_args.iter_mut()) + .chain(call_args.iter_mut().map(|v| &mut v.0)) .collect::>(); 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, ) } - KEYWORD_FN_PTR_CURRY if obj.is::() => { - // Curry call + KEYWORD_FN_PTR_CURRY => { + if !obj.is::() { + return Err(self.make_type_mismatch_err::( + self.map_type_name(obj.type_name()), + pos, + )); + } + let fn_ptr = obj.read_lock::().unwrap(); + + // Curry call Ok(( - FnPtr::new_unchecked( - fn_ptr.get_fn_name().clone(), - fn_ptr - .curry() - .iter() - .cloned() - .chain(call_args.into_iter()) - .collect(), - ) + if call_args.is_empty() { + fn_ptr.clone() + } else { + FnPtr::new_unchecked( + fn_ptr.get_fn_name().clone(), + fn_ptr + .curry() + .iter() + .cloned() + .chain(call_args.iter_mut().map(|v| mem::take(v).0)) + .collect(), + ) + } .into(), false, )) @@ -981,7 +1007,7 @@ impl Engine { .iter() .cloned() .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 hash = FnHash::from_script_and_native( calc_fn_hash(empty(), fn_name, call_args.len()), @@ -993,7 +1019,7 @@ impl Engine { // Attached object pointer in front of the arguments let mut arg_values = once(obj) - .chain(call_args.iter_mut()) + .chain(call_args.iter_mut().map(|v| &mut v.0)) .collect::>(); let args = arg_values.as_mut();