Add gen_fn_siguatures API.

This commit is contained in:
Stephen Chung
2020-11-22 17:21:34 +08:00
parent 739dce72e3
commit 07fe132e1a
17 changed files with 400 additions and 83 deletions

View File

@@ -100,7 +100,7 @@ impl fmt::Display for ScriptFnDef {
.iter()
.map(|s| s.as_str())
.collect::<Vec<_>>()
.join(",")
.join(", ")
)
}
}

View File

@@ -95,24 +95,25 @@ impl Imports {
self.0.as_mut().unwrap().truncate(size);
}
}
/// Get an iterator to this stack of imported modules.
/// Get an iterator to this stack of imported modules in reverse order.
#[allow(dead_code)]
pub fn iter(&self) -> impl Iterator<Item = (&str, Shared<Module>)> {
self.0.iter().flat_map(|lib| {
lib.iter()
.rev()
.map(|(name, module)| (name.as_str(), module.clone()))
})
}
/// Get an iterator to this stack of imported modules.
/// Get an iterator to this stack of imported modules in reverse order.
#[allow(dead_code)]
pub(crate) fn iter_raw<'a>(
&'a self,
) -> impl Iterator<Item = (ImmutableString, Shared<Module>)> + 'a {
self.0.iter().flat_map(|lib| lib.iter().cloned())
self.0.iter().flat_map(|lib| lib.iter().rev().cloned())
}
/// Get a consuming iterator to this stack of imported modules.
/// Get a consuming iterator to this stack of imported modules in reverse order.
pub fn into_iter(self) -> impl Iterator<Item = (ImmutableString, Shared<Module>)> {
self.0.into_iter().flat_map(|lib| lib.into_iter())
self.0.into_iter().flat_map(|lib| lib.into_iter().rev())
}
/// Add a stream of imported modules.
pub fn extend(&mut self, stream: impl Iterator<Item = (ImmutableString, Shared<Module>)>) {

View File

@@ -1515,7 +1515,7 @@ impl Engine {
.into()
});
}
/// Call a script function defined in an [`AST`] with multiple `Dynamic` arguments
/// Call a script function defined in an [`AST`] with multiple [`Dynamic`] arguments
/// and optionally a value for binding to the `this` pointer.
///
/// ## WARNING
@@ -1578,7 +1578,7 @@ impl Engine {
self.call_fn_dynamic_raw(scope, &[lib.as_ref()], name, &mut this_ptr, args.as_mut())
}
/// Call a script function defined in an [`AST`] with multiple `Dynamic` arguments.
/// Call a script function defined in an [`AST`] with multiple [`Dynamic`] arguments.
///
/// ## WARNING
///
@@ -1646,6 +1646,27 @@ impl Engine {
let stmt = crate::stdlib::mem::take(ast.statements_mut());
crate::optimize::optimize_into_ast(self, scope, stmt, lib, optimization_level)
}
/// Generate a list of all registered functions.
///
/// The ordering is:
/// 1) Functions registered into the global namespace
/// 2) Functions in registered sub-modules
/// 3) Functions in packages
pub fn gen_fn_signatures(&self, include_packages: bool) -> Vec<String> {
let mut signatures: Vec<_> = Default::default();
signatures.extend(self.global_namespace.gen_fn_signatures());
self.global_sub_modules.iter().for_each(|(name, m)| {
signatures.extend(m.gen_fn_signatures().map(|f| format!("{}::{}", name, f)))
});
if include_packages {
signatures.extend(self.packages.gen_fn_signatures());
}
signatures
}
/// Provide a callback that will be invoked before each variable access.
///
/// ## Return Value of Callback

View File

@@ -187,7 +187,7 @@ macro_rules! def_register {
{
#[inline]
fn register_fn(&mut self, name: &str, f: FN) -> &mut Self {
self.global_namespace.set_fn(name, FnNamespace::Global, FnAccess::Public,
self.global_namespace.set_fn(name, FnNamespace::Global, FnAccess::Public, None,
&[$(map_type_id::<$par>()),*],
CallableFunction::$abi(make_func!(f : map_dynamic ; $($par => $let => $clone => $arg),*))
);
@@ -202,7 +202,7 @@ macro_rules! def_register {
{
#[inline]
fn register_result_fn(&mut self, name: &str, f: FN) -> &mut Self {
self.global_namespace.set_fn(name, FnNamespace::Global, FnAccess::Public,
self.global_namespace.set_fn(name, FnNamespace::Global, FnAccess::Public, None,
&[$(map_type_id::<$par>()),*],
CallableFunction::$abi(make_func!(f : map_result ; $($par => $let => $clone => $arg),*))
);

View File

@@ -79,7 +79,31 @@ pub struct FuncInfo {
/// Number of parameters.
pub params: usize,
/// Parameter types (if applicable).
pub types: Option<StaticVec<TypeId>>,
pub param_types: Option<StaticVec<TypeId>>,
/// Parameter names (if available).
pub param_names: Option<StaticVec<ImmutableString>>,
}
impl FuncInfo {
/// Generate a signature of the function.
pub fn gen_signature(&self) -> String {
let mut sig = format!("{}(", self.name);
if let Some(ref names) = self.param_names {
let params: Vec<_> = names.iter().map(ImmutableString::to_string).collect();
sig.push_str(&params.join(", "));
} else {
for x in 0..self.params {
sig.push_str("_");
if x < self.params - 1 {
sig.push_str(", ");
}
}
}
sig.push_str(")");
sig
}
}
/// A module which may contain variables, sub-modules, external Rust functions,
@@ -230,6 +254,14 @@ impl Module {
self.indexed
}
/// Generate signatures for all the functions in the module.
pub fn gen_fn_signatures<'a>(&'a self) -> impl Iterator<Item = String> + 'a {
self.functions
.values()
.filter(|FuncInfo { access, .. }| !access.is_private())
.map(FuncInfo::gen_signature)
}
/// Does a variable exist in the module?
///
/// # Example
@@ -329,7 +361,8 @@ impl Module {
namespace: FnNamespace::Internal,
access: fn_def.access,
params: num_params,
types: None,
param_types: None,
param_names: Some(fn_def.params.clone()),
func: fn_def.into(),
},
);
@@ -450,6 +483,17 @@ impl Module {
}
}
/// Update the parameter names and types in a registered function.
///
/// The [`u64`] hash is calculated either by the function [`crate::calc_native_fn_hash`] or
/// the function [`crate::calc_script_fn_hash`].
pub fn update_fn_param_names(&mut self, hash_fn: u64, arg_names: &[&str]) -> &mut Self {
if let Some(f) = self.functions.get_mut(&hash_fn) {
f.param_names = Some(arg_names.iter().map(|&n| n.into()).collect());
}
self
}
/// Set a Rust function into the module, returning a hash key.
///
/// If there is an existing Rust function of the same hash, it is replaced.
@@ -462,6 +506,7 @@ impl Module {
name: impl Into<String>,
namespace: FnNamespace,
access: FnAccess,
arg_names: Option<&[&str]>,
arg_types: &[TypeId],
func: CallableFunction,
) -> u64 {
@@ -488,7 +533,8 @@ impl Module {
namespace,
access,
params: params.len(),
types: Some(params),
param_types: Some(params),
param_names: arg_names.map(|p| p.iter().map(|&v| v.into()).collect()),
func: func.into(),
},
);
@@ -576,6 +622,7 @@ impl Module {
name,
namespace,
access,
None,
arg_types,
CallableFunction::from_method(Box::new(f)),
)
@@ -606,6 +653,7 @@ impl Module {
name,
FnNamespace::Internal,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_pure(Box::new(f)),
)
@@ -638,6 +686,7 @@ impl Module {
name,
FnNamespace::Internal,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_pure(Box::new(f)),
)
@@ -673,6 +722,7 @@ impl Module {
name,
namespace,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_method(Box::new(f)),
)
@@ -738,6 +788,7 @@ impl Module {
name,
FnNamespace::Internal,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_pure(Box::new(f)),
)
@@ -780,6 +831,7 @@ impl Module {
name,
namespace,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_method(Box::new(f)),
)
@@ -900,6 +952,7 @@ impl Module {
name,
FnNamespace::Internal,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_pure(Box::new(f)),
)
@@ -948,6 +1001,7 @@ impl Module {
name,
namespace,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_method(Box::new(f)),
)
@@ -1008,6 +1062,7 @@ impl Module {
crate::engine::FN_IDX_SET,
FnNamespace::Internal,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_method(Box::new(f)),
)
@@ -1100,6 +1155,7 @@ impl Module {
name,
FnNamespace::Internal,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_pure(Box::new(f)),
)
@@ -1155,6 +1211,7 @@ impl Module {
name,
namespace,
FnAccess::Public,
None,
&arg_types,
CallableFunction::from_method(Box::new(f)),
)
@@ -1569,7 +1626,7 @@ impl Module {
name,
namespace,
params,
types,
param_types: types,
func,
..
},

View File

@@ -48,7 +48,8 @@ macro_rules! reg_range {
($lib:expr, $x:expr, $( $y:ty ),*) => (
$(
$lib.set_iterator::<Range<$y>>();
$lib.set_fn_2($x, get_range::<$y>);
let hash = $lib.set_fn_2($x, get_range::<$y>);
$lib.update_fn_param_names(hash, &[concat!("from: ", stringify!($y)), concat!("to: ", stringify!($y))]);
)*
)
}
@@ -59,14 +60,16 @@ macro_rules! reg_step {
($lib:expr, $x:expr, $( $y:ty ),*) => (
$(
$lib.set_iterator::<StepRange<$y>>();
$lib.set_fn_3($x, get_step_range::<$y>);
let hash = $lib.set_fn_3($x, get_step_range::<$y>);
$lib.update_fn_param_names(hash, &[concat!("from: ", stringify!($y)), concat!("to: ", stringify!($y)), concat!("step: ", stringify!($y))]);
)*
)
}
def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
lib.set_iterator::<Range<INT>>();
lib.set_fn_2("range", get_range::<INT>);
let hash = lib.set_fn_2("range", get_range::<INT>);
lib.update_fn_param_names(hash, &["from: INT", "to: INT"]);
#[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))]
@@ -79,7 +82,8 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
}
lib.set_iterator::<StepRange<INT>>();
lib.set_fn_3("range", get_step_range::<INT>);
let hash = lib.set_fn_3("range", get_step_range::<INT>);
lib.update_fn_param_names(hash, &["from: INT", "to: INT", "step: INT"]);
#[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))]

View File

@@ -87,6 +87,15 @@ impl PackagesCollection {
.as_ref()
.and_then(|x| x.iter().find_map(|p| p.get_iter(id)))
}
/// Get an iterator over all the packages in the [`PackagesCollection`].
pub(crate) fn iter(&self) -> impl Iterator<Item = &PackageLibrary> {
self.0.iter().flat_map(|p| p.iter())
}
/// Generate signatures for all the functions in the [`PackagesCollection`].
pub fn gen_fn_signatures<'a>(&'a self) -> impl Iterator<Item = String> + 'a {
self.iter().flat_map(|m| m.gen_fn_signatures())
}
}
/// Macro that makes it easy to define a _package_ (which is basically a shared module)

View File

@@ -33,6 +33,9 @@ pub trait PluginFunction {
/// Convert a plugin function into a boxed trait object.
fn clone_boxed(&self) -> Box<dyn PluginFunction>;
/// Return a boxed slice of the names of the function's parameters.
fn input_names(&self) -> Box<[&'static str]>;
/// Return a boxed slice of type ID's of the function's parameters.
fn input_types(&self) -> Box<[TypeId]>;
}

View File

@@ -2,7 +2,7 @@
use crate::engine::{
KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY,
KEYWORD_IS_DEF_FN, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_THIS, KEYWORD_TYPE_OF,
KEYWORD_PRINT, KEYWORD_THIS, KEYWORD_TYPE_OF,
};
use crate::stdlib::{
borrow::Cow,
@@ -538,11 +538,7 @@ impl Token {
| "async" | "await" | "yield" => Reserved(syntax.into()),
KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR
| KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_IS_DEF_VAR
| KEYWORD_IS_DEF_FN | KEYWORD_THIS => Reserved(syntax.into()),
#[cfg(not(feature = "no_closure"))]
crate::engine::KEYWORD_IS_SHARED => Reserved(syntax.into()),
| KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_THIS => Reserved(syntax.into()),
_ => return None,
})
@@ -1513,12 +1509,8 @@ fn get_identifier(
#[inline(always)]
pub fn is_keyword_function(name: &str) -> bool {
match name {
#[cfg(not(feature = "no_closure"))]
crate::engine::KEYWORD_IS_SHARED => true,
KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR
| KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_IS_DEF_VAR | KEYWORD_IS_DEF_FN => {
true
}
| KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY => true,
_ => false,
}
}
@@ -1528,8 +1520,7 @@ pub fn is_keyword_function(name: &str) -> bool {
#[inline(always)]
pub fn can_override_keyword(name: &str) -> bool {
match name {
KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR
| KEYWORD_IS_DEF_VAR | KEYWORD_IS_DEF_FN => true,
KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR => true,
_ => false,
}
}