Refactor to do more pre-calculation work.
This commit is contained in:
parent
9f18d6519d
commit
d0a47d7f66
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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::<StaticVec<_>>()
|
||||
.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::<StaticVec<_>>()
|
||||
.join(Token::DoubleColon.literal_syntax()),
|
||||
.join(crate::engine::NAMESPACE_SEPARATOR),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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}"),
|
||||
|
@ -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::<Dynamic>().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),
|
||||
|
@ -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)
|
||||
)
|
||||
};
|
||||
|
@ -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]
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user