Further simplify matches.

This commit is contained in:
Stephen Chung 2023-04-05 23:40:27 +08:00
parent df05f43460
commit 9de41e7559

View File

@ -344,8 +344,6 @@ impl Engine {
expr: &Expr, expr: &Expr,
new_val: Option<(Dynamic, &OpAssignment)>, new_val: Option<(Dynamic, &OpAssignment)>,
) -> RhaiResult { ) -> RhaiResult {
let chain_type = ChainType::from(expr);
let BinaryExpr { lhs, rhs } = match expr { let BinaryExpr { lhs, rhs } = match expr {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Expr::Index(x, ..) => &**x, Expr::Index(x, ..) => &**x,
@ -356,20 +354,22 @@ impl Engine {
let idx_values = &mut FnArgsVec::new_const(); let idx_values = &mut FnArgsVec::new_const();
match rhs { match (rhs, ChainType::from(expr)) {
// Short-circuit for simple property access: {expr}.prop // Short-circuit for simple property access: {expr}.prop
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::Property(..) if chain_type == ChainType::Dotting => (), (Expr::Property(..), ChainType::Dotting) => (),
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::Property(..) => unreachable!("unexpected Expr::Property for indexing"), (Expr::Property(..), ..) => {
unreachable!("unexpected Expr::Property for indexing")
}
// Short-circuit for indexing with literal: {expr}[1] // Short-circuit for indexing with literal: {expr}[1]
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
_ if chain_type == ChainType::Indexing && rhs.is_constant() => { (_, ChainType::Indexing) if rhs.is_constant() => {
idx_values.push(rhs.get_literal_value().unwrap()) idx_values.push(rhs.get_literal_value().unwrap())
} }
// Short-circuit for simple method call: {expr}.func() // Short-circuit for simple method call: {expr}.func()
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::MethodCall(x, ..) if chain_type == ChainType::Dotting && x.args.is_empty() => (), (Expr::MethodCall(x, ..), ChainType::Dotting) if x.args.is_empty() => (),
// All other patterns - evaluate the arguments chain // All other patterns - evaluate the arguments chain
_ => self.eval_dot_index_chain_arguments( _ => self.eval_dot_index_chain_arguments(
global, global,
@ -387,9 +387,9 @@ impl Engine {
#[cfg(not(feature = "debugging"))] #[cfg(not(feature = "debugging"))]
let scope2 = (); let scope2 = ();
match lhs { match (lhs, new_val) {
// id.??? or id[???] // id.??? or id[???]
Expr::Variable(.., var_pos) => { (Expr::Variable(.., var_pos), new_val) => {
self.track_operation(global, *var_pos)?; self.track_operation(global, *var_pos)?;
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
@ -402,9 +402,9 @@ impl Engine {
) )
} }
// {expr}.??? = ??? or {expr}[???] = ??? // {expr}.??? = ??? or {expr}[???] = ???
_ if new_val.is_some() => unreachable!("cannot assign to an expression"), (_, Some(..)) => unreachable!("cannot assign to an expression"),
// {expr}.??? or {expr}[???] // {expr}.??? or {expr}[???]
lhs_expr => { (lhs_expr, None) => {
let value = self let value = self
.eval_expr(global, caches, scope, this_ptr.as_deref_mut(), lhs_expr)? .eval_expr(global, caches, scope, this_ptr.as_deref_mut(), lhs_expr)?
.flatten(); .flatten();
@ -412,7 +412,7 @@ impl Engine {
self.eval_dot_index_chain_raw( self.eval_dot_index_chain_raw(
global, caches, scope2, this_ptr, lhs_expr, expr, obj_ptr, rhs, idx_values, global, caches, scope2, this_ptr, lhs_expr, expr, obj_ptr, rhs, idx_values,
new_val, None,
) )
} }
} }
@ -437,7 +437,7 @@ impl Engine {
(Expr::MethodCall(x, ..), ChainType::Dotting) => { (Expr::MethodCall(x, ..), ChainType::Dotting) => {
debug_assert!( debug_assert!(
!x.is_qualified(), !x.is_qualified(),
"function call in dot chain should not be namespace-qualified" "method call in dot chain should not be namespace-qualified"
); );
for expr in &x.args { for expr in &x.args {
@ -450,7 +450,7 @@ impl Engine {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
(Expr::Property(..), ChainType::Dotting) => (), (Expr::Property(..), ChainType::Dotting) => (),
(Expr::Index(x, ..), chain_type) | (Expr::Dot(x, ..), chain_type) (Expr::Index(x, ..) | Expr::Dot(x, ..), chain_type)
if !parent.options().contains(ASTFlags::BREAK) => if !parent.options().contains(ASTFlags::BREAK) =>
{ {
let BinaryExpr { lhs, rhs, .. } = &**x; let BinaryExpr { lhs, rhs, .. } = &**x;
@ -466,7 +466,7 @@ impl Engine {
(Expr::MethodCall(x, ..), ChainType::Dotting) => { (Expr::MethodCall(x, ..), ChainType::Dotting) => {
debug_assert!( debug_assert!(
!x.is_qualified(), !x.is_qualified(),
"function call in dot chain should not be namespace-qualified" "method call in dot chain should not be namespace-qualified"
); );
for expr in &x.args { for expr in &x.args {
@ -540,9 +540,9 @@ impl Engine {
let pos = rhs.start_position(); let pos = rhs.start_position();
match rhs { match (rhs, new_val) {
// xxx[idx].expr... | xxx[idx][expr]... // xxx[idx].expr... | xxx[idx][expr]...
Expr::Dot(x, ..) | Expr::Index(x, ..) (Expr::Dot(x, ..) | Expr::Index(x, ..), new_val)
if !parent.options().contains(ASTFlags::BREAK) => if !parent.options().contains(ASTFlags::BREAK) =>
{ {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
@ -589,11 +589,10 @@ impl Engine {
Ok(result) Ok(result)
} }
// xxx[rhs] op= new_val // xxx[rhs] op= new_val
_ if new_val.is_some() => { (_, Some((new_val, op_info))) => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
self.run_debugger(global, caches, scope, this_ptr, parent)?; self.run_debugger(global, caches, scope, this_ptr, parent)?;
let (new_val, op_info) = new_val.expect("`Some`");
let idx_val = &mut idx_values.pop().unwrap(); let idx_val = &mut idx_values.pop().unwrap();
let idx = &mut idx_val.clone(); let idx = &mut idx_val.clone();
@ -646,7 +645,7 @@ impl Engine {
Ok((Dynamic::UNIT, true)) Ok((Dynamic::UNIT, true))
} }
// xxx[rhs] // xxx[rhs]
_ => { (_, None) => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
self.run_debugger(global, caches, scope, this_ptr, parent)?; self.run_debugger(global, caches, scope, this_ptr, parent)?;
@ -667,9 +666,18 @@ impl Engine {
return Ok((Dynamic::UNIT, false)); return Ok((Dynamic::UNIT, false));
} }
match rhs { match (rhs, new_val, target.is_map()) {
// xxx.fn_name(...) = ???
(Expr::MethodCall(..), Some(..), ..) => {
unreachable!("method call cannot be assigned to")
}
// xxx.fn_name(arg_expr_list) // xxx.fn_name(arg_expr_list)
Expr::MethodCall(x, pos) if !x.is_qualified() && new_val.is_none() => { (Expr::MethodCall(x, pos), None, ..) => {
debug_assert!(
!x.is_qualified(),
"method call in dot chain should not be namespace-qualified"
);
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
let reset = let reset =
self.run_debugger_with_reset(global, caches, scope, this_ptr, rhs)?; self.run_debugger_with_reset(global, caches, scope, this_ptr, rhs)?;
@ -690,21 +698,12 @@ impl Engine {
global, caches, name, *hashes, target, call_args, arg1_pos, *pos, global, caches, name, *hashes, target, call_args, arg1_pos, *pos,
) )
} }
// xxx.fn_name(...) = ???
Expr::MethodCall(..) if new_val.is_some() => {
unreachable!("method call cannot be assigned to")
}
// xxx.module::fn_name(...) - syntax error
Expr::MethodCall(..) => {
unreachable!("function call in dot chain should not be namespace-qualified")
}
// {xxx:map}.id op= ??? // {xxx:map}.id op= ???
Expr::Property(x, pos) if new_val.is_some() && target.is_map() => { (Expr::Property(x, pos), Some((new_val, op_info)), true) => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
self.run_debugger(global, caches, scope, this_ptr, rhs)?; self.run_debugger(global, caches, scope, this_ptr, rhs)?;
let index = &mut x.2.clone().into(); let index = &mut x.2.clone().into();
let (new_val, op_info) = new_val.expect("`Some`");
{ {
let val_target = &mut self.get_indexed_mut( let val_target = &mut self.get_indexed_mut(
global, caches, target, index, *pos, op_pos, true, false, global, caches, target, index, *pos, op_pos, true, false,
@ -717,7 +716,7 @@ impl Engine {
Ok((Dynamic::UNIT, true)) Ok((Dynamic::UNIT, true))
} }
// {xxx:map}.id // {xxx:map}.id
Expr::Property(x, pos) if target.is_map() => { (Expr::Property(x, pos), None, true) => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
self.run_debugger(global, caches, scope, this_ptr, rhs)?; self.run_debugger(global, caches, scope, this_ptr, rhs)?;
@ -728,12 +727,11 @@ impl Engine {
Ok((val.take_or_clone(), false)) Ok((val.take_or_clone(), false))
} }
// xxx.id op= ??? // xxx.id op= ???
Expr::Property(x, pos) if new_val.is_some() => { (Expr::Property(x, pos), Some((mut new_val, op_info)), false) => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
self.run_debugger(global, caches, scope, this_ptr, rhs)?; self.run_debugger(global, caches, scope, this_ptr, rhs)?;
let ((getter, hash_get), (setter, hash_set), name) = &**x; let ((getter, hash_get), (setter, hash_set), name) = &**x;
let (mut new_val, op_info) = new_val.expect("`Some`");
if op_info.is_op_assignment() { if op_info.is_op_assignment() {
let args = &mut [target.as_mut()]; let args = &mut [target.as_mut()];
@ -793,7 +791,7 @@ impl Engine {
}) })
} }
// xxx.id // xxx.id
Expr::Property(x, pos) => { (Expr::Property(x, pos), None, false) => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
self.run_debugger(global, caches, scope, this_ptr, rhs)?; self.run_debugger(global, caches, scope, this_ptr, rhs)?;
@ -822,7 +820,7 @@ impl Engine {
) )
} }
// {xxx:map}.sub_lhs[expr] | {xxx:map}.sub_lhs.expr // {xxx:map}.sub_lhs[expr] | {xxx:map}.sub_lhs.expr
Expr::Index(x, ..) | Expr::Dot(x, ..) if target.is_map() => { (Expr::Index(x, ..) | Expr::Dot(x, ..), new_val, true) => {
let _node = &x.lhs; let _node = &x.lhs;
let mut _this_ptr = this_ptr; let mut _this_ptr = this_ptr;
let _tp = _this_ptr.as_deref_mut(); let _tp = _this_ptr.as_deref_mut();
@ -838,7 +836,12 @@ 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::MethodCall(ref x, pos) if !x.is_qualified() => { Expr::MethodCall(ref x, pos) => {
debug_assert!(
!x.is_qualified(),
"method call in dot chain should not be namespace-qualified"
);
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
let reset = self let reset = self
.run_debugger_with_reset(global, caches, scope, _tp, _node)?; .run_debugger_with_reset(global, caches, scope, _tp, _node)?;
@ -861,10 +864,6 @@ impl Engine {
.0 .0
.into() .into()
} }
// {xxx:map}.module::fn_name(...) - syntax error
Expr::MethodCall(..) => unreachable!(
"function call in dot chain should not be namespace-qualified"
),
// Others - syntax error // Others - syntax error
ref expr => unreachable!("invalid dot expression: {:?}", expr), ref expr => unreachable!("invalid dot expression: {:?}", expr),
}; };
@ -875,7 +874,7 @@ impl Engine {
) )
} }
// xxx.sub_lhs[expr] | xxx.sub_lhs.expr // xxx.sub_lhs[expr] | xxx.sub_lhs.expr
Expr::Index(x, ..) | Expr::Dot(x, ..) => { (Expr::Index(x, ..) | Expr::Dot(x, ..), new_val, ..) => {
let _node = &x.lhs; let _node = &x.lhs;
let mut _this_ptr = this_ptr; let mut _this_ptr = this_ptr;
let _tp = _this_ptr.as_deref_mut(); let _tp = _this_ptr.as_deref_mut();
@ -956,7 +955,12 @@ impl Engine {
Ok((result, may_be_changed)) Ok((result, may_be_changed))
} }
// 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::MethodCall(ref f, pos) if !f.is_qualified() => { Expr::MethodCall(ref f, pos) => {
debug_assert!(
!f.is_qualified(),
"method call in dot chain should not be namespace-qualified"
);
let val = { let val = {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
let reset = self.run_debugger_with_reset( let reset = self.run_debugger_with_reset(
@ -988,16 +992,12 @@ impl Engine {
idx_values, new_val, idx_values, new_val,
) )
} }
// xxx.module::fn_name(...) - syntax error
Expr::MethodCall(..) => unreachable!(
"function call in dot chain should not be namespace-qualified"
),
// Others - syntax error // Others - syntax error
ref expr => unreachable!("invalid dot expression: {:?}", expr), ref expr => unreachable!("invalid dot expression: {:?}", expr),
} }
} }
// Syntax error // Syntax error
expr => unreachable!("invalid chaining expression: {:?}", expr), (expr, ..) => unreachable!("invalid chaining expression: {:?}", expr),
} }
} }
} }