Use namespace for ScriptFnDef.

This commit is contained in:
Stephen Chung 2021-03-07 22:10:54 +08:00
parent e87f981674
commit 330d3f87af
12 changed files with 106 additions and 108 deletions

View File

@ -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<ScriptFnMetadata<'a>> for &'a ScriptFnDef {
#[inline(always)]
fn into(self) -> ScriptFnMetadata<'a> {

View File

@ -1212,7 +1212,7 @@ impl Dynamic {
},
)
}
_ => unreachable!("self should be Shared"),
_ => unreachable!(),
},
_ => (),
}
@ -1684,6 +1684,16 @@ impl<T: Variant + Clone> From<&[T]> for Dynamic {
))
}
}
#[cfg(not(feature = "no_index"))]
impl<T: Variant + Clone> crate::stdlib::iter::FromIterator<T> for Dynamic {
#[inline(always)]
fn from_iter<X: IntoIterator<Item = T>>(iter: X) -> Self {
Self(Union::Array(
Box::new(iter.into_iter().map(Dynamic::from).collect()),
AccessMode::ReadWrite,
))
}
}
#[cfg(not(feature = "no_object"))]
impl<K: Into<ImmutableString>, T: Variant + Clone> From<crate::stdlib::collections::HashMap<K, T>>
for Dynamic

View File

@ -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<Item = (&ImmutableString, &Shared<Module>)> {
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::<ImmutableString>() => {
let mut s = s.write_lock::<ImmutableString>().unwrap();
Self::StringChar(s, index, _) => {
let s = &mut *s.write_lock::<ImmutableString>().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::<StaticVec<_>>();
let index = *index;
// See if changed - if so, update the String
if chars[*index] != new_ch {
chars[*index] = new_ch;
*s = chars.iter().collect::<String>().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<EvalAltResult>> {
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;

View File

@ -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<NonZeroU64>,
_hash_script: Option<NonZeroU64>,
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::<FnPtr>() && args[1].is::<INT>() =>
if args.len() == 2 && args[0].is::<FnPtr>() && args[1].is::<crate::INT>() =>
{
let fn_name = args[0].read_lock::<ImmutableString>().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::<INT>(err, args_expr[0].position())
self.make_type_mismatch_err::<crate::INT>(err, args_expr[0].position())
})?;
return Ok(if num_params < 0 {

View File

@ -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<FnPlugin>),
/// A script-defined function.
#[cfg(not(feature = "no_function"))]
Script(Shared<ScriptFnDef>),
Script(Shared<crate::ast::ScriptFnDef>),
}
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<IteratorFn> for CallableFunction {
}
}
impl From<ScriptFnDef> for CallableFunction {
#[cfg(not(feature = "no_function"))]
impl From<crate::ast::ScriptFnDef> 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<Shared<ScriptFnDef>> for CallableFunction {
#[cfg(not(feature = "no_function"))]
impl From<Shared<crate::ast::ScriptFnDef>> for CallableFunction {
#[inline(always)]
fn from(_func: Shared<ScriptFnDef>) -> Self {
#[cfg(feature = "no_function")]
unreachable!("no_function active");
#[cfg(not(feature = "no_function"))]
fn from(_func: Shared<crate::ast::ScriptFnDef>) -> Self {
Self::Script(_func)
}
}

View File

@ -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

View File

@ -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`.

View File

@ -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<Shared<ScriptFnDef>>) -> NonZeroU64 {
pub(crate) fn set_script_fn(
&mut self,
fn_def: impl Into<Shared<crate::ast::ScriptFnDef>>,
) -> 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<Item = (FnNamespace, FnAccess, &str, usize, &ScriptFnDef)> + '_ {
) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize, &crate::ast::ScriptFnDef)> + '_
{
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<Item = (FnNamespace, FnAccess, &str, usize, &ScriptFnDef)> {
) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize, &crate::ast::ScriptFnDef)> {
self.iter_script_fn()
}

View File

@ -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<Stmt>,
_functions: Vec<ScriptFnDef>,
_functions: Vec<crate::ast::ScriptFnDef>,
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(),

View File

@ -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
}

View File

@ -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,
)

View File

@ -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!(),
});
}