From df05f434607f89c64d57e8cee3a918d5c8f7f007 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 5 Apr 2023 23:15:55 +0800 Subject: [PATCH] Simplify match. --- src/ast/expr.rs | 12 ++++---- src/ast/stmt.rs | 4 +-- src/defer.rs | 14 ++++----- src/eval/chaining.rs | 71 +++++++++++++++++--------------------------- src/eval/expr.rs | 19 ++++++------ 5 files changed, 53 insertions(+), 67 deletions(-) diff --git a/src/ast/expr.rs b/src/ast/expr.rs index 1896f0df..52d7ccd1 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -288,8 +288,8 @@ pub enum Expr { Unit(Position), /// Variable access - (optional long index, namespace, namespace hash, variable name), optional short index, position /// - /// The short index is [`u8`] which is used when the index is <= 255, which should be the vast - /// majority of cases (unless there are more than 255 variables defined!). + /// The short index is [`u8`] which is used when the index is <= 255, which should be + /// the vast majority of cases (unless there are more than 255 variables defined!). /// This is to avoid reading a pointer redirection during each variable access. Variable( Box<(Option, Namespace, u64, ImmutableString)>, @@ -315,15 +315,15 @@ pub enum Expr { /// /// ### Flags /// - /// [`NEGATED`][ASTFlags::NEGATED] = `?.` (`.` if unset) - /// [`BREAK`][ASTFlags::BREAK] = terminate the chain (recurse into the chain if unset) + /// * [`NEGATED`][ASTFlags::NEGATED] = `?.` (`.` if unset) + /// * [`BREAK`][ASTFlags::BREAK] = terminate the chain (recurse into the chain if unset) Dot(Box, ASTFlags, Position), /// lhs `[` rhs `]` /// /// ### Flags /// - /// [`NEGATED`][ASTFlags::NEGATED] = `?[` ... `]` (`[` ... `]` if unset) - /// [`BREAK`][ASTFlags::BREAK] = terminate the chain (recurse into the chain if unset) + /// * [`NEGATED`][ASTFlags::NEGATED] = `?[` ... `]` (`[` ... `]` if unset) + /// * [`BREAK`][ASTFlags::BREAK] = terminate the chain (recurse into the chain if unset) Index(Box, ASTFlags, Position), /// lhs `&&` rhs And(Box, Position), diff --git a/src/ast/stmt.rs b/src/ast/stmt.rs index 8487c4fb..65634092 100644 --- a/src/ast/stmt.rs +++ b/src/ast/stmt.rs @@ -663,7 +663,7 @@ pub enum Stmt { /// /// ### Flags /// - /// * [`NONE`][ASTFlags::NONE] = `while` + /// * [`NONE`][ASTFlags::NONE] = `while` /// * [`NEGATED`][ASTFlags::NEGATED] = `until` Do(Box, ASTFlags, Position), /// `for` `(` id `,` counter `)` `in` expr `{` stmt `}` @@ -672,7 +672,7 @@ pub enum Stmt { /// /// ### Flags /// - /// * [`EXPORTED`][ASTFlags::EXPORTED] = `export` + /// * [`EXPORTED`][ASTFlags::EXPORTED] = `export` /// * [`CONSTANT`][ASTFlags::CONSTANT] = `const` Var(Box<(Ident, Expr, Option)>, ASTFlags, Position), /// expr op`=` expr diff --git a/src/defer.rs b/src/defer.rs index f3947430..4bf0ff21 100644 --- a/src/defer.rs +++ b/src/defer.rs @@ -65,8 +65,8 @@ macro_rules! defer { /// Run custom restoration logic upon the end of scope. #[must_use] pub struct Deferred<'a, T: ?Sized, R: FnOnce(&mut T)> { - value: &'a mut T, - restore: Option, + lock: &'a mut T, + defer: Option, } impl<'a, T: ?Sized, R: FnOnce(&mut T)> Deferred<'a, T, R> { @@ -78,8 +78,8 @@ impl<'a, T: ?Sized, R: FnOnce(&mut T)> Deferred<'a, T, R> { #[inline(always)] pub fn lock(value: &'a mut T, restore: R) -> Self { Self { - value, - restore: Some(restore), + lock: value, + defer: Some(restore), } } } @@ -87,7 +87,7 @@ impl<'a, T: ?Sized, R: FnOnce(&mut T)> Deferred<'a, T, R> { impl<'a, T: ?Sized, R: FnOnce(&mut T)> Drop for Deferred<'a, T, R> { #[inline(always)] fn drop(&mut self) { - self.restore.take().unwrap()(self.value); + self.defer.take().unwrap()(self.lock); } } @@ -96,13 +96,13 @@ impl<'a, T: ?Sized, R: FnOnce(&mut T)> Deref for Deferred<'a, T, R> { #[inline(always)] fn deref(&self) -> &Self::Target { - self.value + self.lock } } impl<'a, T: ?Sized, R: FnOnce(&mut T)> DerefMut for Deferred<'a, T, R> { #[inline(always)] fn deref_mut(&mut self) -> &mut Self::Target { - self.value + self.lock } } diff --git a/src/eval/chaining.rs b/src/eval/chaining.rs index 43570317..13e1433c 100644 --- a/src/eval/chaining.rs +++ b/src/eval/chaining.rs @@ -362,21 +362,14 @@ impl Engine { Expr::Property(..) if chain_type == ChainType::Dotting => (), #[cfg(not(feature = "no_object"))] Expr::Property(..) => unreachable!("unexpected Expr::Property for indexing"), - // Short-circuit for simple method call: {expr}.func() - #[cfg(not(feature = "no_object"))] - Expr::FnCall(x, ..) if chain_type == ChainType::Dotting && x.args.is_empty() => (), - // Short-circuit for method call with all literal arguments: {expr}.func(1, 2, 3) - #[cfg(not(feature = "no_object"))] - Expr::FnCall(x, ..) - if chain_type == ChainType::Dotting && x.args.iter().all(Expr::is_constant) => - { - idx_values.extend(x.args.iter().map(|expr| expr.get_literal_value().unwrap())) - } // Short-circuit for indexing with literal: {expr}[1] #[cfg(not(feature = "no_index"))] _ if chain_type == ChainType::Indexing && rhs.is_constant() => { idx_values.push(rhs.get_literal_value().unwrap()) } + // Short-circuit for simple method call: {expr}.func() + #[cfg(not(feature = "no_object"))] + Expr::MethodCall(x, ..) if chain_type == ChainType::Dotting && x.args.is_empty() => (), // All other patterns - evaluate the arguments chain _ => self.eval_dot_index_chain_arguments( global, @@ -439,27 +432,25 @@ impl Engine { ) -> RhaiResultOf<()> { self.track_operation(global, expr.position())?; - let chain_type = ChainType::from(parent); - - match expr { + match (expr, ChainType::from(parent)) { #[cfg(not(feature = "no_object"))] - Expr::MethodCall(x, ..) if chain_type == ChainType::Dotting && !x.is_qualified() => { + (Expr::MethodCall(x, ..), ChainType::Dotting) => { + debug_assert!( + !x.is_qualified(), + "function call in dot chain should not be namespace-qualified" + ); + for expr in &x.args { let arg_value = self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)?; idx_values.push(arg_value.0.flatten()); } } - #[cfg(not(feature = "no_object"))] - Expr::MethodCall(..) if chain_type == ChainType::Dotting => { - unreachable!("function call in dot chain should not be namespace-qualified") - } #[cfg(not(feature = "no_object"))] - Expr::Property(..) if chain_type == ChainType::Dotting => (), - Expr::Property(..) => unreachable!("unexpected Expr::Property for indexing"), + (Expr::Property(..), ChainType::Dotting) => (), - Expr::Index(x, ..) | Expr::Dot(x, ..) + (Expr::Index(x, ..), chain_type) | (Expr::Dot(x, ..), chain_type) if !parent.options().contains(ASTFlags::BREAK) => { let BinaryExpr { lhs, rhs, .. } = &**x; @@ -467,37 +458,34 @@ impl Engine { let mut _arg_values = FnArgsVec::new_const(); // Evaluate in left-to-right order - match lhs { + match (lhs, chain_type) { #[cfg(not(feature = "no_object"))] - Expr::Property(..) if chain_type == ChainType::Dotting => (), - Expr::Property(..) => unreachable!("unexpected Expr::Property for indexing"), + (Expr::Property(..), ChainType::Dotting) => (), #[cfg(not(feature = "no_object"))] - Expr::MethodCall(x, ..) - if chain_type == ChainType::Dotting && !x.is_qualified() => - { + (Expr::MethodCall(x, ..), ChainType::Dotting) => { + debug_assert!( + !x.is_qualified(), + "function call in dot chain should not be namespace-qualified" + ); + for expr in &x.args { let tp = this_ptr.as_deref_mut(); let arg_value = self.get_arg_value(global, caches, scope, tp, expr)?; _arg_values.push(arg_value.0.flatten()); } } - #[cfg(not(feature = "no_object"))] - Expr::MethodCall(..) if chain_type == ChainType::Dotting => { - unreachable!("function call in dot chain should not be namespace-qualified") - } - #[cfg(not(feature = "no_object"))] - expr if chain_type == ChainType::Dotting => { - unreachable!("invalid dot expression: {:?}", expr); - } #[cfg(not(feature = "no_index"))] - _ if chain_type == ChainType::Indexing => { + (_, ChainType::Indexing) => { _arg_values.push( self.eval_expr(global, caches, scope, this_ptr.as_deref_mut(), lhs)? .flatten(), ); } - expr => unreachable!("unknown chained expression: {:?}", expr), + #[allow(unreachable_patterns)] + (expr, chain_type) => { + unreachable!("unknown {:?} expression: {:?}", chain_type, expr) + } } // Push in reverse order @@ -508,16 +496,13 @@ impl Engine { idx_values.extend(_arg_values); } - #[cfg(not(feature = "no_object"))] - _ if chain_type == ChainType::Dotting => { - unreachable!("invalid dot expression: {:?}", expr); - } #[cfg(not(feature = "no_index"))] - _ if chain_type == ChainType::Indexing => idx_values.push( + (_, ChainType::Indexing) => idx_values.push( self.eval_expr(global, caches, scope, this_ptr, expr)? .flatten(), ), - _ => unreachable!("unknown chained expression: {:?}", expr), + #[allow(unreachable_patterns)] + (expr, chain_type) => unreachable!("unknown {:?} expression: {:?}", chain_type, expr), } Ok(()) diff --git a/src/eval/expr.rs b/src/eval/expr.rs index f8af1f35..f1555a3d 100644 --- a/src/eval/expr.rs +++ b/src/eval/expr.rs @@ -259,17 +259,18 @@ impl Engine { self.eval_fn_call_expr(global, caches, scope, this_ptr, x, *pos) } - Expr::Variable(x, index, var_pos) => { - if index.is_none() && x.0.is_none() && x.3 == KEYWORD_THIS { - this_ptr - .ok_or_else(|| ERR::ErrorUnboundThis(*var_pos).into()) - .cloned() - } else { - self.search_namespace(global, caches, scope, this_ptr, expr) - .map(Target::take_or_clone) - } + Expr::Variable(x, index, var_pos) + if index.is_none() && x.0.is_none() && x.3 == KEYWORD_THIS => + { + this_ptr + .ok_or_else(|| ERR::ErrorUnboundThis(*var_pos).into()) + .cloned() } + Expr::Variable(..) => self + .search_namespace(global, caches, scope, this_ptr, expr) + .map(Target::take_or_clone), + Expr::InterpolatedString(x, _) => { let mut concat = SmartString::new_const();