From ea3efe654cc9a41a3d206836d8f256e2ec175723 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 11 Jan 2023 11:42:46 +0800 Subject: [PATCH] Avoid unnecessarily creating Scope. --- src/api/compile.rs | 10 +++++++--- src/api/eval.rs | 4 ++-- src/api/formatting.rs | 5 ++--- src/api/json.rs | 5 ++--- src/api/optimize.rs | 2 +- src/api/run.rs | 2 +- src/eval/expr.rs | 2 +- src/func/call.rs | 2 +- src/optimizer.rs | 16 +++++++++------- src/parser.rs | 24 ++++++++++++++---------- 10 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/api/compile.rs b/src/api/compile.rs index 2b949efc..e222e403 100644 --- a/src/api/compile.rs +++ b/src/api/compile.rs @@ -202,7 +202,11 @@ impl Engine { scope: &Scope, scripts: impl AsRef<[S]>, ) -> ParseResult { - self.compile_with_scope_and_optimization_level(scope, scripts, self.optimization_level) + self.compile_with_scope_and_optimization_level( + Some(scope), + scripts, + self.optimization_level, + ) } /// Join a list of strings and compile into an [`AST`] using own scope at a specific optimization level. /// @@ -214,7 +218,7 @@ impl Engine { #[inline] pub(crate) fn compile_with_scope_and_optimization_level>( &self, - scope: &Scope, + scope: Option<&Scope>, scripts: impl AsRef<[S]>, optimization_level: OptimizationLevel, ) -> ParseResult { @@ -291,7 +295,7 @@ impl Engine { let scripts = [script]; let (stream, t) = self.lex_raw(&scripts, self.token_mapper.as_deref()); let interned_strings = &mut *locked_write(&self.interned_strings); - let state = &mut ParseState::new(scope, interned_strings, t); + let state = &mut ParseState::new(Some(scope), interned_strings, t); self.parse_global_expr(stream.peekable(), state, |_| {}, self.optimization_level) } } diff --git a/src/api/eval.rs b/src/api/eval.rs index d08915c4..c9fa2503 100644 --- a/src/api/eval.rs +++ b/src/api/eval.rs @@ -69,7 +69,7 @@ impl Engine { script: &str, ) -> RhaiResultOf { let ast = self.compile_with_scope_and_optimization_level( - scope, + Some(scope), [script], self.optimization_level, )?; @@ -123,7 +123,7 @@ impl Engine { let (stream, tc) = self.lex_raw(&scripts, self.token_mapper.as_deref()); - let state = &mut ParseState::new(scope, interned_strings, tc); + let state = &mut ParseState::new(Some(scope), interned_strings, tc); // No need to optimize a lone expression self.parse_global_expr( diff --git a/src/api/formatting.rs b/src/api/formatting.rs index d5f24576..9a342d10 100644 --- a/src/api/formatting.rs +++ b/src/api/formatting.rs @@ -4,7 +4,7 @@ use crate::parser::{ParseResult, ParseState}; use crate::types::StringsInterner; use crate::{ Engine, ExclusiveRange, FnPtr, ImmutableString, InclusiveRange, OptimizationLevel, Position, - RhaiError, Scope, SmartString, ERR, + RhaiError, SmartString, ERR, }; use std::any::type_name; #[cfg(feature = "no_std")] @@ -282,9 +282,8 @@ impl Engine { let (mut stream, tc) = self.lex_raw(&scripts, self.token_mapper.as_deref()); tc.borrow_mut().compressed = Some(String::new()); stream.state.last_token = Some(SmartString::new_const()); - let scope = Scope::new(); let mut interner = StringsInterner::new(); - let mut state = ParseState::new(&scope, &mut interner, tc); + let mut state = ParseState::new(None, &mut interner, tc); let mut _ast = self.parse( stream.peekable(), &mut state, diff --git a/src/api/json.rs b/src/api/json.rs index b62c1fb9..24ad805d 100644 --- a/src/api/json.rs +++ b/src/api/json.rs @@ -4,7 +4,7 @@ use crate::func::native::locked_write; use crate::parser::{ParseSettingFlags, ParseState}; use crate::tokenizer::Token; -use crate::{Engine, LexError, Map, OptimizationLevel, RhaiResultOf, Scope}; +use crate::{Engine, LexError, Map, OptimizationLevel, RhaiResultOf}; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -115,9 +115,8 @@ impl Engine { ); let ast = { - let scope = Scope::new(); let interned_strings = &mut *locked_write(&self.interned_strings); - let state = &mut ParseState::new(&scope, interned_strings, tokenizer_control); + let state = &mut ParseState::new(None, interned_strings, tokenizer_control); self.parse_global_expr( stream.peekable(), diff --git a/src/api/optimize.rs b/src/api/optimize.rs index 6ac76b22..92adec95 100644 --- a/src/api/optimize.rs +++ b/src/api/optimize.rs @@ -52,7 +52,7 @@ impl Engine { let mut ast = ast; let mut _new_ast = self.optimize_into_ast( - scope, + Some(scope), ast.take_statements(), #[cfg(not(feature = "no_function"))] ast.shared_lib() diff --git a/src/api/run.rs b/src/api/run.rs index e0f0b49c..77ca5360 100644 --- a/src/api/run.rs +++ b/src/api/run.rs @@ -60,7 +60,7 @@ impl Engine { let ast = { let (stream, tc) = self.lex_raw(&scripts, self.token_mapper.as_deref()); let interned_strings = &mut *locked_write(&self.interned_strings); - let state = &mut ParseState::new(scope, interned_strings, tc); + let state = &mut ParseState::new(Some(scope), interned_strings, tc); self.parse(stream.peekable(), state, self.optimization_level)? }; self.run_ast_with_scope(scope, &ast) diff --git a/src/eval/expr.rs b/src/eval/expr.rs index d99f7d41..75d9c0a5 100644 --- a/src/eval/expr.rs +++ b/src/eval/expr.rs @@ -298,7 +298,7 @@ impl Engine { let source = global.source(); let context = &(self, FUNC_TO_STRING, source, &*global, pos).into(); let display = print_with_func(FUNC_TO_STRING, context, item); - write!(concat, "{}", display).unwrap(); + write!(concat, "{display}").unwrap(); } #[cfg(not(feature = "unchecked"))] diff --git a/src/func/call.rs b/src/func/call.rs index f1f169c2..2532face 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -1518,7 +1518,7 @@ impl Engine { // Compile the script text // No optimizations because we only run it once let ast = self.compile_with_scope_and_optimization_level( - &Scope::new(), + None, [script], #[cfg(not(feature = "no_optimize"))] OptimizationLevel::None, diff --git a/src/optimizer.rs b/src/optimizer.rs index 15d11d2c..ea9c1fd7 100644 --- a/src/optimizer.rs +++ b/src/optimizer.rs @@ -1288,7 +1288,7 @@ impl Engine { fn optimize_top_level( &self, statements: StmtBlockContainer, - scope: &Scope, + scope: Option<&Scope>, lib: &[crate::SharedModule], optimization_level: OptimizationLevel, ) -> StmtBlockContainer { @@ -1309,11 +1309,13 @@ impl Engine { } // Add constants and variables from the scope - for (name, constant, value) in scope.iter() { - if constant { - state.push_var(name, AccessMode::ReadOnly, Some(value)); - } else { - state.push_var(name, AccessMode::ReadWrite, None); + if let Some(scope) = scope { + for (name, constant, value) in scope.iter() { + if constant { + state.push_var(name, AccessMode::ReadOnly, Some(value)); + } else { + state.push_var(name, AccessMode::ReadWrite, None); + } } } @@ -1323,7 +1325,7 @@ impl Engine { /// Optimize a collection of statements and functions into an [`AST`]. pub(crate) fn optimize_into_ast( &self, - scope: &Scope, + scope: Option<&Scope>, statements: StmtBlockContainer, #[cfg(not(feature = "no_function"))] functions: StaticVec< crate::Shared, diff --git a/src/parser.rs b/src/parser.rs index 6d58af31..60454e37 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -55,7 +55,7 @@ pub struct ParseState<'e, 's> { /// Strings interner. pub interned_strings: &'s mut StringsInterner, /// External [scope][Scope] with constants. - pub scope: &'e Scope<'e>, + pub external_constants: Option<&'e Scope<'e>>, /// Global runtime state. pub global: Option>, /// Encapsulates a local stack with variable names to simulate an actual runtime scope. @@ -87,7 +87,7 @@ impl fmt::Debug for ParseState<'_, '_> { f.field("tokenizer_control", &self.tokenizer_control) .field("interned_strings", &self.interned_strings) - .field("scope", &self.scope) + .field("external_constants_scope", &self.external_constants) .field("global", &self.global) .field("stack", &self.stack) .field("block_stack_len", &self.block_stack_len); @@ -109,7 +109,7 @@ impl<'e, 's> ParseState<'e, 's> { #[inline] #[must_use] pub fn new( - scope: &'e Scope, + external_constants: Option<&'e Scope>, interned_strings: &'s mut StringsInterner, tokenizer_control: TokenizerControl, ) -> Self { @@ -121,7 +121,7 @@ impl<'e, 's> ParseState<'e, 's> { #[cfg(not(feature = "no_closure"))] allow_capture: true, interned_strings, - scope, + external_constants, global: None, stack: None, block_stack_len: 0, @@ -1416,7 +1416,7 @@ impl Engine { // Build new parse state let new_interner = &mut StringsInterner::new(); let new_state = &mut ParseState::new( - state.scope, + state.external_constants, new_interner, state.tokenizer_control.clone(), ); @@ -1476,7 +1476,9 @@ impl Engine { && index.is_none() && !settings.has_flag(ParseSettingFlags::CLOSURE_SCOPE) && settings.has_option(LangOptions::STRICT_VAR) - && !state.scope.contains(name) + && !state + .external_constants + .map_or(false, |scope| scope.contains(name)) { // If the parent scope is not inside another capturing closure // then we can conclude that the captured variable doesn't exist. @@ -1624,7 +1626,9 @@ impl Engine { && !is_func && index.is_none() && settings.has_option(LangOptions::STRICT_VAR) - && !state.scope.contains(&s) + && !state + .external_constants + .map_or(false, |scope| scope.contains(&s)) { return Err( PERR::VariableUndefined(s.to_string()).into_err(settings.pos) @@ -3298,7 +3302,7 @@ impl Engine { (Token::Fn, pos) => { // Build new parse state let new_state = &mut ParseState::new( - state.scope, + state.external_constants, state.interned_strings, state.tokenizer_control.clone(), ); @@ -3848,7 +3852,7 @@ impl Engine { #[cfg(not(feature = "no_optimize"))] return Ok(self.optimize_into_ast( - state.scope, + state.external_constants, statements, #[cfg(not(feature = "no_function"))] functions.into_iter().map(|(.., v)| v).collect(), @@ -3934,7 +3938,7 @@ impl Engine { #[cfg(not(feature = "no_optimize"))] return Ok(self.optimize_into_ast( - state.scope, + state.external_constants, statements, #[cfg(not(feature = "no_function"))] _lib,