From d0a47d7f664ac9f49fac15d4c0699299de85bd2c Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 12 Feb 2023 21:50:32 +0800 Subject: [PATCH] Refactor to do more pre-calculation work. --- src/api/register.rs | 2 +- src/ast/expr.rs | 2 +- src/ast/namespace.rs | 5 ++--- src/ast/stmt.rs | 36 ++++++++++++++++++++++++++++++------ src/engine.rs | 7 +++++++ src/eval/expr.rs | 4 ++-- src/eval/stmt.rs | 20 ++++++++------------ src/func/call.rs | 2 +- src/optimizer.rs | 7 +++---- src/packages/lang_core.rs | 5 +++-- src/parser.rs | 11 +++++++---- 11 files changed, 65 insertions(+), 36 deletions(-) diff --git a/src/api/register.rs b/src/api/register.rs index 203740a0..a2d26944 100644 --- a/src/api/register.rs +++ b/src/api/register.rs @@ -729,7 +729,7 @@ impl Engine { name: &str, module: SharedModule, ) { - let separator = crate::tokenizer::Token::DoubleColon.literal_syntax(); + let separator = crate::engine::NAMESPACE_SEPARATOR; if name.contains(separator) { let mut iter = name.splitn(2, separator); diff --git a/src/ast/expr.rs b/src/ast/expr.rs index 586d5815..0152b72a 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -383,7 +383,7 @@ impl fmt::Debug for Expr { #[cfg(not(feature = "no_module"))] if !x.1.is_empty() { - write!(f, "{}{}", x.1, Token::DoubleColon.literal_syntax())?; + write!(f, "{}{}", x.1, crate::engine::NAMESPACE_SEPARATOR)?; let pos = x.1.position(); if !pos.is_none() { display_pos = pos; diff --git a/src/ast/namespace.rs b/src/ast/namespace.rs index 2888b25e..c6cd91e9 100644 --- a/src/ast/namespace.rs +++ b/src/ast/namespace.rs @@ -2,7 +2,6 @@ #![cfg(not(feature = "no_module"))] use crate::ast::Ident; -use crate::tokenizer::Token; use crate::{Position, StaticVec}; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -46,7 +45,7 @@ impl fmt::Debug for Namespace { .iter() .map(Ident::as_str) .collect::>() - .join(Token::DoubleColon.literal_syntax()), + .join(crate::engine::NAMESPACE_SEPARATOR), ) } } @@ -63,7 +62,7 @@ impl fmt::Display for Namespace { .iter() .map(Ident::as_str) .collect::>() - .join(Token::DoubleColon.literal_syntax()), + .join(crate::engine::NAMESPACE_SEPARATOR), ) } } diff --git a/src/ast/stmt.rs b/src/ast/stmt.rs index 7110fd1b..cd26df7f 100644 --- a/src/ast/stmt.rs +++ b/src/ast/stmt.rs @@ -1,7 +1,7 @@ //! Module defining script statements. use super::{ASTFlags, ASTNode, BinaryExpr, Expr, FnCallExpr, Ident}; -use crate::engine::KEYWORD_EVAL; +use crate::engine::{KEYWORD_EVAL, OP_EQUALS}; use crate::func::StraightHashMap; use crate::tokenizer::Token; use crate::types::Span; @@ -29,8 +29,12 @@ pub struct OpAssignment { hash_op: u64, /// Op-assignment operator. op_assign: Token, + /// Syntax of op-assignment operator. + op_assign_syntax: &'static str, /// Underlying operator. op: Token, + /// Syntax of underlying operator. + op_syntax: &'static str, /// [Position] of the op-assignment operator. pos: Position, } @@ -44,7 +48,9 @@ impl OpAssignment { hash_op_assign: 0, hash_op: 0, op_assign: Token::Equals, + op_assign_syntax: OP_EQUALS, op: Token::Equals, + op_syntax: OP_EQUALS, pos, } } @@ -56,17 +62,28 @@ impl OpAssignment { } /// Get information if this [`OpAssignment`] is an op-assignment. /// - /// Returns `( hash_op_assign, hash_op, op_assign, op )`: + /// Returns `( hash_op_assign, hash_op, op_assign, op_assign_syntax, op, op_syntax )`: /// /// * `hash_op_assign`: Hash of the op-assignment call. /// * `hash_op`: Hash of the underlying operator call (for fallback). /// * `op_assign`: Op-assignment operator. + /// * `op_assign_syntax`: Syntax of op-assignment operator. /// * `op`: Underlying operator. + /// * `op_syntax`: Syntax of underlying operator. #[must_use] #[inline] - pub fn get_op_assignment_info(&self) -> Option<(u64, u64, &Token, &Token)> { + pub fn get_op_assignment_info( + &self, + ) -> Option<(u64, u64, &Token, &'static str, &Token, &'static str)> { if self.is_op_assignment() { - Some((self.hash_op_assign, self.hash_op, &self.op_assign, &self.op)) + Some(( + self.hash_op_assign, + self.hash_op, + &self.op_assign, + self.op_assign_syntax, + &self.op, + self.op_syntax, + )) } else { None } @@ -99,11 +116,16 @@ impl OpAssignment { .get_base_op_from_assignment() .expect("op-assignment operator"); + let op_assign_syntax = op_assign.literal_syntax(); + let op_syntax = op.literal_syntax(); + Self { - hash_op_assign: calc_fn_hash(None, op_assign.literal_syntax(), 2), - hash_op: calc_fn_hash(None, op.literal_syntax(), 2), + hash_op_assign: calc_fn_hash(None, op_assign_syntax, 2), + hash_op: calc_fn_hash(None, op_syntax, 2), op_assign, + op_assign_syntax, op, + op_syntax, pos, } } @@ -139,7 +161,9 @@ impl fmt::Debug for OpAssignment { .field("hash_op_assign", &self.hash_op_assign) .field("hash_op", &self.hash_op) .field("op_assign", &self.op_assign) + .field("op_assign_syntax", &self.op_assign_syntax) .field("op", &self.op) + .field("op_syntax", &self.op_syntax) .field("pos", &self.pos) .finish() } else { diff --git a/src/engine.rs b/src/engine.rs index 3e07bda9..750b35f0 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -57,12 +57,19 @@ pub const OP_EQUALS: &str = Token::EqualsTo.literal_syntax(); /// The `in` operator is implemented as a call to this function. pub const OP_CONTAINS: &str = "contains"; +/// Standard not operator. +pub const OP_NOT: &str = Token::Bang.literal_syntax(); + /// Standard exclusive range operator. pub const OP_EXCLUSIVE_RANGE: &str = Token::ExclusiveRange.literal_syntax(); /// Standard inclusive range operator. pub const OP_INCLUSIVE_RANGE: &str = Token::InclusiveRange.literal_syntax(); +/// Separator for namespaces. +#[cfg(not(feature = "no_module"))] +pub const NAMESPACE_SEPARATOR: &str = Token::DoubleColon.literal_syntax(); + /// Rhai main scripting engine. /// /// # Thread Safety diff --git a/src/eval/expr.rs b/src/eval/expr.rs index 0f3125f4..0567e39e 100644 --- a/src/eval/expr.rs +++ b/src/eval/expr.rs @@ -74,7 +74,7 @@ impl Engine { if let Some(module) = self.search_imports(global, ns) { return module.get_qualified_var(*hash_var).map_or_else( || { - let sep = crate::tokenizer::Token::DoubleColon.literal_syntax(); + let sep = crate::engine::NAMESPACE_SEPARATOR; Err(ERR::ErrorVariableNotFound( format!("{ns}{sep}{var_name}"), @@ -104,7 +104,7 @@ impl Engine { } } - let sep = crate::tokenizer::Token::DoubleColon.literal_syntax(); + let sep = crate::engine::NAMESPACE_SEPARATOR; return Err(ERR::ErrorVariableNotFound( format!("{ns}{sep}{var_name}"), diff --git a/src/eval/stmt.rs b/src/eval/stmt.rs index 2fac1fe2..d6e5229e 100644 --- a/src/eval/stmt.rs +++ b/src/eval/stmt.rs @@ -127,21 +127,20 @@ impl Engine { let pos = op_info.position(); - if let Some((hash1, hash2, op_assign, op)) = op_info.get_op_assignment_info() { + if let Some((hash_x, hash, op_x, op_x_str, op, op_str)) = op_info.get_op_assignment_info() { let mut lock_guard = target.write_lock::().unwrap(); let args = &mut [&mut *lock_guard, &mut new_val]; if self.fast_operators() { if let Some((func, need_context)) = - get_builtin_op_assignment_fn(op_assign, args[0], args[1]) + get_builtin_op_assignment_fn(op_x, args[0], args[1]) { // Built-in found auto_restore! { let orig_level = global.level; global.level += 1 } let context = if need_context { - let op = op_assign.literal_syntax(); let source = global.source(); - Some((self, op, source, &*global, pos).into()) + Some((self, op_x_str, source, &*global, pos).into()) } else { None }; @@ -149,20 +148,17 @@ impl Engine { } } - let token = Some(op_assign); - let op_assign = op_assign.literal_syntax(); + let opx = Some(op_x); - match self.exec_native_fn_call(global, caches, op_assign, token, hash1, args, true, pos) - { + match self.exec_native_fn_call(global, caches, op_x_str, opx, hash_x, args, true, pos) { Ok(_) => (), - Err(err) if matches!(*err, ERR::ErrorFunctionNotFound(ref f, ..) if f.starts_with(op_assign)) => + Err(err) if matches!(*err, ERR::ErrorFunctionNotFound(ref f, ..) if f.starts_with(op_x_str)) => { // Expand to `var = var op rhs` - let token = Some(op); - let op = op.literal_syntax(); + let op = Some(op); *args[0] = self - .exec_native_fn_call(global, caches, op, token, hash2, args, true, pos)? + .exec_native_fn_call(global, caches, op_str, op, hash, args, true, pos)? .0; } Err(err) => return Err(err), diff --git a/src/func/call.rs b/src/func/call.rs index 2eb7ace7..2abda94b 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -1491,7 +1491,7 @@ impl Engine { } else { format!( "{namespace}{}{}", - crate::tokenizer::Token::DoubleColon.literal_syntax(), + crate::engine::NAMESPACE_SEPARATOR, self.gen_fn_call_signature(fn_name, args) ) }; diff --git a/src/optimizer.rs b/src/optimizer.rs index 6de5862f..d01f98c3 100644 --- a/src/optimizer.rs +++ b/src/optimizer.rs @@ -5,7 +5,9 @@ use crate::ast::{ ASTFlags, Expr, FlowControl, OpAssignment, Stmt, StmtBlock, StmtBlockContainer, SwitchCasesCollection, }; -use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF}; +use crate::engine::{ + KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF, OP_NOT, +}; use crate::eval::{Caches, GlobalRuntimeState}; use crate::func::builtin::get_builtin_binary_op_fn; use crate::func::hashing::get_hasher; @@ -25,9 +27,6 @@ use std::{ mem, }; -/// Standard not operator. -const OP_NOT: &str = Token::Bang.literal_syntax(); - /// Level of optimization performed. #[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)] #[non_exhaustive] diff --git a/src/packages/lang_core.rs b/src/packages/lang_core.rs index ce75f7ef..229113d3 100644 --- a/src/packages/lang_core.rs +++ b/src/packages/lang_core.rs @@ -287,7 +287,8 @@ fn collect_fn_metadata( #[cfg(not(feature = "no_module"))] { - use crate::{tokenizer::Token::DoubleColon, Shared, SmartString}; + use crate::engine::NAMESPACE_SEPARATOR; + use crate::{Shared, SmartString}; // Recursively scan modules for script-defined functions. fn scan_module( @@ -305,7 +306,7 @@ fn collect_fn_metadata( use std::fmt::Write; let mut ns = SmartString::new_const(); - write!(&mut ns, "{namespace}{}{name}", DoubleColon.literal_syntax()).unwrap(); + write!(&mut ns, "{namespace}{}{name}", NAMESPACE_SEPARATOR).unwrap(); scan_module(engine, list, &ns, m, filter); } } diff --git a/src/parser.rs b/src/parser.rs index 0f452d8c..ac296d15 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -7,7 +7,7 @@ use crate::ast::{ FnCallHashes, Ident, Namespace, OpAssignment, RangeCase, ScriptFnDef, Stmt, StmtBlock, StmtBlockContainer, SwitchCasesCollection, }; -use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS}; +use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS, OP_NOT}; use crate::eval::{Caches, GlobalRuntimeState}; use crate::func::{hashing::get_hasher, StraightHashMap}; use crate::tokenizer::{ @@ -1299,6 +1299,10 @@ impl Engine { } } + expressions.shrink_to_fit(); + cases.shrink_to_fit(); + ranges.shrink_to_fit(); + let cases = SwitchCasesCollection { expressions, cases, @@ -2418,14 +2422,13 @@ impl Engine { fn_call } else { // Put a `!` call in front - let op = Token::Bang.literal_syntax(); let mut args = FnArgsVec::new_const(); args.push(fn_call); let not_base = FnCallExpr { namespace: Namespace::NONE, - name: state.get_interned_string(op), - hashes: FnCallHashes::from_native_only(calc_fn_hash(None, op, 1)), + name: state.get_interned_string(OP_NOT), + hashes: FnCallHashes::from_native_only(calc_fn_hash(None, OP_NOT, 1)), args, op_token: Some(Token::Bang), capture_parent_scope: false,