Refactor to do more pre-calculation work.

This commit is contained in:
Stephen Chung 2023-02-12 21:50:32 +08:00
parent 9f18d6519d
commit d0a47d7f66
11 changed files with 65 additions and 36 deletions

View File

@ -729,7 +729,7 @@ impl Engine {
name: &str, name: &str,
module: SharedModule, module: SharedModule,
) { ) {
let separator = crate::tokenizer::Token::DoubleColon.literal_syntax(); let separator = crate::engine::NAMESPACE_SEPARATOR;
if name.contains(separator) { if name.contains(separator) {
let mut iter = name.splitn(2, separator); let mut iter = name.splitn(2, separator);

View File

@ -383,7 +383,7 @@ impl fmt::Debug for Expr {
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
if !x.1.is_empty() { 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(); let pos = x.1.position();
if !pos.is_none() { if !pos.is_none() {
display_pos = pos; display_pos = pos;

View File

@ -2,7 +2,6 @@
#![cfg(not(feature = "no_module"))] #![cfg(not(feature = "no_module"))]
use crate::ast::Ident; use crate::ast::Ident;
use crate::tokenizer::Token;
use crate::{Position, StaticVec}; use crate::{Position, StaticVec};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
@ -46,7 +45,7 @@ impl fmt::Debug for Namespace {
.iter() .iter()
.map(Ident::as_str) .map(Ident::as_str)
.collect::<StaticVec<_>>() .collect::<StaticVec<_>>()
.join(Token::DoubleColon.literal_syntax()), .join(crate::engine::NAMESPACE_SEPARATOR),
) )
} }
} }
@ -63,7 +62,7 @@ impl fmt::Display for Namespace {
.iter() .iter()
.map(Ident::as_str) .map(Ident::as_str)
.collect::<StaticVec<_>>() .collect::<StaticVec<_>>()
.join(Token::DoubleColon.literal_syntax()), .join(crate::engine::NAMESPACE_SEPARATOR),
) )
} }
} }

View File

@ -1,7 +1,7 @@
//! Module defining script statements. //! Module defining script statements.
use super::{ASTFlags, ASTNode, BinaryExpr, Expr, FnCallExpr, Ident}; 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::func::StraightHashMap;
use crate::tokenizer::Token; use crate::tokenizer::Token;
use crate::types::Span; use crate::types::Span;
@ -29,8 +29,12 @@ pub struct OpAssignment {
hash_op: u64, hash_op: u64,
/// Op-assignment operator. /// Op-assignment operator.
op_assign: Token, op_assign: Token,
/// Syntax of op-assignment operator.
op_assign_syntax: &'static str,
/// Underlying operator. /// Underlying operator.
op: Token, op: Token,
/// Syntax of underlying operator.
op_syntax: &'static str,
/// [Position] of the op-assignment operator. /// [Position] of the op-assignment operator.
pos: Position, pos: Position,
} }
@ -44,7 +48,9 @@ impl OpAssignment {
hash_op_assign: 0, hash_op_assign: 0,
hash_op: 0, hash_op: 0,
op_assign: Token::Equals, op_assign: Token::Equals,
op_assign_syntax: OP_EQUALS,
op: Token::Equals, op: Token::Equals,
op_syntax: OP_EQUALS,
pos, pos,
} }
} }
@ -56,17 +62,28 @@ impl OpAssignment {
} }
/// Get information if this [`OpAssignment`] is an op-assignment. /// 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_assign`: Hash of the op-assignment call.
/// * `hash_op`: Hash of the underlying operator call (for fallback). /// * `hash_op`: Hash of the underlying operator call (for fallback).
/// * `op_assign`: Op-assignment operator. /// * `op_assign`: Op-assignment operator.
/// * `op_assign_syntax`: Syntax of op-assignment operator.
/// * `op`: Underlying operator. /// * `op`: Underlying operator.
/// * `op_syntax`: Syntax of underlying operator.
#[must_use] #[must_use]
#[inline] #[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() { 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 { } else {
None None
} }
@ -99,11 +116,16 @@ impl OpAssignment {
.get_base_op_from_assignment() .get_base_op_from_assignment()
.expect("op-assignment operator"); .expect("op-assignment operator");
let op_assign_syntax = op_assign.literal_syntax();
let op_syntax = op.literal_syntax();
Self { Self {
hash_op_assign: calc_fn_hash(None, op_assign.literal_syntax(), 2), hash_op_assign: calc_fn_hash(None, op_assign_syntax, 2),
hash_op: calc_fn_hash(None, op.literal_syntax(), 2), hash_op: calc_fn_hash(None, op_syntax, 2),
op_assign, op_assign,
op_assign_syntax,
op, op,
op_syntax,
pos, pos,
} }
} }
@ -139,7 +161,9 @@ impl fmt::Debug for OpAssignment {
.field("hash_op_assign", &self.hash_op_assign) .field("hash_op_assign", &self.hash_op_assign)
.field("hash_op", &self.hash_op) .field("hash_op", &self.hash_op)
.field("op_assign", &self.op_assign) .field("op_assign", &self.op_assign)
.field("op_assign_syntax", &self.op_assign_syntax)
.field("op", &self.op) .field("op", &self.op)
.field("op_syntax", &self.op_syntax)
.field("pos", &self.pos) .field("pos", &self.pos)
.finish() .finish()
} else { } else {

View File

@ -57,12 +57,19 @@ pub const OP_EQUALS: &str = Token::EqualsTo.literal_syntax();
/// The `in` operator is implemented as a call to this function. /// The `in` operator is implemented as a call to this function.
pub const OP_CONTAINS: &str = "contains"; pub const OP_CONTAINS: &str = "contains";
/// Standard not operator.
pub const OP_NOT: &str = Token::Bang.literal_syntax();
/// Standard exclusive range operator. /// Standard exclusive range operator.
pub const OP_EXCLUSIVE_RANGE: &str = Token::ExclusiveRange.literal_syntax(); pub const OP_EXCLUSIVE_RANGE: &str = Token::ExclusiveRange.literal_syntax();
/// Standard inclusive range operator. /// Standard inclusive range operator.
pub const OP_INCLUSIVE_RANGE: &str = Token::InclusiveRange.literal_syntax(); 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. /// Rhai main scripting engine.
/// ///
/// # Thread Safety /// # Thread Safety

View File

@ -74,7 +74,7 @@ impl Engine {
if let Some(module) = self.search_imports(global, ns) { if let Some(module) = self.search_imports(global, ns) {
return module.get_qualified_var(*hash_var).map_or_else( 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( Err(ERR::ErrorVariableNotFound(
format!("{ns}{sep}{var_name}"), 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( return Err(ERR::ErrorVariableNotFound(
format!("{ns}{sep}{var_name}"), format!("{ns}{sep}{var_name}"),

View File

@ -127,21 +127,20 @@ impl Engine {
let pos = op_info.position(); 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::<Dynamic>().unwrap(); let mut lock_guard = target.write_lock::<Dynamic>().unwrap();
let args = &mut [&mut *lock_guard, &mut new_val]; let args = &mut [&mut *lock_guard, &mut new_val];
if self.fast_operators() { if self.fast_operators() {
if let Some((func, need_context)) = 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 // Built-in found
auto_restore! { let orig_level = global.level; global.level += 1 } auto_restore! { let orig_level = global.level; global.level += 1 }
let context = if need_context { let context = if need_context {
let op = op_assign.literal_syntax();
let source = global.source(); let source = global.source();
Some((self, op, source, &*global, pos).into()) Some((self, op_x_str, source, &*global, pos).into())
} else { } else {
None None
}; };
@ -149,20 +148,17 @@ impl Engine {
} }
} }
let token = Some(op_assign); let opx = Some(op_x);
let op_assign = op_assign.literal_syntax();
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(_) => (), 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` // Expand to `var = var op rhs`
let token = Some(op); let op = Some(op);
let op = op.literal_syntax();
*args[0] = self *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; .0;
} }
Err(err) => return Err(err), Err(err) => return Err(err),

View File

@ -1491,7 +1491,7 @@ impl Engine {
} else { } else {
format!( format!(
"{namespace}{}{}", "{namespace}{}{}",
crate::tokenizer::Token::DoubleColon.literal_syntax(), crate::engine::NAMESPACE_SEPARATOR,
self.gen_fn_call_signature(fn_name, args) self.gen_fn_call_signature(fn_name, args)
) )
}; };

View File

@ -5,7 +5,9 @@ use crate::ast::{
ASTFlags, Expr, FlowControl, OpAssignment, Stmt, StmtBlock, StmtBlockContainer, ASTFlags, Expr, FlowControl, OpAssignment, Stmt, StmtBlock, StmtBlockContainer,
SwitchCasesCollection, 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::eval::{Caches, GlobalRuntimeState};
use crate::func::builtin::get_builtin_binary_op_fn; use crate::func::builtin::get_builtin_binary_op_fn;
use crate::func::hashing::get_hasher; use crate::func::hashing::get_hasher;
@ -25,9 +27,6 @@ use std::{
mem, mem,
}; };
/// Standard not operator.
const OP_NOT: &str = Token::Bang.literal_syntax();
/// Level of optimization performed. /// Level of optimization performed.
#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)] #[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)]
#[non_exhaustive] #[non_exhaustive]

View File

@ -287,7 +287,8 @@ fn collect_fn_metadata(
#[cfg(not(feature = "no_module"))] #[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. // Recursively scan modules for script-defined functions.
fn scan_module( fn scan_module(
@ -305,7 +306,7 @@ fn collect_fn_metadata(
use std::fmt::Write; use std::fmt::Write;
let mut ns = SmartString::new_const(); 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); scan_module(engine, list, &ns, m, filter);
} }
} }

View File

@ -7,7 +7,7 @@ use crate::ast::{
FnCallHashes, Ident, Namespace, OpAssignment, RangeCase, ScriptFnDef, Stmt, StmtBlock, FnCallHashes, Ident, Namespace, OpAssignment, RangeCase, ScriptFnDef, Stmt, StmtBlock,
StmtBlockContainer, SwitchCasesCollection, 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::eval::{Caches, GlobalRuntimeState};
use crate::func::{hashing::get_hasher, StraightHashMap}; use crate::func::{hashing::get_hasher, StraightHashMap};
use crate::tokenizer::{ use crate::tokenizer::{
@ -1299,6 +1299,10 @@ impl Engine {
} }
} }
expressions.shrink_to_fit();
cases.shrink_to_fit();
ranges.shrink_to_fit();
let cases = SwitchCasesCollection { let cases = SwitchCasesCollection {
expressions, expressions,
cases, cases,
@ -2418,14 +2422,13 @@ impl Engine {
fn_call fn_call
} else { } else {
// Put a `!` call in front // Put a `!` call in front
let op = Token::Bang.literal_syntax();
let mut args = FnArgsVec::new_const(); let mut args = FnArgsVec::new_const();
args.push(fn_call); args.push(fn_call);
let not_base = FnCallExpr { let not_base = FnCallExpr {
namespace: Namespace::NONE, namespace: Namespace::NONE,
name: state.get_interned_string(op), name: state.get_interned_string(OP_NOT),
hashes: FnCallHashes::from_native_only(calc_fn_hash(None, op, 1)), hashes: FnCallHashes::from_native_only(calc_fn_hash(None, OP_NOT, 1)),
args, args,
op_token: Some(Token::Bang), op_token: Some(Token::Bang),
capture_parent_scope: false, capture_parent_scope: false,