From 9daa894e257044087e63a50767bb463339db5fa1 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 9 Mar 2021 18:11:43 +0800 Subject: [PATCH] Pack method call args more tightly. --- CHANGELOG.md | 1 + src/engine.rs | 34 +++++++++++++++++++++------------- src/fn_call.rs | 22 +++++++++++++--------- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c0f4af9..c9a74be3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ Breaking changes * `is_def_var` and `is_def_fn` are now reserved keywords. * `Engine::id` field is removed. * `num-traits` is now a required dependency. +* The `in` operator is now implemented on top of the `contains` function and is no longer restricted to a few specific types. Enhancements ------------ diff --git a/src/engine.rs b/src/engine.rs index 017b2e27..274710bd 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -230,7 +230,7 @@ pub enum ChainArgument { /// Dot-property access. Property(Position), /// Arguments to a dot-function call. - FnCallArgs(StaticVec<(Dynamic, Position)>), + FnCallArgs(StaticVec, StaticVec), /// Index value. IndexValue(Dynamic, Position), } @@ -246,7 +246,7 @@ impl ChainArgument { #[cfg(not(feature = "no_index"))] pub fn as_index_value(self) -> Dynamic { match self { - Self::Property(_) | Self::FnCallArgs(_) => { + Self::Property(_) | Self::FnCallArgs(_, _) => { panic!("expecting ChainArgument::IndexValue") } Self::IndexValue(value, _) => value, @@ -259,21 +259,21 @@ impl ChainArgument { /// Panics if not `ChainArgument::FnCallArgs`. #[inline(always)] #[cfg(not(feature = "no_object"))] - pub fn as_fn_call_args(self) -> StaticVec<(Dynamic, Position)> { + pub fn as_fn_call_args(self) -> (StaticVec, StaticVec) { match self { Self::Property(_) | Self::IndexValue(_, _) => { panic!("expecting ChainArgument::FnCallArgs") } - Self::FnCallArgs(value) => value, + Self::FnCallArgs(values, positions) => (values, positions), } } } #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] -impl From> for ChainArgument { +impl From<(StaticVec, StaticVec)> for ChainArgument { #[inline(always)] - fn from(value: StaticVec<(Dynamic, Position)>) -> Self { - Self::FnCallArgs(value) + fn from((values, positions): (StaticVec, StaticVec)) -> Self { + Self::FnCallArgs(values, positions) } } @@ -1436,16 +1436,19 @@ impl Engine { match expr { Expr::FnCall(x, _) if parent_chain_type == ChainType::Dot && x.namespace.is_none() => { + let mut arg_positions: StaticVec<_> = Default::default(); + let arg_values = x .args .iter() .map(|arg_expr| { + arg_positions.push(arg_expr.position()); self.eval_expr(scope, mods, state, lib, this_ptr, arg_expr, level) - .map(|v| (v.flatten(), arg_expr.position())) + .map(Dynamic::flatten) }) .collect::, _>>()?; - idx_values.push(arg_values.into()); + idx_values.push((arg_values, arg_positions).into()); } Expr::FnCall(_, _) if parent_chain_type == ChainType::Dot => { unreachable!("function call in dot chain should not be namespace-qualified") @@ -1468,14 +1471,19 @@ impl Engine { Expr::FnCall(x, _) if parent_chain_type == ChainType::Dot && x.namespace.is_none() => { - x.args + let mut arg_positions: StaticVec<_> = Default::default(); + + let arg_values = x + .args .iter() .map(|arg_expr| { + arg_positions.push(arg_expr.position()); self.eval_expr(scope, mods, state, lib, this_ptr, arg_expr, level) - .map(|v| (v.flatten(), arg_expr.position())) + .map(Dynamic::flatten) }) - .collect::, _>>()? - .into() + .collect::, _>>()?; + + (arg_values, arg_positions).into() } Expr::FnCall(_, _) if parent_chain_type == ChainType::Dot => { unreachable!("function call in dot chain should not be namespace-qualified") diff --git a/src/fn_call.rs b/src/fn_call.rs index c3ed8d30..f9ce5626 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -885,7 +885,7 @@ impl Engine { fn_name: &str, mut hash: FnHash, target: &mut crate::engine::Target, - call_args: &mut StaticVec<(Dynamic, Position)>, + (call_args, call_arg_positions): &mut (StaticVec, StaticVec), pos: Position, level: usize, ) -> Result<(Dynamic, bool), Box> { @@ -908,7 +908,7 @@ impl Engine { let mut curry = fn_ptr.curry().iter().cloned().collect::>(); let mut arg_values = curry .iter_mut() - .chain(call_args.iter_mut().map(|v| &mut v.0)) + .chain(call_args.iter_mut()) .collect::>(); let args = arg_values.as_mut(); @@ -919,10 +919,10 @@ impl Engine { } KEYWORD_FN_PTR_CALL => { if call_args.len() > 0 { - if !call_args[0].0.is::() { + if !call_args[0].is::() { return Err(self.make_type_mismatch_err::( self.map_type_name(obj.type_name()), - call_args[0].1, + call_arg_positions[0], )); } } else { @@ -933,7 +933,8 @@ impl Engine { } // FnPtr call on object - let fn_ptr = call_args.remove(0).0.cast::(); + let fn_ptr = call_args.remove(0).cast::(); + call_arg_positions.remove(0); // Redirect function name let fn_name = fn_ptr.fn_name(); let args_len = call_args.len() + fn_ptr.curry().len(); @@ -946,7 +947,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().map(|v| &mut v.0)) + .chain(call_args.iter_mut()) .collect::>(); let args = arg_values.as_mut(); @@ -976,7 +977,7 @@ impl Engine { .curry() .iter() .cloned() - .chain(call_args.iter_mut().map(|v| mem::take(v).0)) + .chain(call_args.iter_mut().map(|v| mem::take(v))) .collect(), ) } @@ -1008,7 +1009,10 @@ impl Engine { .iter() .cloned() .enumerate() - .for_each(|(i, v)| call_args.insert(i, (v, Position::NONE))); + .for_each(|(i, v)| { + call_args.insert(i, v); + call_arg_positions.insert(i, 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()), @@ -1020,7 +1024,7 @@ impl Engine { // Attached object pointer in front of the arguments let mut arg_values = once(obj) - .chain(call_args.iter_mut().map(|v| &mut v.0)) + .chain(call_args.iter_mut()) .collect::>(); let args = arg_values.as_mut();