Simplify match.

This commit is contained in:
Stephen Chung 2023-04-05 23:15:55 +08:00
parent 5eaa4c5240
commit df05f43460
5 changed files with 53 additions and 67 deletions

View File

@ -288,8 +288,8 @@ pub enum Expr {
Unit(Position), Unit(Position),
/// Variable access - (optional long index, namespace, namespace hash, variable name), optional short index, 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 /// The short index is [`u8`] which is used when the index is <= 255, which should be
/// majority of cases (unless there are more than 255 variables defined!). /// 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. /// This is to avoid reading a pointer redirection during each variable access.
Variable( Variable(
Box<(Option<NonZeroUsize>, Namespace, u64, ImmutableString)>, Box<(Option<NonZeroUsize>, Namespace, u64, ImmutableString)>,
@ -315,15 +315,15 @@ pub enum Expr {
/// ///
/// ### Flags /// ### Flags
/// ///
/// [`NEGATED`][ASTFlags::NEGATED] = `?.` (`.` if unset) /// * [`NEGATED`][ASTFlags::NEGATED] = `?.` (`.` if unset)
/// [`BREAK`][ASTFlags::BREAK] = terminate the chain (recurse into the chain if unset) /// * [`BREAK`][ASTFlags::BREAK] = terminate the chain (recurse into the chain if unset)
Dot(Box<BinaryExpr>, ASTFlags, Position), Dot(Box<BinaryExpr>, ASTFlags, Position),
/// lhs `[` rhs `]` /// lhs `[` rhs `]`
/// ///
/// ### Flags /// ### Flags
/// ///
/// [`NEGATED`][ASTFlags::NEGATED] = `?[` ... `]` (`[` ... `]` if unset) /// * [`NEGATED`][ASTFlags::NEGATED] = `?[` ... `]` (`[` ... `]` if unset)
/// [`BREAK`][ASTFlags::BREAK] = terminate the chain (recurse into the chain if unset) /// * [`BREAK`][ASTFlags::BREAK] = terminate the chain (recurse into the chain if unset)
Index(Box<BinaryExpr>, ASTFlags, Position), Index(Box<BinaryExpr>, ASTFlags, Position),
/// lhs `&&` rhs /// lhs `&&` rhs
And(Box<BinaryExpr>, Position), And(Box<BinaryExpr>, Position),

View File

@ -663,7 +663,7 @@ pub enum Stmt {
/// ///
/// ### Flags /// ### Flags
/// ///
/// * [`NONE`][ASTFlags::NONE] = `while` /// * [`NONE`][ASTFlags::NONE] = `while`
/// * [`NEGATED`][ASTFlags::NEGATED] = `until` /// * [`NEGATED`][ASTFlags::NEGATED] = `until`
Do(Box<FlowControl>, ASTFlags, Position), Do(Box<FlowControl>, ASTFlags, Position),
/// `for` `(` id `,` counter `)` `in` expr `{` stmt `}` /// `for` `(` id `,` counter `)` `in` expr `{` stmt `}`
@ -672,7 +672,7 @@ pub enum Stmt {
/// ///
/// ### Flags /// ### Flags
/// ///
/// * [`EXPORTED`][ASTFlags::EXPORTED] = `export` /// * [`EXPORTED`][ASTFlags::EXPORTED] = `export`
/// * [`CONSTANT`][ASTFlags::CONSTANT] = `const` /// * [`CONSTANT`][ASTFlags::CONSTANT] = `const`
Var(Box<(Ident, Expr, Option<NonZeroUsize>)>, ASTFlags, Position), Var(Box<(Ident, Expr, Option<NonZeroUsize>)>, ASTFlags, Position),
/// expr op`=` expr /// expr op`=` expr

View File

@ -65,8 +65,8 @@ macro_rules! defer {
/// Run custom restoration logic upon the end of scope. /// Run custom restoration logic upon the end of scope.
#[must_use] #[must_use]
pub struct Deferred<'a, T: ?Sized, R: FnOnce(&mut T)> { pub struct Deferred<'a, T: ?Sized, R: FnOnce(&mut T)> {
value: &'a mut T, lock: &'a mut T,
restore: Option<R>, defer: Option<R>,
} }
impl<'a, T: ?Sized, R: FnOnce(&mut T)> Deferred<'a, T, R> { 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)] #[inline(always)]
pub fn lock(value: &'a mut T, restore: R) -> Self { pub fn lock(value: &'a mut T, restore: R) -> Self {
Self { Self {
value, lock: value,
restore: Some(restore), 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> { impl<'a, T: ?Sized, R: FnOnce(&mut T)> Drop for Deferred<'a, T, R> {
#[inline(always)] #[inline(always)]
fn drop(&mut self) { 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)] #[inline(always)]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
self.value self.lock
} }
} }
impl<'a, T: ?Sized, R: FnOnce(&mut T)> DerefMut for Deferred<'a, T, R> { impl<'a, T: ?Sized, R: FnOnce(&mut T)> DerefMut for Deferred<'a, T, R> {
#[inline(always)] #[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
self.value self.lock
} }
} }

View File

@ -362,21 +362,14 @@ impl Engine {
Expr::Property(..) if chain_type == ChainType::Dotting => (), Expr::Property(..) if chain_type == 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 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] // 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() => { _ if chain_type == ChainType::Indexing && 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()
#[cfg(not(feature = "no_object"))]
Expr::MethodCall(x, ..) if chain_type == ChainType::Dotting && 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,
@ -439,27 +432,25 @@ impl Engine {
) -> RhaiResultOf<()> { ) -> RhaiResultOf<()> {
self.track_operation(global, expr.position())?; self.track_operation(global, expr.position())?;
let chain_type = ChainType::from(parent); match (expr, ChainType::from(parent)) {
match expr {
#[cfg(not(feature = "no_object"))] #[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 { for expr in &x.args {
let arg_value = let arg_value =
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)?; self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)?;
idx_values.push(arg_value.0.flatten()); 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"))] #[cfg(not(feature = "no_object"))]
Expr::Property(..) if chain_type == ChainType::Dotting => (), (Expr::Property(..), ChainType::Dotting) => (),
Expr::Property(..) => unreachable!("unexpected Expr::Property for indexing"),
Expr::Index(x, ..) | Expr::Dot(x, ..) (Expr::Index(x, ..), chain_type) | (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;
@ -467,37 +458,34 @@ impl Engine {
let mut _arg_values = FnArgsVec::new_const(); let mut _arg_values = FnArgsVec::new_const();
// Evaluate in left-to-right order // Evaluate in left-to-right order
match lhs { match (lhs, chain_type) {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::Property(..) if chain_type == ChainType::Dotting => (), (Expr::Property(..), ChainType::Dotting) => (),
Expr::Property(..) => unreachable!("unexpected Expr::Property for indexing"),
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::MethodCall(x, ..) (Expr::MethodCall(x, ..), ChainType::Dotting) => {
if chain_type == ChainType::Dotting && !x.is_qualified() => debug_assert!(
{ !x.is_qualified(),
"function call in dot chain should not be namespace-qualified"
);
for expr in &x.args { for expr in &x.args {
let tp = this_ptr.as_deref_mut(); let tp = this_ptr.as_deref_mut();
let arg_value = self.get_arg_value(global, caches, scope, tp, expr)?; let arg_value = self.get_arg_value(global, caches, scope, tp, expr)?;
_arg_values.push(arg_value.0.flatten()); _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"))] #[cfg(not(feature = "no_index"))]
_ if chain_type == ChainType::Indexing => { (_, ChainType::Indexing) => {
_arg_values.push( _arg_values.push(
self.eval_expr(global, caches, scope, this_ptr.as_deref_mut(), lhs)? self.eval_expr(global, caches, scope, this_ptr.as_deref_mut(), lhs)?
.flatten(), .flatten(),
); );
} }
expr => unreachable!("unknown chained expression: {:?}", expr), #[allow(unreachable_patterns)]
(expr, chain_type) => {
unreachable!("unknown {:?} expression: {:?}", chain_type, expr)
}
} }
// Push in reverse order // Push in reverse order
@ -508,16 +496,13 @@ impl Engine {
idx_values.extend(_arg_values); 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"))] #[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)? self.eval_expr(global, caches, scope, this_ptr, expr)?
.flatten(), .flatten(),
), ),
_ => unreachable!("unknown chained expression: {:?}", expr), #[allow(unreachable_patterns)]
(expr, chain_type) => unreachable!("unknown {:?} expression: {:?}", chain_type, expr),
} }
Ok(()) Ok(())

View File

@ -259,17 +259,18 @@ impl Engine {
self.eval_fn_call_expr(global, caches, scope, this_ptr, x, *pos) self.eval_fn_call_expr(global, caches, scope, this_ptr, x, *pos)
} }
Expr::Variable(x, index, var_pos) => { Expr::Variable(x, index, var_pos)
if index.is_none() && x.0.is_none() && x.3 == KEYWORD_THIS { if index.is_none() && x.0.is_none() && x.3 == KEYWORD_THIS =>
this_ptr {
.ok_or_else(|| ERR::ErrorUnboundThis(*var_pos).into()) this_ptr
.cloned() .ok_or_else(|| ERR::ErrorUnboundThis(*var_pos).into())
} else { .cloned()
self.search_namespace(global, caches, scope, this_ptr, expr)
.map(Target::take_or_clone)
}
} }
Expr::Variable(..) => self
.search_namespace(global, caches, scope, this_ptr, expr)
.map(Target::take_or_clone),
Expr::InterpolatedString(x, _) => { Expr::InterpolatedString(x, _) => {
let mut concat = SmartString::new_const(); let mut concat = SmartString::new_const();