From 68c0ee08c0e01ee661441b3bf19f6d8d1c5afbe0 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 7 Nov 2021 18:12:37 +0800 Subject: [PATCH] Reduce usage of Default::default() to make it easier to refactor. --- src/ast.rs | 30 ++++++---- src/bin/rhai-repl.rs | 8 +-- src/engine.rs | 40 +++++-------- src/engine_api.rs | 26 ++++----- src/fn_call.rs | 23 ++++---- src/fn_native.rs | 21 +++---- src/fn_ptr.rs | 2 +- src/fn_register.rs | 8 +-- src/module/mod.rs | 31 ++++------ src/module/resolvers/collection.rs | 3 +- src/module/resolvers/file.rs | 11 +--- src/module/resolvers/stat.rs | 4 +- src/optimize.rs | 20 ++++--- src/packages/iter_basic.rs | 4 +- src/packages/string_basic.rs | 4 +- src/parse.rs | 39 ++++++++----- src/scope.rs | 4 +- src/serde/de.rs | 2 +- src/serde/metadata.rs | 11 ++-- src/serde/ser.rs | 6 +- src/token.rs | 15 ++++- tests/closures.rs | 2 +- tests/custom_syntax.rs | 2 +- tests/expressions.rs | 2 +- tests/functions.rs | 91 ++++++++++++++++++++---------- tests/modules.rs | 4 +- 26 files changed, 224 insertions(+), 189 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 69c5d513..18aa6b7b 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -227,11 +227,11 @@ impl AST { /// Create an empty [`AST`]. #[inline] #[must_use] - pub(crate) fn empty() -> Self { + pub fn empty() -> Self { Self { source: None, - body: Default::default(), - functions: Default::default(), + body: StmtBlock::empty(), + functions: Module::new().into(), #[cfg(not(feature = "no_module"))] resolver: None, } @@ -399,11 +399,11 @@ impl AST { &self, filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool, ) -> Self { - let mut functions: Module = Default::default(); + let mut functions = Module::new(); functions.merge_filtered(&self.functions, &filter); Self { source: self.source.clone(), - body: Default::default(), + body: StmtBlock::empty(), functions: functions.into(), #[cfg(not(feature = "no_module"))] resolver: self.resolver.clone(), @@ -417,7 +417,7 @@ impl AST { Self { source: self.source.clone(), body: self.body.clone(), - functions: Default::default(), + functions: Module::new().into(), #[cfg(not(feature = "no_module"))] resolver: self.resolver.clone(), } @@ -599,7 +599,7 @@ impl AST { } (false, true) => body.clone(), (true, false) => other.body.clone(), - (true, true) => Default::default(), + (true, true) => StmtBlock::empty(), }; let source = other.source.clone().or_else(|| self.source.clone()); @@ -740,13 +740,13 @@ impl AST { #[cfg(not(feature = "no_function"))] #[inline(always)] pub fn clear_functions(&mut self) -> &mut Self { - self.functions = Default::default(); + self.functions = Module::new().into(); self } /// Clear all statements in the [`AST`], leaving only function definitions. #[inline(always)] pub fn clear_statements(&mut self) -> &mut Self { - self.body = Default::default(); + self.body = StmtBlock::empty(); self } /// Recursively walk the [`AST`], including function bodies (if any). @@ -755,7 +755,7 @@ impl AST { #[cfg(not(feature = "no_module"))] #[inline] pub(crate) fn walk(&self, on_node: &mut impl FnMut(&[ASTNode]) -> bool) -> bool { - let path = &mut Default::default(); + let path = &mut Vec::new(); for stmt in self.statements() { if !stmt.walk(path, on_node) { @@ -777,7 +777,7 @@ impl AST { #[cfg(feature = "internals")] #[inline] pub fn walk(&self, on_node: &mut impl FnMut(&[ASTNode]) -> bool) -> bool { - let path = &mut Default::default(); + let path = &mut Vec::new(); for stmt in self.statements() { if !stmt.walk(path, on_node) { @@ -899,6 +899,12 @@ impl StmtBlock { statements.shrink_to_fit(); Self(statements, pos) } + /// Create an empty [`StmtBlock`]. + #[inline(always)] + #[must_use] + pub fn empty() -> Self { + Default::default() + } /// Is this statements block empty? #[inline(always)] #[must_use] @@ -1205,7 +1211,7 @@ impl From for StmtBlock { fn from(stmt: Stmt) -> Self { match stmt { Stmt::Block(mut block, pos) => Self(block.iter_mut().map(mem::take).collect(), pos), - Stmt::Noop(pos) => Self(Default::default(), pos), + Stmt::Noop(pos) => Self(StaticVec::new(), pos), _ => { let pos = stmt.position(); Self(vec![stmt].into(), pos) diff --git a/src/bin/rhai-repl.rs b/src/bin/rhai-repl.rs index 62dc3869..ddbdbd92 100644 --- a/src/bin/rhai-repl.rs +++ b/src/bin/rhai-repl.rs @@ -114,7 +114,7 @@ fn main() { .map_err(|err| err.into()) .and_then(|mut ast| { ast.set_source(filename.to_string_lossy().to_string()); - Module::eval_ast_as_new(Default::default(), &ast, &engine) + Module::eval_ast_as_new(Scope::new(), &ast, &engine) }) { Err(err) => { let filename = filename.to_string_lossy(); @@ -163,9 +163,9 @@ fn main() { // REPL loop let mut input = String::new(); - let mut main_ast: AST = Default::default(); - let mut ast_u: AST = Default::default(); - let mut ast: AST = Default::default(); + let mut main_ast = AST::empty(); + let mut ast_u = AST::empty(); + let mut ast = AST::empty(); 'main_loop: loop { print!("rhai-repl> "); diff --git a/src/engine.rs b/src/engine.rs index c512fbf9..e8b8b50f 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -56,7 +56,7 @@ pub type Precedence = NonZeroU8; // This implementation splits the module names from the shared modules to improve data locality. // Most usage will be looking up a particular key from the list and then getting the module that // corresponds to that key. -#[derive(Clone, Default)] +#[derive(Clone)] pub struct Imports { keys: StaticVec, modules: StaticVec>, @@ -689,12 +689,6 @@ pub struct EvalState { pub global_constants: BTreeMap, } -impl Default for EvalState { - fn default() -> Self { - Self::new() - } -} - impl EvalState { /// Create a new [`EvalState`]. #[inline(always)] @@ -736,7 +730,7 @@ impl EvalState { #[allow(dead_code)] #[inline(always)] pub fn push_fn_resolution_cache(&mut self) { - self.fn_resolution_caches.push(Default::default()); + self.fn_resolution_caches.push(BTreeMap::new()); } /// Remove the current function resolution cache from the stack and make the last one current. /// @@ -824,8 +818,8 @@ pub struct Limits { } #[cfg(not(feature = "unchecked"))] -impl Default for Limits { - fn default() -> Self { +impl Limits { + pub const fn new() -> Self { Self { #[cfg(not(feature = "no_function"))] max_call_stack_depth: MAX_CALL_STACK_DEPTH, @@ -1090,17 +1084,17 @@ impl Engine { #[must_use] pub fn new_raw() -> Self { let mut engine = Self { - global_modules: Default::default(), - global_sub_modules: Default::default(), + global_modules: StaticVec::new(), + global_sub_modules: BTreeMap::new(), #[cfg(not(feature = "no_module"))] module_resolver: None, - type_names: Default::default(), - empty_string: Default::default(), - disabled_symbols: Default::default(), - custom_keywords: Default::default(), - custom_syntax: Default::default(), + type_names: BTreeMap::new(), + empty_string: ImmutableString::new(), + disabled_symbols: BTreeSet::new(), + custom_keywords: BTreeMap::new(), + custom_syntax: BTreeMap::new(), resolve_var: None, token_mapper: None, @@ -1115,7 +1109,7 @@ impl Engine { optimization_level: Default::default(), #[cfg(not(feature = "unchecked"))] - limits: Default::default(), + limits: Limits::new(), }; // Add the global namespace module @@ -1654,7 +1648,7 @@ impl Engine { let rhs_chain = match_chaining_type(rhs); let hash_get = FnCallHashes::from_native(*hash_get); let hash_set = FnCallHashes::from_native(*hash_set); - let mut arg_values = [target.as_mut(), &mut Default::default()]; + let mut arg_values = [target.as_mut(), &mut Dynamic::UNIT.clone()]; let args = &mut arg_values[..1]; // Assume getters are always pure @@ -1796,7 +1790,7 @@ impl Engine { _ => unreachable!("index or dot chain expected, but gets {:?}", expr), }; - let idx_values = &mut Default::default(); + let idx_values = &mut StaticVec::new(); self.eval_dot_index_chain_arguments( scope, mods, state, lib, this_ptr, rhs, term, chain_type, idx_values, 0, level, @@ -2037,7 +2031,7 @@ impl Engine { })?; if _add_if_not_found && !map.contains_key(index.as_str()) { - map.insert(index.clone().into(), Default::default()); + map.insert(index.clone().into(), Dynamic::UNIT); } Ok(map @@ -2782,7 +2776,6 @@ impl Engine { }); scope.push(unsafe_cast_var_name_to_lifetime(name), ()); let index = scope.len() - 1; - state.scope_level += 1; for (x, iter_value) in func(iter_obj).enumerate() { // Increment counter @@ -2839,7 +2832,6 @@ impl Engine { } } - state.scope_level -= 1; scope.rewind(orig_scope_len); Ok(Dynamic::UNIT) } else { @@ -2942,7 +2934,6 @@ impl Engine { }; let orig_scope_len = scope.len(); - state.scope_level += 1; err_var.as_ref().map(|Ident { name, .. }| { scope.push(unsafe_cast_var_name_to_lifetime(name), err_value) @@ -2952,7 +2943,6 @@ impl Engine { scope, mods, state, lib, this_ptr, catch_stmt, true, level, ); - state.scope_level -= 1; scope.rewind(orig_scope_len); match result { diff --git a/src/engine_api.rs b/src/engine_api.rs index c7b0f475..00a616d0 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -1002,7 +1002,7 @@ impl Engine { /// ``` #[inline(always)] pub fn compile(&self, script: &str) -> Result { - self.compile_with_scope(&Default::default(), script) + self.compile_with_scope(&Scope::new(), script) } /// Compile a string into an [`AST`] using own scope, which can be used later for evaluation. /// @@ -1091,7 +1091,7 @@ impl Engine { if let Some(ref module_resolver) = self.module_resolver { let mut resolver = StaticModuleResolver::new(); - let mut imports = Default::default(); + let mut imports = BTreeSet::new(); collect_imports(&ast, &resolver, &mut imports); @@ -1256,7 +1256,7 @@ impl Engine { #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] #[inline(always)] pub fn compile_file(&self, path: std::path::PathBuf) -> Result> { - self.compile_file_with_scope(&Default::default(), path) + self.compile_file_with_scope(&Scope::new(), path) } /// Compile a script file into an [`AST`] using own scope, which can be used later for evaluation. /// @@ -1424,7 +1424,7 @@ impl Engine { /// ``` #[inline(always)] pub fn compile_expression(&self, script: &str) -> Result { - self.compile_expression_with_scope(&Default::default(), script) + self.compile_expression_with_scope(&Scope::new(), script) } /// Compile a string containing an expression into an [`AST`] using own scope, /// which can be used later for evaluation. @@ -1558,7 +1558,7 @@ impl Engine { /// ``` #[inline(always)] pub fn eval(&self, script: &str) -> Result> { - self.eval_with_scope(&mut Default::default(), script) + self.eval_with_scope(&mut Scope::new(), script) } /// Evaluate a string with own scope. /// @@ -1615,7 +1615,7 @@ impl Engine { &self, script: &str, ) -> Result> { - self.eval_expression_with_scope(&mut Default::default(), script) + self.eval_expression_with_scope(&mut Scope::new(), script) } /// Evaluate a string containing an expression with own scope. /// @@ -1677,7 +1677,7 @@ impl Engine { /// ``` #[inline(always)] pub fn eval_ast(&self, ast: &AST) -> Result> { - self.eval_ast_with_scope(&mut Default::default(), ast) + self.eval_ast_with_scope(&mut Scope::new(), ast) } /// Evaluate an [`AST`] with own scope. /// @@ -1714,7 +1714,7 @@ impl Engine { scope: &mut Scope, ast: &AST, ) -> Result> { - let mods = &mut Default::default(); + let mods = &mut Imports::new(); let result = self.eval_ast_with_scope_raw(scope, mods, ast, 0)?; @@ -1779,7 +1779,7 @@ impl Engine { /// Evaluate a script, returning any error (if any). #[inline(always)] pub fn run(&self, script: &str) -> Result<(), Box> { - self.run_with_scope(&mut Default::default(), script) + self.run_with_scope(&mut Scope::new(), script) } /// Evaluate a script with own scope, returning any error (if any). #[inline] @@ -1806,7 +1806,7 @@ impl Engine { /// Evaluate an AST, returning any error (if any). #[inline(always)] pub fn run_ast(&self, ast: &AST) -> Result<(), Box> { - self.run_ast_with_scope(&mut Default::default(), ast) + self.run_ast_with_scope(&mut Scope::new(), ast) } /// Evaluate an [`AST`] with own scope, returning any error (if any). #[inline] @@ -1815,7 +1815,7 @@ impl Engine { scope: &mut Scope, ast: &AST, ) -> Result<(), Box> { - let mods = &mut Default::default(); + let mods = &mut Imports::new(); let mut state = EvalState::new(); state.source = ast.source_raw().cloned(); #[cfg(not(feature = "no_module"))] @@ -1989,7 +1989,7 @@ impl Engine { args: &mut FnCallArgs, ) -> RhaiResult { let state = &mut EvalState::new(); - let mods = &mut Default::default(); + let mods = &mut Imports::new(); let lib = &[ast.lib()]; let statements = ast.statements(); @@ -2059,7 +2059,7 @@ impl Engine { .collect(); #[cfg(feature = "no_function")] - let lib = Default::default(); + let lib = StaticVec::new(); let stmt = std::mem::take(ast.statements_mut()); crate::optimize::optimize_into_ast(self, scope, stmt, lib, optimization_level) diff --git a/src/fn_call.rs b/src/fn_call.rs index 4acef578..84b1016a 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -33,13 +33,20 @@ pub type FnCallArgs<'a> = [&'a mut Dynamic]; /// A type that temporarily stores a mutable reference to a `Dynamic`, /// replacing it with a cloned copy. -#[derive(Debug, Default)] +#[derive(Debug)] struct ArgBackup<'a> { orig_mut: Option<&'a mut Dynamic>, value_copy: Dynamic, } impl<'a> ArgBackup<'a> { + /// Create a new `ArgBackup`. + pub fn new() -> Self { + Self { + orig_mut: None, + value_copy: Dynamic::UNIT, + } + } /// This function replaces the first argument of a method call with a clone copy. /// This is to prevent a pure function unintentionally consuming the first argument. /// @@ -325,7 +332,7 @@ impl Engine { // Calling pure function but the first argument is a reference? let mut backup: Option = None; if is_method_call && func.is_pure() && !args.is_empty() { - backup = Some(Default::default()); + backup = Some(ArgBackup::new()); backup .as_mut() .expect("`backup` is `Some`") @@ -523,9 +530,6 @@ impl Engine { return Err(EvalAltResult::ErrorStackOverflow(pos).into()); } - let orig_scope_level = state.scope_level; - state.scope_level += 1; - let prev_scope_len = scope.len(); let prev_mods_len = mods.len(); @@ -593,7 +597,6 @@ impl Engine { // Remove all local variables scope.rewind(prev_scope_len); mods.truncate(prev_mods_len); - state.scope_level = orig_scope_level; if unified { state.pop_fn_resolution_cache(); @@ -782,7 +785,7 @@ impl Engine { // The first argument is a reference? let mut backup: Option = None; if is_ref_mut && !args.is_empty() { - backup = Some(Default::default()); + backup = Some(ArgBackup::new()); backup .as_mut() .expect("`backup` is `Some`") @@ -862,7 +865,7 @@ impl Engine { // Compile the script text // No optimizations because we only run it once let ast = self.compile_with_scope_and_optimization_level( - &Default::default(), + &Scope::new(), &[script], #[cfg(not(feature = "no_optimize"))] crate::OptimizationLevel::None, @@ -1352,7 +1355,7 @@ impl Engine { // func(x, ...) -> x.func(...) for index in 0..args_expr.len() { if index == 0 { - arg_values.push(Default::default()); + arg_values.push(Dynamic::UNIT); } else { let (value, _) = self.get_arg_value( scope, mods, state, lib, this_ptr, level, args_expr, constants, index, @@ -1433,7 +1436,7 @@ impl Engine { if fn_def.body.is_empty() { Ok(Dynamic::UNIT) } else { - let new_scope = &mut Default::default(); + let new_scope = &mut Scope::new(); let mut source = module.id_raw().cloned(); mem::swap(&mut state.source, &mut source); diff --git a/src/fn_native.rs b/src/fn_native.rs index 31799527..ef706800 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -1,7 +1,7 @@ //! Module defining interfaces to native-Rust functions. use crate::ast::{FnAccess, FnCallHashes}; -use crate::engine::Imports; +use crate::engine::{EvalState, Imports}; use crate::fn_call::FnCallArgs; use crate::plugin::PluginFunction; use crate::token::{Token, TokenizeState}; @@ -89,18 +89,18 @@ impl<'a, M: AsRef<[&'a Module]> + ?Sized> } } -impl<'a, M: AsRef<[&'a Module]> + ?Sized> From<(&'a Engine, &'a str, &'a M, Position)> +impl<'a, M: AsRef<[&'a Module]> + ?Sized> From<(&'a Engine, &'a str, &'a M)> for NativeCallContext<'a> { #[inline(always)] - fn from(value: (&'a Engine, &'a str, &'a M, Position)) -> Self { + fn from(value: (&'a Engine, &'a str, &'a M)) -> Self { Self { engine: value.0, fn_name: value.1, source: None, mods: None, lib: value.2.as_ref(), - pos: value.3, + pos: Position::NONE, } } } @@ -109,19 +109,14 @@ impl<'a> NativeCallContext<'a> { /// Create a new [`NativeCallContext`]. #[inline(always)] #[must_use] - pub const fn new( - engine: &'a Engine, - fn_name: &'a str, - lib: &'a [&Module], - pos: Position, - ) -> Self { + pub const fn new(engine: &'a Engine, fn_name: &'a str, lib: &'a [&Module]) -> Self { Self { engine, fn_name, source: None, mods: None, lib, - pos, + pos: Position::NONE, } } /// _(internals)_ Create a new [`NativeCallContext`]. @@ -247,8 +242,8 @@ impl<'a> NativeCallContext<'a> { self.engine() .exec_fn_call( - &mut self.mods.cloned().unwrap_or_default(), - &mut Default::default(), + &mut self.mods.cloned().unwrap_or_else(|| Imports::new()), + &mut EvalState::new(), self.lib, fn_name, hash, diff --git a/src/fn_ptr.rs b/src/fn_ptr.rs index e0140579..8f091077 100644 --- a/src/fn_ptr.rs +++ b/src/fn_ptr.rs @@ -146,7 +146,7 @@ impl TryFrom for FnPtr { #[inline] fn try_from(value: Identifier) -> Result { if is_valid_identifier(value.chars()) { - Ok(Self(value, Default::default())) + Ok(Self(value, StaticVec::new())) } else { Err(EvalAltResult::ErrorFunctionNotFound(value.to_string(), Position::NONE).into()) } diff --git a/src/fn_register.rs b/src/fn_register.rs index fbc74237..60bcbec8 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -123,7 +123,7 @@ macro_rules! def_register { #[inline(always)] fn into_callable_function(self) -> CallableFunction { CallableFunction::$abi(Box::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| { if args.len() == 2 && args[0].is_read_only() && is_setter(ctx.fn_name()) { - return Err(EvalAltResult::ErrorAssignmentToConstant(Default::default(), Position::NONE).into()); + return Err(EvalAltResult::ErrorAssignmentToConstant(String::new(), Position::NONE).into()); } // The arguments are assumed to be of the correct number and types! @@ -151,7 +151,7 @@ macro_rules! def_register { #[inline(always)] fn into_callable_function(self) -> CallableFunction { CallableFunction::$abi(Box::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| { if args.len() == 2 && args[0].is_read_only() && is_setter(ctx.fn_name()) { - return Err(EvalAltResult::ErrorAssignmentToConstant(Default::default(), Position::NONE).into()); + return Err(EvalAltResult::ErrorAssignmentToConstant(String::new(), Position::NONE).into()); } // The arguments are assumed to be of the correct number and types! @@ -179,7 +179,7 @@ macro_rules! def_register { #[inline(always)] fn into_callable_function(self) -> CallableFunction { CallableFunction::$abi(Box::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| { if args.len() == 2 && args[0].is_read_only() && is_setter(ctx.fn_name()) { - return Err(EvalAltResult::ErrorAssignmentToConstant(Default::default(), Position::NONE).into()); + return Err(EvalAltResult::ErrorAssignmentToConstant(String::new(), Position::NONE).into()); } // The arguments are assumed to be of the correct number and types! @@ -204,7 +204,7 @@ macro_rules! def_register { #[inline(always)] fn into_callable_function(self) -> CallableFunction { CallableFunction::$abi(Box::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| { if args.len() == 2 && args[0].is_read_only() && is_setter(ctx.fn_name()) { - return Err(EvalAltResult::ErrorAssignmentToConstant(Default::default(), Position::NONE).into()); + return Err(EvalAltResult::ErrorAssignmentToConstant(String::new(), Position::NONE).into()); } // The arguments are assumed to be of the correct number and types! diff --git a/src/module/mod.rs b/src/module/mod.rs index 5b26b3b0..03ef891e 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -37,13 +37,6 @@ pub enum FnNamespace { Internal, } -impl Default for FnNamespace { - #[inline(always)] - fn default() -> Self { - Self::Internal - } -} - /// Data structure containing a single registered function. #[derive(Debug, Clone)] pub struct FuncInfo { @@ -249,16 +242,16 @@ impl Module { id: None, internal: false, standard: false, - modules: Default::default(), - variables: Default::default(), - all_variables: Default::default(), - functions: Default::default(), - all_functions: Default::default(), - type_iterators: Default::default(), - all_type_iterators: Default::default(), + modules: BTreeMap::new(), + variables: BTreeMap::new(), + all_variables: BTreeMap::new(), + functions: BTreeMap::new(), + all_functions: BTreeMap::new(), + type_iterators: BTreeMap::new(), + all_type_iterators: BTreeMap::new(), indexed: true, contains_indexed_global_functions: false, - identifiers: Default::default(), + identifiers: IdentifierBuilder::new(), } } @@ -486,7 +479,7 @@ impl Module { namespace: FnNamespace::Internal, access: fn_def.access, params: num_params, - param_types: Default::default(), + param_types: StaticVec::new(), #[cfg(feature = "metadata")] param_names, func: Into::::into(fn_def).into(), @@ -1565,9 +1558,9 @@ impl Module { if !self.indexed { let mut path = Vec::with_capacity(4); - let mut variables = Default::default(); - let mut functions = Default::default(); - let mut type_iterators = Default::default(); + let mut variables = BTreeMap::new(); + let mut functions = BTreeMap::new(); + let mut type_iterators = BTreeMap::new(); path.push(""); diff --git a/src/module/resolvers/collection.rs b/src/module/resolvers/collection.rs index 6a61ff3f..a3581a99 100644 --- a/src/module/resolvers/collection.rs +++ b/src/module/resolvers/collection.rs @@ -20,7 +20,6 @@ use std::prelude::v1::*; /// let mut engine = Engine::new(); /// engine.set_module_resolver(collection); /// ``` -#[derive(Default)] pub struct ModuleResolversCollection(Vec>); impl ModuleResolversCollection { @@ -43,7 +42,7 @@ impl ModuleResolversCollection { #[inline(always)] #[must_use] pub fn new() -> Self { - Default::default() + Self(Vec::new()) } /// Append a [module resolver][ModuleResolver] to the end. #[inline(always)] diff --git a/src/module/resolvers/file.rs b/src/module/resolvers/file.rs index 276243fa..09bd7e4d 100644 --- a/src/module/resolvers/file.rs +++ b/src/module/resolvers/file.rs @@ -1,4 +1,4 @@ -use crate::{Engine, EvalAltResult, Identifier, Module, ModuleResolver, Position, Shared}; +use crate::{Engine, EvalAltResult, Identifier, Module, ModuleResolver, Position, Scope, Shared}; #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{ @@ -51,13 +51,6 @@ pub struct FileModuleResolver { cache: std::sync::RwLock>>, } -impl Default for FileModuleResolver { - #[inline(always)] - fn default() -> Self { - Self::new() - } -} - impl FileModuleResolver { /// Create a new [`FileModuleResolver`] with the current directory as base path. /// @@ -301,7 +294,7 @@ impl ModuleResolver for FileModuleResolver { } // Load the script file and compile it - let scope = Default::default(); + let scope = Scope::new(); let mut ast = engine .compile_file(file_path.clone()) diff --git a/src/module/resolvers/stat.rs b/src/module/resolvers/stat.rs index a5b4d0c9..90b33ed7 100644 --- a/src/module/resolvers/stat.rs +++ b/src/module/resolvers/stat.rs @@ -22,7 +22,7 @@ use std::{collections::BTreeMap, ops::AddAssign}; /// /// engine.set_module_resolver(resolver); /// ``` -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub struct StaticModuleResolver(BTreeMap>); impl StaticModuleResolver { @@ -45,7 +45,7 @@ impl StaticModuleResolver { #[inline(always)] #[must_use] pub fn new() -> Self { - Default::default() + Self(BTreeMap::new()) } /// Add a [module][Module] keyed by its path. #[inline] diff --git a/src/optimize.rs b/src/optimize.rs index 0d2c2262..157d3365 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -2,7 +2,9 @@ use crate::ast::{Expr, OpAssignment, Stmt, AST_OPTION_FLAGS::*}; use crate::dynamic::AccessMode; -use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF}; +use crate::engine::{ + EvalState, Imports, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF, +}; use crate::fn_builtin::get_builtin_binary_op_fn; use crate::fn_hash::get_hasher; use crate::token::Token; @@ -131,8 +133,8 @@ impl<'a> OptimizerState<'a> { ) -> Option { self.engine .call_native_fn( - &Default::default(), - &mut Default::default(), + &Imports::new(), + &mut EvalState::new(), self.lib, fn_name, calc_fn_hash(fn_name, arg_values.len()), @@ -959,7 +961,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) { state.set_dirty(); let fn_ptr = FnPtr::new_unchecked( fn_name.as_str_ref().expect("`fn_name` is `ImmutableString`").into(), - Default::default() + StaticVec::new() ); *expr = Expr::DynamicConstant(Box::new(fn_ptr.into()), *pos); } @@ -1001,7 +1003,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) { _ if x.args.len() == 2 && !state.has_native_fn_override(x.hashes.native, arg_types.as_ref()) => { if let Some(result) = get_builtin_binary_op_fn(x.name.as_ref(), &arg_values[0], &arg_values[1]) .and_then(|f| { - let context = (state.engine, x.name.as_ref(), state.lib, Position::NONE).into(); + let context = (state.engine, x.name.as_ref(), state.lib).into(); let (first, second) = arg_values.split_first_mut().expect("`arg_values` is not empty"); (f)(context, &mut [ first, &mut second[0] ]).ok() }) { @@ -1154,16 +1156,16 @@ pub fn optimize_into_ast( .map(|fn_def| crate::ast::ScriptFnDef { name: fn_def.name.clone(), access: fn_def.access, - body: Default::default(), + body: crate::ast::StmtBlock::empty(), params: fn_def.params.clone(), #[cfg(not(feature = "no_closure"))] externals: fn_def.externals.clone(), lib: None, #[cfg(not(feature = "no_module"))] - mods: Default::default(), + mods: crate::engine::Imports::new(), #[cfg(not(feature = "no_function"))] #[cfg(feature = "metadata")] - comments: Default::default(), + comments: StaticVec::new(), }) .for_each(|fn_def| { lib2.set_script_fn(fn_def); @@ -1198,7 +1200,7 @@ pub fn optimize_into_ast( }; #[cfg(feature = "no_function")] - let lib = Default::default(); + let lib = Module::new(); statements.shrink_to_fit(); diff --git a/src/packages/iter_basic.rs b/src/packages/iter_basic.rs index 133ef488..16d3d5e4 100644 --- a/src/packages/iter_basic.rs +++ b/src/packages/iter_basic.rs @@ -27,7 +27,7 @@ where if r == from { return Err(EvalAltResult::ErrorInFunctionCall( "range".to_string(), - Default::default(), + String::new(), EvalAltResult::ErrorArithmetic( "step value cannot be zero".to_string(), crate::Position::NONE, @@ -201,7 +201,7 @@ struct CharsStream(Vec, usize); impl CharsStream { pub fn new(string: &str, from: INT, len: INT) -> Self { if len <= 0 { - return Self(Default::default(), 0); + return Self(Vec::new(), 0); } if from >= 0 { return Self( diff --git a/src/packages/string_basic.rs b/src/packages/string_basic.rs index 38dd5ac2..1959decc 100644 --- a/src/packages/string_basic.rs +++ b/src/packages/string_basic.rs @@ -60,8 +60,8 @@ mod print_debug_functions { ctx.engine().map_type_name(&format!("{:?}", item)).into() } #[rhai_fn(name = "print", name = "debug")] - pub fn print_empty_string() -> ImmutableString { - Default::default() + pub fn print_empty_string(ctx: NativeCallContext) -> ImmutableString { + ctx.engine().const_empty_string() } #[rhai_fn(name = "print", name = "to_string")] pub fn print_string(s: ImmutableString) -> ImmutableString { diff --git a/src/parse.rs b/src/parse.rs index e490b18c..9e3be877 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -50,12 +50,21 @@ const NEVER_ENDS: &str = "`TokenStream` never ends"; /// When [`ImmutableString`] is used as [`Identifier`], this type acts as an interner which keeps a /// collection of strings and returns shared instances, only creating a new string when it is not /// yet interned. -#[derive(Debug, Clone, Default, Hash)] +#[derive(Debug, Clone, Hash)] pub struct IdentifierBuilder( #[cfg(feature = "no_smartstring")] std::collections::BTreeSet, ); impl IdentifierBuilder { + /// Create a new IdentifierBuilder. + #[inline] + #[must_use] + pub fn new() -> Self { + Self( + #[cfg(feature = "no_smartstring")] + std::collections::BTreeSet::new(), + ) + } /// Get an identifier from a text string. #[inline] #[must_use] @@ -121,14 +130,14 @@ impl<'e> ParseState<'e> { #[cfg(not(feature = "no_function"))] max_function_expr_depth: NonZeroUsize::new(engine.max_function_expr_depth()), #[cfg(not(feature = "no_closure"))] - external_vars: Default::default(), + external_vars: BTreeMap::new(), #[cfg(not(feature = "no_closure"))] allow_capture: true, - interned_strings: Default::default(), - stack: Default::default(), + interned_strings: IdentifierBuilder::new(), + stack: StaticVec::new(), entry_stack_len: 0, #[cfg(not(feature = "no_module"))] - modules: Default::default(), + modules: StaticVec::new(), } } @@ -398,7 +407,7 @@ fn parse_symbol(input: &mut TokenStream) -> Result<(String, Position), ParseErro // Bad identifier (Token::LexError(err), pos) => Err(err.into_err(pos)), // Not a symbol - (_, pos) => Err(PERR::MissingSymbol(Default::default()).into_err(pos)), + (_, pos) => Err(PERR::MissingSymbol(String::new()).into_err(pos)), } } @@ -902,7 +911,7 @@ fn parse_map_literal( let expr = parse_expr(input, state, lib, settings.level_up())?; let name = state.get_identifier(name); - template.insert(name.clone(), Default::default()); + template.insert(name.clone(), crate::Dynamic::UNIT); map.push((Ident { name, pos }, expr)); match input.peek().expect(NEVER_ENDS) { @@ -2556,7 +2565,7 @@ fn parse_export( } (name, pos) } else { - (Default::default(), Position::NONE) + (String::new(), Position::NONE) }; exports.push(( @@ -3075,7 +3084,7 @@ fn parse_fn( body, lib: None, #[cfg(not(feature = "no_module"))] - mods: Default::default(), + mods: crate::engine::Imports::new(), #[cfg(not(feature = "no_function"))] #[cfg(feature = "metadata")] comments, @@ -3216,17 +3225,17 @@ fn parse_anon_fn( access: FnAccess::Public, params, #[cfg(not(feature = "no_closure"))] - externals: Default::default(), + externals: std::collections::BTreeSet::new(), body: body.into(), lib: None, #[cfg(not(feature = "no_module"))] - mods: Default::default(), + mods: crate::engine::Imports::new(), #[cfg(not(feature = "no_function"))] #[cfg(feature = "metadata")] - comments: Default::default(), + comments: StaticVec::new(), }; - let fn_ptr = crate::FnPtr::new_unchecked(fn_name, Default::default()); + let fn_ptr = crate::FnPtr::new_unchecked(fn_name, StaticVec::new()); let expr = Expr::DynamicConstant(Box::new(fn_ptr.into()), settings.pos); #[cfg(not(feature = "no_closure"))] @@ -3245,7 +3254,7 @@ impl Engine { #[cfg(not(feature = "no_optimize"))] optimization_level: crate::OptimizationLevel, ) -> Result { let _scope = scope; - let mut functions = Default::default(); + let mut functions = BTreeMap::new(); let settings = ParseSettings { allow_if_expr: false, @@ -3278,7 +3287,7 @@ impl Engine { self, _scope, statements, - Default::default(), + StaticVec::new(), optimization_level, )); diff --git a/src/scope.rs b/src/scope.rs index 4064fe6d..ba5ce2fc 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -243,7 +243,7 @@ impl<'a> Scope<'a> { access: AccessMode, mut value: Dynamic, ) -> &mut Self { - self.names.push((name.into(), Default::default())); + self.names.push((name.into(), None)); value.set_access_mode(access); self.values.push(value); self @@ -592,7 +592,7 @@ impl<'a, K: Into>> Extend<(K, Dynamic)> for Scope<'a> { #[inline] fn extend>(&mut self, iter: T) { iter.into_iter().for_each(|(name, value)| { - self.names.push((name.into(), Default::default())); + self.names.push((name.into(), None)); self.values.push(value); }); } diff --git a/src/serde/de.rs b/src/serde/de.rs index b7c3e67a..e038c260 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -116,7 +116,7 @@ pub fn from_dynamic<'de, T: Deserialize<'de>>( impl Error for Box { fn custom(err: T) -> Self { - LexError::ImproperSymbol(Default::default(), err.to_string()) + LexError::ImproperSymbol(String::new(), err.to_string()) .into_err(Position::NONE) .into() } diff --git a/src/serde/metadata.rs b/src/serde/metadata.rs index 2ff11a9f..1e10e58a 100644 --- a/src/serde/metadata.rs +++ b/src/serde/metadata.rs @@ -168,7 +168,7 @@ impl From<&crate::module::FuncInfo> for FnMetadata { .to_vec() } } else { - Default::default() + Vec::new() }, } } @@ -198,7 +198,7 @@ impl From> for FnMetadata { } } -#[derive(Debug, Clone, Default, Serialize)] +#[derive(Debug, Clone, Serialize)] #[serde(rename_all = "camelCase")] struct ModuleMetadata { #[serde(skip_serializing_if = "BTreeMap::is_empty")] @@ -210,7 +210,10 @@ struct ModuleMetadata { impl ModuleMetadata { #[inline(always)] pub fn new() -> Self { - Default::default() + Self { + modules: BTreeMap::new(), + functions: Vec::new(), + } } } @@ -281,6 +284,6 @@ impl Engine { /// 2) Functions in static modules /// 3) Functions in global modules (optional) pub fn gen_fn_metadata_to_json(&self, include_global: bool) -> serde_json::Result { - self.gen_fn_metadata_with_ast_to_json(&Default::default(), include_global) + self.gen_fn_metadata_with_ast_to_json(&AST::empty(), include_global) } } diff --git a/src/serde/ser.rs b/src/serde/ser.rs index bfd0d128..a784a47e 100644 --- a/src/serde/ser.rs +++ b/src/serde/ser.rs @@ -28,7 +28,7 @@ impl DynamicSerializer { #[must_use] pub fn new(_value: Dynamic) -> Self { Self { - _key: Default::default(), + _key: Dynamic::UNIT, _value, } } @@ -83,7 +83,7 @@ impl DynamicSerializer { /// # } /// ``` pub fn to_dynamic(value: T) -> RhaiResult { - let mut s = DynamicSerializer::new(Default::default()); + let mut s = DynamicSerializer::new(Dynamic::UNIT); value.serialize(&mut s) } @@ -397,7 +397,7 @@ impl Serializer for &mut DynamicSerializer { #[cfg(not(feature = "no_object"))] return Ok(StructVariantSerializer { variant: _variant, - map: Default::default(), + map: Map::new(), }); #[cfg(feature = "no_object")] return Err(EvalAltResult::ErrorMismatchDataType( diff --git a/src/token.rs b/src/token.rs index fd56f31d..51c57726 100644 --- a/src/token.rs +++ b/src/token.rs @@ -33,13 +33,24 @@ use crate::engine::KEYWORD_IS_DEF_FN; /// # Volatile Data Structure /// /// This type is volatile and may change. -#[derive(Debug, Clone, Eq, PartialEq, Hash, Copy, Default)] +#[derive(Debug, Clone, Eq, PartialEq, Hash, Copy)] pub struct TokenizerControlBlock { /// Is the current tokenizer position within an interpolated text string? /// This flag allows switching the tokenizer back to _text_ parsing after an interpolation stream. pub is_within_text: bool, } +impl TokenizerControlBlock { + /// Create a new `TokenizerControlBlock`. + #[inline(always)] + #[must_use] + pub const fn new() -> Self { + Self { + is_within_text: false, + } + } +} + /// _(internals)_ A shared object that allows control of the tokenizer from outside. pub type TokenizerControl = Rc>; @@ -2281,7 +2292,7 @@ impl Engine { input: impl IntoIterator, token_mapper: Option<&'a OnParseTokenCallback>, ) -> (TokenIterator<'a>, TokenizerControl) { - let buffer: TokenizerControl = Default::default(); + let buffer: TokenizerControl = Cell::new(TokenizerControlBlock::new()).into(); let buffer2 = buffer.clone(); ( diff --git a/tests/closures.rs b/tests/closures.rs index 598469c4..c68038f5 100644 --- a/tests/closures.rs +++ b/tests/closures.rs @@ -338,7 +338,7 @@ fn test_closures_external() -> Result<(), Box> { // Create native call context let fn_name = fn_ptr.fn_name().to_string(); - let context = NativeCallContext::new(&engine, &fn_name, &lib, rhai::Position::NONE); + let context = NativeCallContext::new(&engine, &fn_name, &lib); // Closure 'f' captures: the engine, the AST, and the curried function pointer let f = move |x: INT| fn_ptr.call_dynamic(&context, None, [x.into()]); diff --git a/tests/custom_syntax.rs b/tests/custom_syntax.rs index d9d6171f..f381bdf0 100644 --- a/tests/custom_syntax.rs +++ b/tests/custom_syntax.rs @@ -196,7 +196,7 @@ fn test_custom_syntax_raw() -> Result<(), Box> { 2 => match stream[1].as_str() { "world" => Ok(Some("$$hello".into())), "kitty" => Ok(None), - s => Err(LexError::ImproperSymbol(s.to_string(), Default::default()) + s => Err(LexError::ImproperSymbol(s.to_string(), String::new()) .into_err(Position::NONE) .into()), }, diff --git a/tests/expressions.rs b/tests/expressions.rs index 13588d0d..6c0f16b1 100644 --- a/tests/expressions.rs +++ b/tests/expressions.rs @@ -59,7 +59,7 @@ fn test_expressions_eval() -> Result<(), Box> { engine.register_get("gender", AGENT::get_gender); engine.register_get("age", AGENT::get_age); - // Create your context, add the agent as a constant + // Create your scope, add the agent as a constant let mut scope = Scope::new(); scope.push_constant("agent", my_agent); diff --git a/tests/functions.rs b/tests/functions.rs index 6a37c87d..9ce5cc0c 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -1,5 +1,5 @@ #![cfg(not(feature = "no_function"))] -use rhai::{Engine, EvalAltResult, FnNamespace, Module, Shared, INT}; +use rhai::{Engine, EvalAltResult, FnNamespace, Module, NativeCallContext, Shared, INT}; #[cfg(not(feature = "no_object"))] #[test] @@ -43,7 +43,35 @@ fn test_functions_trait_object() -> Result<(), Box> { fn test_functions_namespaces() -> Result<(), Box> { let mut engine = Engine::new(); - #[cfg(not(feature = "no_function"))] + #[cfg(not(feature = "no_module"))] + { + let mut m = Module::new(); + let hash = m.set_native_fn("test", || Ok(999 as INT)); + m.update_fn_namespace(hash, FnNamespace::Global); + + engine.register_static_module("hello", m.into()); + + let mut m = Module::new(); + m.set_var("ANSWER", 123 as INT); + + assert_eq!(engine.eval::("test()")?, 999); + + assert_eq!(engine.eval::("fn test() { 123 } test()")?, 123); + } + + engine.register_fn("test", || 42 as INT); + + assert_eq!(engine.eval::("fn test() { 123 } test()")?, 123); + + assert_eq!(engine.eval::("test()")?, 42); + + Ok(()) +} + +#[test] +fn test_functions_global_module() -> Result<(), Box> { + let mut engine = Engine::new(); + #[cfg(not(feature = "no_module"))] { assert_eq!( @@ -56,43 +84,28 @@ fn test_functions_namespaces() -> Result<(), Box> { )?, 42 ); - } - #[cfg(not(feature = "no_module"))] - { - let mut m = Module::new(); - let hash = m.set_native_fn("test", || Ok(999 as INT)); - m.update_fn_namespace(hash, FnNamespace::Global); + assert!(matches!(*engine.run(" + fn foo() { global::ANSWER } - engine.register_static_module("hello", m.into()); + { + const ANSWER = 42; + foo() + } + ").expect_err("should error"), + EvalAltResult::ErrorInFunctionCall(_, _, err, _) + if matches!(&*err, EvalAltResult::ErrorVariableNotFound(v, _) if v == "global::ANSWER") + )); - let mut m = Module::new(); - m.set_var("ANSWER", 123 as INT); - - engine.register_static_module("global", m.into()); - - assert_eq!(engine.eval::("test()")?, 999); - - #[cfg(not(feature = "no_function"))] - assert_eq!(engine.eval::("fn test() { 123 } test()")?, 123); - } - - engine.register_fn("test", || 42 as INT); - - assert_eq!(engine.eval::("test()")?, 42); - - #[cfg(not(feature = "no_function"))] - #[cfg(not(feature = "no_module"))] - { - assert_eq!(engine.eval::("fn test() { 123 } test()")?, 123); + let mut module = Module::new(); + module.set_var("ANSWER", 123 as INT); + engine.register_static_module("global", module.into()); assert_eq!( engine.eval::( " const ANSWER = 42; - fn foo() { global::ANSWER } - foo() " )?, @@ -100,5 +113,23 @@ fn test_functions_namespaces() -> Result<(), Box> { ); } + engine.register_result_fn( + "do_stuff", + |context: NativeCallContext, callback: rhai::FnPtr| { + callback.call_dynamic(&context, None, []) + }, + ); + + #[cfg(not(feature = "no_closure"))] + assert!(matches!(*engine.run(" + do_stuff(|| { + const LOCAL_VALUE = 42; + global::LOCAL_VALUE + }); + ").expect_err("should error"), + EvalAltResult::ErrorInFunctionCall(_, _, err, _) + if matches!(&*err, EvalAltResult::ErrorVariableNotFound(v, _) if v == "global::LOCAL_VALUE") + )); + Ok(()) } diff --git a/tests/modules.rs b/tests/modules.rs index 8a6f8d67..e42198d9 100644 --- a/tests/modules.rs +++ b/tests/modules.rs @@ -444,7 +444,7 @@ fn test_module_ast_namespace() -> Result<(), Box> { let ast = engine.compile(script)?; - let module = Module::eval_ast_as_new(Default::default(), &ast, &engine)?; + let module = Module::eval_ast_as_new(Scope::new(), &ast, &engine)?; let mut resolver = StaticModuleResolver::new(); resolver.insert("testing", module); @@ -512,6 +512,6 @@ fn test_module_file() -> Result<(), Box> { print("top"); "#, )?; - Module::eval_ast_as_new(Default::default(), &ast, &engine)?; + Module::eval_ast_as_new(Scope::new(), &ast, &engine)?; Ok(()) }