From 330d3f87af4cc414ac91adf0f5f8f678e991ea7d Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 7 Mar 2021 22:10:54 +0800 Subject: [PATCH] Use namespace for ScriptFnDef. --- src/ast.rs | 3 +++ src/dynamic.rs | 12 ++++++++- src/engine.rs | 55 +++++++++++++++++----------------------- src/fn_call.rs | 10 ++++---- src/fn_native.rs | 25 ++++++++---------- src/fn_register.rs | 9 +++---- src/lib.rs | 5 +++- src/module/mod.rs | 15 ++++++----- src/optimize.rs | 6 ++--- src/packages/fn_basic.rs | 49 ++++++++++++++++++----------------- src/parser.rs | 17 +++++-------- src/token.rs | 8 +++--- 12 files changed, 106 insertions(+), 108 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 06d3b714..46789cbd 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -89,6 +89,7 @@ impl fmt::Display for ScriptFnDef { /// A type containing the metadata of a script-defined function. /// /// Created by [`AST::iter_functions`]. +#[cfg(not(feature = "no_function"))] #[derive(Debug, Eq, PartialEq, Clone, Hash)] pub struct ScriptFnMetadata<'a> { /// Function doc-comments (if any). @@ -108,6 +109,7 @@ pub struct ScriptFnMetadata<'a> { pub params: Vec<&'a str>, } +#[cfg(not(feature = "no_function"))] impl fmt::Display for ScriptFnMetadata<'_> { #[inline(always)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -124,6 +126,7 @@ impl fmt::Display for ScriptFnMetadata<'_> { } } +#[cfg(not(feature = "no_function"))] impl<'a> Into> for &'a ScriptFnDef { #[inline(always)] fn into(self) -> ScriptFnMetadata<'a> { diff --git a/src/dynamic.rs b/src/dynamic.rs index abafc404..b6bb5e71 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -1212,7 +1212,7 @@ impl Dynamic { }, ) } - _ => unreachable!("self should be Shared"), + _ => unreachable!(), }, _ => (), } @@ -1684,6 +1684,16 @@ impl From<&[T]> for Dynamic { )) } } +#[cfg(not(feature = "no_index"))] +impl crate::stdlib::iter::FromIterator for Dynamic { + #[inline(always)] + fn from_iter>(iter: X) -> Self { + Self(Union::Array( + Box::new(iter.into_iter().map(Dynamic::from).collect()), + AccessMode::ReadWrite, + )) + } +} #[cfg(not(feature = "no_object"))] impl, T: Variant + Clone> From> for Dynamic diff --git a/src/engine.rs b/src/engine.rs index b4ac13c2..d8ffd7bb 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -108,6 +108,7 @@ impl Imports { self.0.iter().rev().map(|(n, m)| (n, m)) } /// Get an iterator to this stack of imported [modules][Module] in forward order. + #[allow(dead_code)] #[inline(always)] pub(crate) fn scan_raw(&self) -> impl Iterator)> { self.0.iter().map(|(n, m)| (n, m)) @@ -405,8 +406,8 @@ impl<'a> Target<'a> { Self::LockGuard((r, _)) => **r = new_val, Self::Value(_) => panic!("cannot update a value"), #[cfg(not(feature = "no_index"))] - Self::StringChar(s, index, _) if s.is::() => { - let mut s = s.write_lock::().unwrap(); + Self::StringChar(s, index, _) => { + let s = &mut *s.write_lock::().unwrap(); // Replace the character at the specified index position let new_ch = new_val.as_char().map_err(|err| { @@ -417,19 +418,14 @@ impl<'a> Target<'a> { )) })?; - let mut chars = s.chars().collect::>(); + let index = *index; - // See if changed - if so, update the String - if chars[*index] != new_ch { - chars[*index] = new_ch; - *s = chars.iter().collect::().into(); - } + *s = s + .chars() + .enumerate() + .map(|(i, ch)| if i == index { new_ch } else { ch }) + .collect(); } - #[cfg(not(feature = "no_index"))] - Self::StringChar(s, _, _) => unreachable!( - "Target::StringChar should contain only a string, not {}", - s.type_name() - ), } Ok(()) @@ -543,6 +539,7 @@ impl State { self.fn_resolution_caches.last_mut().unwrap() } /// Push an empty functions resolution cache onto the stack and make it current. + #[allow(dead_code)] pub fn push_fn_resolution_cache(&mut self) { self.fn_resolution_caches.push(Default::default()); } @@ -550,14 +547,6 @@ impl State { pub fn pop_fn_resolution_cache(&mut self) { self.fn_resolution_caches.pop(); } - /// Clear the current functions resolution cache. - /// - /// # Panics - /// - /// Panics if there is no current functions resolution cache. - pub fn clear_fn_resolution_cache(&mut self) { - self.fn_resolution_caches.last_mut().unwrap().clear(); - } } /// _(INTERNALS)_ A type containing all the limits imposed by the [`Engine`]. @@ -1066,9 +1055,7 @@ impl Engine { level: usize, new_val: Option<((Dynamic, Position), (&str, Position))>, ) -> Result<(Dynamic, bool), Box> { - if chain_type == ChainType::NonChaining { - unreachable!("should not be ChainType::NonChaining"); - } + assert!(chain_type != ChainType::NonChaining); let is_ref = target.is_ref(); @@ -1875,7 +1862,7 @@ impl Engine { restore_prev_state: bool, level: usize, ) -> RhaiResult { - let mut _restore_fn_resolution_cache = false; + let mut _extra_fn_resolution_cache = false; let prev_always_search = state.always_search; let prev_scope_len = scope.len(); let prev_mods_len = mods.len(); @@ -1898,15 +1885,18 @@ impl Engine { .skip(_mods_len) .any(|(_, m)| m.contains_indexed_global_functions()) { - if _restore_fn_resolution_cache { + if _extra_fn_resolution_cache { // When new module is imported with global functions and there is already // a new cache, clear it - notice that this is expensive as all function // resolutions must start again - state.clear_fn_resolution_cache(); + state.fn_resolution_cache_mut().clear(); } else if restore_prev_state { // When new module is imported with global functions, push a new cache state.push_fn_resolution_cache(); - _restore_fn_resolution_cache = true; + _extra_fn_resolution_cache = true; + } else { + // When the block is to be evaluated in-place, just clear the current cache + state.fn_resolution_cache_mut().clear(); } } } @@ -1914,12 +1904,13 @@ impl Engine { Ok(r) }); + if _extra_fn_resolution_cache { + // If imports list is modified, pop the functions lookup cache + state.pop_fn_resolution_cache(); + } + if restore_prev_state { scope.rewind(prev_scope_len); - if _restore_fn_resolution_cache { - // If imports list is modified, pop the functions lookup cache - state.pop_fn_resolution_cache(); - } mods.truncate(prev_mods_len); state.scope_level -= 1; diff --git a/src/fn_call.rs b/src/fn_call.rs index f539ae3e..35c7a768 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -28,7 +28,7 @@ use crate::{ }; use crate::{ calc_native_fn_hash, calc_script_fn_hash, Dynamic, Engine, EvalAltResult, FnPtr, - ImmutableString, Module, ParseErrorType, Position, Scope, StaticVec, INT, + ImmutableString, Module, ParseErrorType, Position, Scope, StaticVec, }; #[cfg(not(feature = "no_object"))] @@ -649,7 +649,7 @@ impl Engine { state: &mut State, lib: &[&Module], fn_name: &str, - hash_script: Option, + _hash_script: Option, args: &mut FnCallArgs, is_ref: bool, _is_method: bool, @@ -675,7 +675,7 @@ impl Engine { // Handle is_def_fn() #[cfg(not(feature = "no_function"))] crate::engine::KEYWORD_IS_DEF_FN - if args.len() == 2 && args[0].is::() && args[1].is::() => + if args.len() == 2 && args[0].is::() && args[1].is::() => { let fn_name = args[0].read_lock::().unwrap(); let num_params = args[1].as_int().unwrap(); @@ -732,7 +732,7 @@ impl Engine { } #[cfg(not(feature = "no_function"))] - if let Some((func, source)) = hash_script.and_then(|hash| { + if let Some((func, source)) = _hash_script.and_then(|hash| { self.resolve_function(mods, state, lib, fn_name, hash, args, false, false) .as_ref() .map(|(f, s)| (f.clone(), s.clone())) @@ -1139,7 +1139,7 @@ impl Engine { .eval_expr(scope, mods, state, lib, this_ptr, &args_expr[1], level)? .as_int() .map_err(|err| { - self.make_type_mismatch_err::(err, args_expr[0].position()) + self.make_type_mismatch_err::(err, args_expr[0].position()) })?; return Ok(if num_params < 0 { diff --git a/src/fn_native.rs b/src/fn_native.rs index 9296da62..d7c299dd 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -1,6 +1,6 @@ //! Module defining interfaces to native-Rust functions. -use crate::ast::{FnAccess, ScriptFnDef}; +use crate::ast::FnAccess; use crate::engine::Imports; use crate::plugin::PluginFunction; use crate::stdlib::{ @@ -143,6 +143,7 @@ impl<'a> NativeCallContext<'a> { } /// Get an iterator over the current set of modules imported via `import` statements. #[cfg(not(feature = "no_module"))] + #[allow(dead_code)] #[inline(always)] pub(crate) fn iter_imports_raw( &self, @@ -438,7 +439,7 @@ pub enum CallableFunction { Plugin(Shared), /// A script-defined function. #[cfg(not(feature = "no_function"))] - Script(Shared), + Script(Shared), } impl fmt::Debug for CallableFunction { @@ -576,7 +577,7 @@ impl CallableFunction { /// Panics if the [`CallableFunction`] is not [`Script`][CallableFunction::Script]. #[cfg(not(feature = "no_function"))] #[inline(always)] - pub fn get_fn_def(&self) -> &ScriptFnDef { + pub fn get_fn_def(&self) -> &crate::ast::ScriptFnDef { match self { Self::Pure(_) | Self::Method(_) | Self::Iterator(_) | Self::Plugin(_) => { panic!("function should be scripted") @@ -642,24 +643,18 @@ impl From for CallableFunction { } } -impl From for CallableFunction { +#[cfg(not(feature = "no_function"))] +impl From for CallableFunction { #[inline(always)] - fn from(_func: ScriptFnDef) -> Self { - #[cfg(feature = "no_function")] - unreachable!("no_function active"); - - #[cfg(not(feature = "no_function"))] + fn from(_func: crate::ast::ScriptFnDef) -> Self { Self::Script(_func.into()) } } -impl From> for CallableFunction { +#[cfg(not(feature = "no_function"))] +impl From> for CallableFunction { #[inline(always)] - fn from(_func: Shared) -> Self { - #[cfg(feature = "no_function")] - unreachable!("no_function active"); - - #[cfg(not(feature = "no_function"))] + fn from(_func: Shared) -> Self { Self::Script(_func) } } diff --git a/src/fn_register.rs b/src/fn_register.rs index 2d8989e0..ea7dc9b0 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -131,8 +131,7 @@ macro_rules! make_func { // The arguments are assumed to be of the correct number and types! let mut _drain = args.iter_mut(); - $($let)* - $($par = ($convert)(_drain.next().unwrap()); )* + $($let $par = ($convert)(_drain.next().unwrap()); )* // Call the function with each argument value let r = $fn($($arg),*); @@ -215,9 +214,9 @@ macro_rules! def_register { }; ($p0:ident $(, $p:ident)*) => { def_register!(imp from_pure : $p0 => $p0 => $p0 => $p0 => let $p0 => by_value $(, $p => $p => $p => $p => let $p => by_value)*); - def_register!(imp from_method : $p0 => &mut $p0 => Mut<$p0> => &mut $p0 => let mut $p0 => by_ref $(, $p => $p => $p => $p => let $p => by_value)*); - // ^ CallableFunction - // handle the first parameter ^ first parameter passed through + def_register!(imp from_method : $p0 => &mut $p0 => Mut<$p0> => &mut $p0 => let mut $p0 => by_ref $(, $p => $p => $p => $p => let $p => by_value)*); + // ^ CallableFunction constructor + // ^ first parameter passed through // ^ others passed by value (by_value) // Currently does not support first argument which is a reference, as there will be diff --git a/src/lib.rs b/src/lib.rs index 26b7b421..01d02910 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,7 +122,7 @@ pub type FLOAT = f64; #[cfg(feature = "f32_float")] pub type FLOAT = f32; -pub use ast::{FnAccess, ScriptFnMetadata, AST}; +pub use ast::{FnAccess, AST}; pub use dynamic::Dynamic; pub use engine::{Engine, EvalContext}; pub use fn_native::{FnPtr, NativeCallContext}; @@ -155,6 +155,9 @@ pub use fn_func::Func; #[cfg(not(feature = "no_function"))] pub use fn_args::FuncArgs; +#[cfg(not(feature = "no_function"))] +pub use ast::ScriptFnMetadata; + /// Variable-sized array of [`Dynamic`] values. /// /// Not available under `no_index`. diff --git a/src/module/mod.rs b/src/module/mod.rs index 6bcdf3d8..ed9f2dab 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -22,9 +22,6 @@ use crate::{ Dynamic, EvalAltResult, ImmutableString, NativeCallContext, Position, Shared, StaticVec, }; -#[cfg(not(feature = "no_function"))] -use crate::ast::ScriptFnDef; - #[cfg(not(feature = "no_index"))] use crate::Array; @@ -460,7 +457,10 @@ impl Module { /// If there is an existing function of the same name and number of arguments, it is replaced. #[cfg(not(feature = "no_function"))] #[inline] - pub(crate) fn set_script_fn(&mut self, fn_def: impl Into>) -> NonZeroU64 { + pub(crate) fn set_script_fn( + &mut self, + fn_def: impl Into>, + ) -> NonZeroU64 { let fn_def = fn_def.into(); // None + function name + number of arguments. @@ -493,7 +493,7 @@ impl Module { name: &str, num_params: usize, public_only: bool, - ) -> Option<&ScriptFnDef> { + ) -> Option<&crate::ast::ScriptFnDef> { self.functions .values() .find( @@ -1692,7 +1692,8 @@ impl Module { #[inline(always)] pub(crate) fn iter_script_fn( &self, - ) -> impl Iterator + '_ { + ) -> impl Iterator + '_ + { self.functions.values().filter(|f| f.func.is_script()).map( |FuncInfo { namespace, @@ -1751,7 +1752,7 @@ impl Module { #[inline(always)] pub fn iter_script_fn_info( &self, - ) -> impl Iterator { + ) -> impl Iterator { self.iter_script_fn() } diff --git a/src/optimize.rs b/src/optimize.rs index 2f367a05..278f2588 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -1,6 +1,6 @@ //! Module implementing the [`AST`] optimizer. -use crate::ast::{Expr, ScriptFnDef, Stmt}; +use crate::ast::{Expr, Stmt}; use crate::dynamic::AccessMode; use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF}; use crate::fn_builtin::get_builtin_binary_op_fn; @@ -872,7 +872,7 @@ pub fn optimize_into_ast( engine: &Engine, scope: &Scope, mut statements: Vec, - _functions: Vec, + _functions: Vec, level: OptimizationLevel, ) -> AST { let level = if cfg!(feature = "no_optimize") { @@ -891,7 +891,7 @@ pub fn optimize_into_ast( _functions .iter() - .map(|fn_def| ScriptFnDef { + .map(|fn_def| crate::ast::ScriptFnDef { name: fn_def.name.clone(), access: fn_def.access, body: Default::default(), diff --git a/src/packages/fn_basic.rs b/src/packages/fn_basic.rs index e9bd49ff..3a6e489d 100644 --- a/src/packages/fn_basic.rs +++ b/src/packages/fn_basic.rs @@ -1,11 +1,6 @@ use crate::plugin::*; use crate::{def_package, FnPtr, ImmutableString, NativeCallContext}; -#[cfg(not(feature = "no_function"))] -#[cfg(not(feature = "no_index"))] -#[cfg(not(feature = "no_object"))] -use crate::{ast::ScriptFnDef, stdlib::collections::HashMap, Array, Map}; - def_package!(crate:BasicFnPackage:"Basic Fn functions.", lib, { combine_with_exported_module!(lib, "FnPtr", fn_ptr_functions); }); @@ -29,7 +24,7 @@ mod fn_ptr_functions { #[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_object"))] pub mod functions_and_maps { - pub fn get_fn_metadata_list(ctx: NativeCallContext) -> Array { + pub fn get_fn_metadata_list(ctx: NativeCallContext) -> crate::Array { collect_fn_metadata(ctx) } } @@ -38,7 +33,9 @@ mod fn_ptr_functions { #[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_object"))] -fn collect_fn_metadata(ctx: NativeCallContext) -> Array { +fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array { + use crate::{ast::ScriptFnDef, stdlib::collections::HashMap, Array, Map}; + // Create a metadata record for a function. fn make_metadata( dict: &HashMap<&str, ImmutableString>, @@ -76,22 +73,6 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> Array { map.into() } - // Recursively scan modules for script-defined functions. - fn scan_module( - list: &mut Array, - dict: &HashMap<&str, ImmutableString>, - namespace: ImmutableString, - module: &Module, - ) { - module.iter_script_fn().for_each(|(_, _, _, _, f)| { - list.push(make_metadata(dict, Some(namespace.clone()), f).into()) - }); - module.iter_sub_modules().for_each(|(ns, m)| { - let ns: ImmutableString = format!("{}::{}", namespace, ns).into(); - scan_module(list, dict, ns, m.as_ref()) - }); - } - // Intern strings let mut dict = HashMap::<&str, ImmutableString>::with_capacity(8); [ @@ -115,8 +96,26 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> Array { .for_each(|(_, _, _, _, f)| list.push(make_metadata(&dict, None, f).into())); #[cfg(not(feature = "no_module"))] - ctx.iter_imports_raw() - .for_each(|(ns, m)| scan_module(&mut list, &dict, ns.clone(), m.as_ref())); + { + // Recursively scan modules for script-defined functions. + fn scan_module( + list: &mut Array, + dict: &HashMap<&str, ImmutableString>, + namespace: ImmutableString, + module: &Module, + ) { + module.iter_script_fn().for_each(|(_, _, _, _, f)| { + list.push(make_metadata(dict, Some(namespace.clone()), f).into()) + }); + module.iter_sub_modules().for_each(|(ns, m)| { + let ns: ImmutableString = format!("{}::{}", namespace, ns).into(); + scan_module(list, dict, ns, m.as_ref()) + }); + } + + ctx.iter_imports_raw() + .for_each(|(ns, m)| scan_module(&mut list, &dict, ns.clone(), m.as_ref())); + } list } diff --git a/src/parser.rs b/src/parser.rs index cb549a41..dd73136d 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -948,7 +948,7 @@ fn parse_primary( } Token::True => Expr::BoolConstant(true, settings.pos), Token::False => Expr::BoolConstant(false, settings.pos), - t => unreachable!("unexpected token: {:?}", t), + _ => unreachable!(), }, #[cfg(not(feature = "no_float"))] Token::FloatConstant(x) => { @@ -1033,7 +1033,7 @@ fn parse_primary( Token::Identifier(_) => { let s = match input.next().unwrap().0 { Token::Identifier(s) => s, - t => unreachable!("expecting Token::Identifier, but gets {:?}", t), + _ => unreachable!(), }; match input.peek().unwrap().0 { @@ -1080,7 +1080,7 @@ fn parse_primary( Token::Reserved(_) => { let s = match input.next().unwrap().0 { Token::Reserved(s) => s, - t => unreachable!("expecting Token::Reserved, but gets {:?}", t), + _ => unreachable!(), }; match input.peek().unwrap().0 { @@ -1115,7 +1115,7 @@ fn parse_primary( Token::LexError(_) => { let err = match input.next().unwrap().0 { Token::LexError(err) => err, - t => unreachable!("expecting Token::LexError, but gets {:?}", t), + _ => unreachable!(), }; return Err(err.into_err(settings.pos)); @@ -2126,7 +2126,7 @@ fn parse_while_loop( (Some(expr), pos) } (Token::Loop, pos) => (None, pos), - (t, _) => unreachable!("expecting Token::While or Token::Loop, but gets {:?}", t), + _ => unreachable!(), }; settings.pos = token_pos; @@ -2544,7 +2544,7 @@ fn parse_stmt( _ => return Err(PERR::WrongDocComment.into_err(comments_pos)), } } - t => unreachable!("expecting Token::Comment, but gets {:?}", t), + _ => unreachable!(), } } } @@ -2651,10 +2651,7 @@ fn parse_stmt( match token { Token::Return => ReturnType::Return, Token::Throw => ReturnType::Exception, - t => unreachable!( - "expecting Token::Return or Token::Throw, but gets {:?}", - t - ), + _ => unreachable!(), }, pos, ) diff --git a/src/token.rs b/src/token.rs index 5cd1cc5c..d0cdcf9e 100644 --- a/src/token.rs +++ b/src/token.rs @@ -480,7 +480,7 @@ impl Token { #[cfg(not(feature = "no_module"))] As => "as", EOF => "{EOF}", - _ => unreachable!("operator should be matched in outer scope"), + t => unreachable!("operator should be matched in outer scope: {:?}", t), } .into(), } @@ -892,7 +892,7 @@ pub fn parse_string_literal( 'x' => 2, 'u' => 4, 'U' => 8, - _ => unreachable!("expecting 'x', 'u' or 'U', but gets {}", ch), + _ => unreachable!(), }; for _ in 0..len { @@ -1190,14 +1190,14 @@ fn get_next_token_inner( 'x' | 'X' => is_hex_digit, 'o' | 'O' => is_numeric_digit, 'b' | 'B' => is_numeric_digit, - _ => unreachable!("expecting 'x', 'o' or 'b', but gets {}", ch), + _ => unreachable!(), }; radix_base = Some(match ch { 'x' | 'X' => 16, 'o' | 'O' => 8, 'b' | 'B' => 2, - _ => unreachable!("expecting 'x', 'o' or 'b', but gets {}", ch), + _ => unreachable!(), }); }