Refine ChainArgument.

This commit is contained in:
Stephen Chung 2021-06-30 10:13:45 +08:00
parent c87645ba77
commit fc0256aff9

View File

@ -274,50 +274,34 @@ enum ChainArgument {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Property(Position), Property(Position),
/// Arguments to a dot method call. /// Arguments to a dot method call.
/// Wrapped values are the arguments plus the [position][Position] of the first argument.
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
MethodCallArgs(StaticVec<Dynamic>, Position), MethodCallArgs(StaticVec<Dynamic>, Position),
/// Index value. /// Index value and [position][Position].
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
IndexValue(Dynamic, Position), IndexValue(Dynamic, Position),
} }
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
impl ChainArgument { impl ChainArgument {
/// Return the `Dynamic` value. /// Return the index value.
///
/// # Panics
///
/// Panics if not `ChainArgument::IndexValue`.
#[inline(always)] #[inline(always)]
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
#[must_use] #[must_use]
pub fn as_index_value(self) -> Dynamic { pub fn as_index_value(self) -> Option<Dynamic> {
match self { match self {
#[cfg(not(feature = "no_object"))] Self::IndexValue(value, _) => Some(value),
Self::Property(_) | Self::MethodCallArgs(_, _) => { _ => None,
panic!("expecting ChainArgument::IndexValue")
}
Self::IndexValue(value, _) => value,
} }
} }
/// Return the `StaticVec<Dynamic>` value. /// Return the list of method call arguments.
///
/// # Panics
///
/// Panics if not `ChainArgument::MethodCallArgs`.
#[inline(always)] #[inline(always)]
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[must_use] #[must_use]
pub fn as_fn_call_args(self) -> (StaticVec<Dynamic>, Position) { pub fn as_fn_call_args(self) -> Option<(StaticVec<Dynamic>, Position)> {
match self { match self {
Self::Property(_) => { Self::MethodCallArgs(values, pos) => Some((values, pos)),
panic!("expecting ChainArgument::MethodCallArgs") _ => None,
}
#[cfg(not(feature = "no_index"))]
Self::IndexValue(_, _) => {
panic!("expecting ChainArgument::MethodCallArgs")
}
Self::MethodCallArgs(values, pos) => (values, pos),
} }
} }
} }
@ -1208,12 +1192,14 @@ impl Engine {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
ChainType::Index => { ChainType::Index => {
let pos = rhs.position(); let pos = rhs.position();
let idx_val = idx_val
.as_index_value()
.expect("never fails because `chain_type` is `ChainType::Index`");
match rhs { match rhs {
// xxx[idx].expr... | xxx[idx][expr]... // xxx[idx].expr... | xxx[idx][expr]...
Expr::Dot(x, x_pos) | Expr::Index(x, x_pos) => { Expr::Dot(x, x_pos) | Expr::Index(x, x_pos) => {
let idx_pos = x.lhs.position(); let idx_pos = x.lhs.position();
let idx_val = idx_val.as_index_value();
let obj_ptr = &mut self.get_indexed_mut( let obj_ptr = &mut self.get_indexed_mut(
mods, state, lib, target, idx_val, idx_pos, false, true, level, mods, state, lib, target, idx_val, idx_pos, false, true, level,
)?; )?;
@ -1229,7 +1215,6 @@ impl Engine {
_ if new_val.is_some() => { _ if new_val.is_some() => {
let ((new_val, new_pos), (op_info, op_pos)) = let ((new_val, new_pos), (op_info, op_pos)) =
new_val.expect("never fails because `new_val` is `Some`"); new_val.expect("never fails because `new_val` is `Some`");
let idx_val = idx_val.as_index_value();
let mut idx_val_for_setter = idx_val.clone(); let mut idx_val_for_setter = idx_val.clone();
let try_setter = match self.get_indexed_mut( let try_setter = match self.get_indexed_mut(
@ -1271,13 +1256,9 @@ impl Engine {
Ok((Dynamic::UNIT, true)) Ok((Dynamic::UNIT, true))
} }
// xxx[rhs] // xxx[rhs]
_ => { _ => self
let idx_val = idx_val.as_index_value(); .get_indexed_mut(mods, state, lib, target, idx_val, pos, false, true, level)
self.get_indexed_mut( .map(|v| (v.take_or_clone(), false)),
mods, state, lib, target, idx_val, pos, false, true, level,
)
.map(|v| (v.take_or_clone(), false))
}
} }
} }
@ -1287,9 +1268,11 @@ impl Engine {
// xxx.fn_name(arg_expr_list) // xxx.fn_name(arg_expr_list)
Expr::FnCall(x, pos) if !x.is_qualified() && new_val.is_none() => { Expr::FnCall(x, pos) if !x.is_qualified() && new_val.is_none() => {
let FnCallExpr { name, hashes, .. } = x.as_ref(); let FnCallExpr { name, hashes, .. } = x.as_ref();
let args = &mut idx_val.as_fn_call_args(); let call_args = &mut idx_val
.as_fn_call_args()
.expect("never fails because `chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`");
self.make_method_call( self.make_method_call(
mods, state, lib, name, *hashes, target, args, *pos, level, mods, state, lib, name, *hashes, target, call_args, *pos, level,
) )
} }
// xxx.fn_name(...) = ??? // xxx.fn_name(...) = ???
@ -1450,9 +1433,11 @@ 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(ref x, pos) if !x.is_qualified() => { Expr::FnCall(ref x, pos) if !x.is_qualified() => {
let FnCallExpr { name, hashes, .. } = x.as_ref(); let FnCallExpr { name, hashes, .. } = x.as_ref();
let args = &mut idx_val.as_fn_call_args(); let call_args = &mut idx_val
.as_fn_call_args()
.expect("never fails because `chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`");
let (val, _) = self.make_method_call( let (val, _) = self.make_method_call(
mods, state, lib, name, *hashes, target, args, pos, level, mods, state, lib, name, *hashes, target, call_args, pos, level,
)?; )?;
val.into() val.into()
} }
@ -1569,7 +1554,9 @@ impl Engine {
Expr::FnCall(ref f, pos) if !f.is_qualified() => { Expr::FnCall(ref f, pos) if !f.is_qualified() => {
let FnCallExpr { name, hashes, .. } = f.as_ref(); let FnCallExpr { name, hashes, .. } = f.as_ref();
let rhs_chain = match_chain_type(rhs); let rhs_chain = match_chain_type(rhs);
let args = &mut idx_val.as_fn_call_args(); let args = &mut idx_val
.as_fn_call_args()
.expect("never fails because `chain_type` is `ChainType::Dot` with `Expr::FnCallExpr`");
let (mut val, _) = self.make_method_call( let (mut val, _) = self.make_method_call(
mods, state, lib, name, *hashes, target, args, pos, level, mods, state, lib, name, *hashes, target, args, pos, level,
)?; )?;
@ -1688,17 +1675,19 @@ impl Engine {
args, constants, .. args, constants, ..
} = x.as_ref(); } = x.as_ref();
let mut arg_values = StaticVec::with_capacity(args.len()); let mut arg_values = StaticVec::with_capacity(args.len());
let mut first_arg_pos = Position::NONE;
for index in 0..args.len() { for index in 0..args.len() {
let (value, _) = self.get_arg_value( let (value, pos) = self.get_arg_value(
scope, mods, state, lib, this_ptr, level, args, constants, index, scope, mods, state, lib, this_ptr, level, args, constants, index,
)?; )?;
arg_values.push(value.flatten()); arg_values.push(value.flatten());
if index == 0 {
first_arg_pos = pos
}
} }
let pos = x.args.get(0).map(Expr::position).unwrap_or_default(); idx_values.push((arg_values, first_arg_pos).into());
idx_values.push((arg_values, pos).into());
} }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::FnCall(_, _) if _parent_chain_type == ChainType::Dot => { Expr::FnCall(_, _) if _parent_chain_type == ChainType::Dot => {
@ -1730,17 +1719,19 @@ impl Engine {
args, constants, .. args, constants, ..
} = x.as_ref(); } = x.as_ref();
let mut arg_values = StaticVec::with_capacity(args.len()); let mut arg_values = StaticVec::with_capacity(args.len());
let mut first_arg_pos = Position::NONE;
for index in 0..args.len() { for index in 0..args.len() {
let (value, _) = self.get_arg_value( let (value, pos) = self.get_arg_value(
scope, mods, state, lib, this_ptr, level, args, constants, index, scope, mods, state, lib, this_ptr, level, args, constants, index,
)?; )?;
arg_values.push(value.flatten()); arg_values.push(value.flatten());
if index == 0 {
first_arg_pos = pos;
}
} }
let pos = x.args.get(0).map(Expr::position).unwrap_or_default(); (arg_values, first_arg_pos).into()
(arg_values, pos).into()
} }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::FnCall(_, _) if _parent_chain_type == ChainType::Dot => { Expr::FnCall(_, _) if _parent_chain_type == ChainType::Dot => {