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

@ -10,6 +10,9 @@ It also allows exposing selected module functions (usually methods) to the globa
This is very convenient when encapsulating the API of a custom Rust type into a module while having methods
and iterators registered on the custom type work normally.
A new `gen_fn_signatures` API enables enumerating the registered functions of an `Engine` for documentation purposes.
It also prepares the way for a future reflection API.
Bug fixes
---------
@ -19,6 +22,7 @@ Breaking changes
----------------
* `Module::set_fn`, `Module::set_raw_fn` and `Module::set_fn_XXX_mut` all take an additional parameter of `FnNamespace`.
* `Module::set_fn` takes a further parameter with a list of parameter names and types, if any.
* `Module::get_sub_module_mut` is removed.
* `begin`, `end`, `unless` are now reserved keywords.
* `EvalPackage` is removed in favor of `Engine::disable_symbol`.
@ -26,13 +30,15 @@ Breaking changes
New features
------------
* `switch` statement.
* `do ... while` and `do ... until` statement.
* `Engine::register_module` to register a module as a sub-module in the global namespace.
* `set_exported_global_fn!` macro to register a plugin function and expose it to the global namespace.
* New `switch` statement.
* New `do ... while` and `do ... until` statements.
* New `Engine::gen_fn_signatures`, `Module::gen_fn_signatures` and `PackagesCollection::gen_fn_signatures` to generate a list of signatures for functions registered.
* New `Engine::register_module` to register a module as a sub-module in the global namespace.
* New `set_exported_global_fn!` macro to register a plugin function and expose it to the global namespace.
* `Module::set_fn_XXX_mut` can expose a module function to the global namespace. This is convenient when registering an API for a custom type.
* `Module::set_getter_fn`, `Module::set_setter_fn`, `Module::set_indexer_get_fn`, `Module::set_indexer_set_fn` all expose the function to the global namespace by default. This is convenient when registering an API for a custom type.
* `#[rhai_fn(global)]` and `#[rhai_fn(internal)]` attributes to determine whether a function defined in a plugin module should be exposed to the global namespace. This is convenient when defining an API for a custom type.
* New `Module::update_fn_param_names` to update a module function's parameter names and types.
* New `#[rhai_fn(global)]` and `#[rhai_fn(internal)]` attributes to determine whether a function defined in a plugin module should be exposed to the global namespace. This is convenient when defining an API for a custom type.
Enhancements
------------

View File

@ -12,7 +12,7 @@ use std::format;
use std::borrow::Cow;
use quote::{quote, quote_spanned};
use quote::{quote, quote_spanned, ToTokens};
use syn::{
parse::{Parse, ParseStream, Parser},
spanned::Spanned,
@ -83,6 +83,10 @@ pub(crate) fn flatten_type_groups(ty: &syn::Type) -> &syn::Type {
}
}
pub(crate) fn print_type(ty: &syn::Type) -> String {
ty.to_token_stream().to_string().replace("& ", "&")
}
#[derive(Debug, Default)]
pub(crate) struct ExportedFnParams {
pub name: Option<Vec<String>>,
@ -576,6 +580,7 @@ impl ExportedFn {
syn::Ident::new(&format!("rhai_fn_{}", self.name()), self.name().span());
let impl_block = self.generate_impl("Token");
let callable_block = self.generate_callable("Token");
let input_names_block = self.generate_input_names("Token");
let input_types_block = self.generate_input_types("Token");
let dyn_result_fn_block = self.generate_dynamic_fn();
quote! {
@ -585,6 +590,7 @@ impl ExportedFn {
struct Token();
#impl_block
#callable_block
#input_names_block
#input_types_block
#dyn_result_fn_block
}
@ -655,6 +661,19 @@ impl ExportedFn {
}
}
pub fn generate_input_names(&self, on_type_name: &str) -> proc_macro2::TokenStream {
let token_name: syn::Ident = syn::Ident::new(on_type_name, self.name().span());
let input_names_fn_name: syn::Ident = syn::Ident::new(
format!("{}_input_names", on_type_name.to_lowercase()).as_str(),
self.name().span(),
);
quote! {
pub fn #input_names_fn_name() -> Box<[&'static str]> {
#token_name().input_names()
}
}
}
pub fn generate_input_types(&self, on_type_name: &str) -> proc_macro2::TokenStream {
let token_name: syn::Ident = syn::Ident::new(on_type_name, self.name().span());
let input_types_fn_name: syn::Ident = syn::Ident::new(
@ -680,6 +699,7 @@ impl ExportedFn {
let mut unpack_stmts: Vec<syn::Stmt> = Vec::new();
let mut unpack_exprs: Vec<syn::Expr> = Vec::new();
let mut input_type_names: Vec<String> = Vec::new();
let mut input_type_exprs: Vec<syn::Expr> = Vec::new();
let skip_first_arg;
@ -693,8 +713,9 @@ impl ExportedFn {
let first_arg = self.arg_list().next().unwrap();
let var = syn::Ident::new("arg0", proc_macro2::Span::call_site());
match first_arg {
syn::FnArg::Typed(pattern) => {
let arg_type = match flatten_type_groups(pattern.ty.as_ref()) {
syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => {
let arg_name = format!("{}: {}", pat.to_token_stream(), print_type(ty));
let arg_type = match flatten_type_groups(ty.as_ref()) {
syn::Type::Reference(syn::TypeReference { ref elem, .. }) => elem.as_ref(),
p => p,
};
@ -706,6 +727,7 @@ impl ExportedFn {
})
.unwrap(),
);
input_type_names.push(arg_name);
input_type_exprs.push(
syn::parse2::<syn::Expr>(quote_spanned!(
arg_type.span()=> TypeId::of::<#arg_type>()
@ -731,9 +753,10 @@ impl ExportedFn {
let is_string;
let is_ref;
match arg {
syn::FnArg::Typed(pattern) => {
let arg_type = pattern.ty.as_ref();
let downcast_span = match flatten_type_groups(pattern.ty.as_ref()) {
syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => {
let arg_name = format!("{}: {}", pat.to_token_stream(), print_type(ty));
let arg_type = ty.as_ref();
let downcast_span = match flatten_type_groups(arg_type) {
syn::Type::Reference(syn::TypeReference {
mutability: None,
ref elem,
@ -767,6 +790,7 @@ impl ExportedFn {
})
.unwrap(),
);
input_type_names.push(arg_name);
if !is_string {
input_type_exprs.push(
syn::parse2::<syn::Expr>(quote_spanned!(
@ -837,6 +861,9 @@ impl ExportedFn {
fn is_method_call(&self) -> bool { #is_method_call }
fn is_variadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(#type_name()) }
fn input_names(&self) -> Box<[&'static str]> {
new_vec![#(#input_type_names),*].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![#(#input_type_exprs),*].into_boxed_slice()
}

View File

@ -340,6 +340,7 @@ pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream
let gen_mod_path = crate::register::generated_module_path(&rust_modpath);
let tokens = quote! {
#module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public,
Some(#gen_mod_path::token_input_names().as_ref()),
#gen_mod_path::token_input_types().as_ref(),
#gen_mod_path::token_callable());
};
@ -381,6 +382,7 @@ pub fn set_exported_global_fn(args: proc_macro::TokenStream) -> proc_macro::Toke
let gen_mod_path = crate::register::generated_module_path(&rust_modpath);
let tokens = quote! {
#module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public,
Some(#gen_mod_path::token_input_names().as_ref()),
#gen_mod_path::token_input_types().as_ref(),
#gen_mod_path::token_callable());
};

View File

@ -3,8 +3,9 @@ use std::collections::HashMap;
use quote::{quote, ToTokens};
use crate::attrs::ExportScope;
use crate::function::flatten_type_groups;
use crate::function::{ExportedFn, FnNamespaceAccess, FnSpecialAccess};
use crate::function::{
flatten_type_groups, print_type, ExportedFn, FnNamespaceAccess, FnSpecialAccess,
};
use crate::module::Module;
pub(crate) type ExportedConst = (String, Box<syn::Type>, syn::Expr);
@ -82,6 +83,16 @@ pub(crate) fn generate_body(
let reg_names = function.exported_names();
let mut namespace = FnNamespaceAccess::Internal;
let fn_input_names: Vec<String> = function
.arg_list()
.map(|fnarg| match fnarg {
syn::FnArg::Receiver(_) => panic!("internal error: receiver fn outside impl!?"),
syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => {
format!("{}: {}", pat.to_token_stream(), print_type(ty))
}
})
.collect();
let fn_input_types: Vec<syn::Expr> = function
.arg_list()
.map(|fnarg| match fnarg {
@ -117,6 +128,7 @@ pub(crate) fn generate_body(
},
t => t.clone(),
};
syn::parse2::<syn::Expr>(quote! {
core::any::TypeId::of::<#arg_type>()})
.unwrap()
@ -138,7 +150,8 @@ pub(crate) fn generate_body(
);
set_fn_stmts.push(
syn::parse2::<syn::Stmt>(quote! {
m.set_fn(#fn_literal, FnNamespace::#ns_str, FnAccess::Public, &[#(#fn_input_types),*],
m.set_fn(#fn_literal, FnNamespace::#ns_str, FnAccess::Public,
Some(&[#(#fn_input_names),*]), &[#(#fn_input_types),*],
#fn_token_name().into());
})
.unwrap(),
@ -151,6 +164,7 @@ pub(crate) fn generate_body(
});
gen_fn_tokens.push(function.generate_impl(&fn_token_name.to_string()));
gen_fn_tokens.push(function.generate_callable(&fn_token_name.to_string()));
gen_fn_tokens.push(function.generate_input_names(&fn_token_name.to_string()));
gen_fn_tokens.push(function.generate_input_types(&fn_token_name.to_string()));
}
@ -195,9 +209,7 @@ pub(crate) fn check_rename_collisions(fns: &Vec<ExportedFn>) -> Result<(), syn::
.fold(name.to_string(), |mut argstr, fnarg| {
let type_string: String = match fnarg {
syn::FnArg::Receiver(_) => unimplemented!("receiver rhai_fns not implemented"),
syn::FnArg::Typed(syn::PatType { ref ty, .. }) => {
ty.as_ref().to_token_stream().to_string()
}
syn::FnArg::Typed(syn::PatType { ref ty, .. }) => print_type(ty),
};
argstr.push('.');
argstr.push_str(&type_string);

View File

@ -286,6 +286,9 @@ mod generate_tests {
fn is_method_call(&self) -> bool { false }
fn is_variadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
fn input_names(&self) -> Box<[&'static str]> {
new_vec![].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![].into_boxed_slice()
}
@ -293,6 +296,9 @@ mod generate_tests {
pub fn token_callable() -> CallableFunction {
Token().into()
}
pub fn token_input_names() -> Box<[&'static str]> {
Token().input_names()
}
pub fn token_input_types() -> Box<[TypeId]> {
Token().input_types()
}
@ -328,6 +334,9 @@ mod generate_tests {
fn is_method_call(&self) -> bool { false }
fn is_variadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: usize"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<usize>()].into_boxed_slice()
}
@ -335,6 +344,9 @@ mod generate_tests {
pub fn token_callable() -> CallableFunction {
Token().into()
}
pub fn token_input_names() -> Box<[&'static str]> {
Token().input_names()
}
pub fn token_input_types() -> Box<[TypeId]> {
Token().input_types()
}
@ -370,6 +382,9 @@ mod generate_tests {
fn is_method_call(&self) -> bool { false }
fn is_variadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: usize"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<usize>()].into_boxed_slice()
}
@ -377,6 +392,9 @@ mod generate_tests {
pub fn token_callable() -> CallableFunction {
Token().into()
}
pub fn token_input_names() -> Box<[&'static str]> {
Token().input_names()
}
pub fn token_input_types() -> Box<[TypeId]> {
Token().input_types()
}
@ -414,6 +432,9 @@ mod generate_tests {
fn is_method_call(&self) -> bool { false }
fn is_variadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
fn input_names(&self) -> Box<[&'static str]> {
new_vec![].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![].into_boxed_slice()
}
@ -421,6 +442,9 @@ mod generate_tests {
pub fn token_callable() -> CallableFunction {
Token().into()
}
pub fn token_input_names() -> Box<[&'static str]> {
Token().input_names()
}
pub fn token_input_types() -> Box<[TypeId]> {
Token().input_types()
}
@ -452,6 +476,9 @@ mod generate_tests {
fn is_method_call(&self) -> bool { false }
fn is_variadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(MyType()) }
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: usize"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<usize>()].into_boxed_slice()
}
@ -485,6 +512,9 @@ mod generate_tests {
fn is_method_call(&self) -> bool { false }
fn is_variadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: usize", "y: usize"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<usize>(),
TypeId::of::<usize>()].into_boxed_slice()
@ -493,6 +523,9 @@ mod generate_tests {
pub fn token_callable() -> CallableFunction {
Token().into()
}
pub fn token_input_names() -> Box<[&'static str]> {
Token().input_names()
}
pub fn token_input_types() -> Box<[TypeId]> {
Token().input_types()
}
@ -529,6 +562,9 @@ mod generate_tests {
fn is_method_call(&self) -> bool { true }
fn is_variadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: &mut usize", "y: usize"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<usize>(),
TypeId::of::<usize>()].into_boxed_slice()
@ -537,6 +573,9 @@ mod generate_tests {
pub fn token_callable() -> CallableFunction {
Token().into()
}
pub fn token_input_names() -> Box<[&'static str]> {
Token().input_names()
}
pub fn token_input_types() -> Box<[TypeId]> {
Token().input_types()
}
@ -573,6 +612,9 @@ mod generate_tests {
fn is_method_call(&self) -> bool { false }
fn is_variadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["message: &str"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<ImmutableString>()].into_boxed_slice()
}
@ -580,6 +622,9 @@ mod generate_tests {
pub fn token_callable() -> CallableFunction {
Token().into()
}
pub fn token_input_names() -> Box<[&'static str]> {
Token().input_names()
}
pub fn token_input_types() -> Box<[TypeId]> {
Token().input_types()
}

View File

@ -297,7 +297,7 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, &[],
m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, Some(&[]), &[],
get_mystic_number_token().into());
if flatten {} else {}
}
@ -315,6 +315,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(get_mystic_number_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec![].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![].into_boxed_slice()
}
@ -322,6 +325,9 @@ mod generate_tests {
pub fn get_mystic_number_token_callable() -> CallableFunction {
get_mystic_number_token().into()
}
pub fn get_mystic_number_token_input_names() -> Box<[&'static str]> {
get_mystic_number_token().input_names()
}
pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> {
get_mystic_number_token().input_types()
}
@ -359,7 +365,7 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("add_one_to", FnNamespace::Global, FnAccess::Public, &[core::any::TypeId::of::<INT>()],
m.set_fn("add_one_to", FnNamespace::Global, FnAccess::Public, Some(&["x: INT"]), &[core::any::TypeId::of::<INT>()],
add_one_to_token().into());
if flatten {} else {}
}
@ -378,6 +384,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(add_one_to_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: INT"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<INT>()].into_boxed_slice()
}
@ -385,6 +394,9 @@ mod generate_tests {
pub fn add_one_to_token_callable() -> CallableFunction {
add_one_to_token().into()
}
pub fn add_one_to_token_input_names() -> Box<[&'static str]> {
add_one_to_token().input_names()
}
pub fn add_one_to_token_input_types() -> Box<[TypeId]> {
add_one_to_token().input_types()
}
@ -421,7 +433,7 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("add_one_to", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<INT>()],
m.set_fn("add_one_to", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT"]), &[core::any::TypeId::of::<INT>()],
add_one_to_token().into());
if flatten {} else {}
}
@ -440,6 +452,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(add_one_to_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: INT"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<INT>()].into_boxed_slice()
}
@ -447,6 +462,9 @@ mod generate_tests {
pub fn add_one_to_token_callable() -> CallableFunction {
add_one_to_token().into()
}
pub fn add_one_to_token_input_names() -> Box<[&'static str]> {
add_one_to_token().input_names()
}
pub fn add_one_to_token_input_types() -> Box<[TypeId]> {
add_one_to_token().input_types()
}
@ -494,10 +512,10 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<INT>()],
m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT"]), &[core::any::TypeId::of::<INT>()],
add_one_to_token().into());
m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<INT>(),
core::any::TypeId::of::<INT>()],
m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]),
&[core::any::TypeId::of::<INT>(), core::any::TypeId::of::<INT>()],
add_n_to_token().into());
if flatten {} else {}
}
@ -516,6 +534,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(add_one_to_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: INT"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<INT>()].into_boxed_slice()
}
@ -523,6 +544,9 @@ mod generate_tests {
pub fn add_one_to_token_callable() -> CallableFunction {
add_one_to_token().into()
}
pub fn add_one_to_token_input_names() -> Box<[&'static str]> {
add_one_to_token().input_names()
}
pub fn add_one_to_token_input_types() -> Box<[TypeId]> {
add_one_to_token().input_types()
}
@ -543,6 +567,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(add_n_to_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: INT", "y: INT"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<INT>(),
TypeId::of::<INT>()].into_boxed_slice()
@ -551,6 +578,9 @@ mod generate_tests {
pub fn add_n_to_token_callable() -> CallableFunction {
add_n_to_token().into()
}
pub fn add_n_to_token_input_names() -> Box<[&'static str]> {
add_n_to_token().input_names()
}
pub fn add_n_to_token_input_types() -> Box<[TypeId]> {
add_n_to_token().input_types()
}
@ -587,8 +617,8 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<INT>(),
core::any::TypeId::of::<INT>()],
m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]),
&[core::any::TypeId::of::<INT>(), core::any::TypeId::of::<INT>()],
add_together_token().into());
if flatten {} else {}
}
@ -608,6 +638,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(add_together_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: INT", "y: INT"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<INT>(),
TypeId::of::<INT>()].into_boxed_slice()
@ -616,6 +649,9 @@ mod generate_tests {
pub fn add_together_token_callable() -> CallableFunction {
add_together_token().into()
}
pub fn add_together_token_input_names() -> Box<[&'static str]> {
add_together_token().input_names()
}
pub fn add_together_token_input_types() -> Box<[TypeId]> {
add_together_token().input_types()
}
@ -653,14 +689,14 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("add", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<INT>(),
core::any::TypeId::of::<INT>()],
m.set_fn("add", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]),
&[core::any::TypeId::of::<INT>(), core::any::TypeId::of::<INT>()],
add_together_token().into());
m.set_fn("+", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<INT>(),
core::any::TypeId::of::<INT>()],
m.set_fn("+", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]),
&[core::any::TypeId::of::<INT>(), core::any::TypeId::of::<INT>()],
add_together_token().into());
m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<INT>(),
core::any::TypeId::of::<INT>()],
m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]),
&[core::any::TypeId::of::<INT>(), core::any::TypeId::of::<INT>()],
add_together_token().into());
if flatten {} else {}
}
@ -680,6 +716,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(add_together_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: INT", "y: INT"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<INT>(),
TypeId::of::<INT>()].into_boxed_slice()
@ -688,6 +727,9 @@ mod generate_tests {
pub fn add_together_token_callable() -> CallableFunction {
add_together_token().into()
}
pub fn add_together_token_input_names() -> Box<[&'static str]> {
add_together_token().input_names()
}
pub fn add_together_token_input_types() -> Box<[TypeId]> {
add_together_token().input_types()
}
@ -906,7 +948,7 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, &[],
m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, Some(&[]), &[],
get_mystic_number_token().into());
if flatten {} else {}
}
@ -924,6 +966,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(get_mystic_number_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec![].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![].into_boxed_slice()
}
@ -931,6 +976,9 @@ mod generate_tests {
pub fn get_mystic_number_token_callable() -> CallableFunction {
get_mystic_number_token().into()
}
pub fn get_mystic_number_token_input_names() -> Box<[&'static str]> {
get_mystic_number_token().input_names()
}
pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> {
get_mystic_number_token().input_types()
}
@ -999,7 +1047,7 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("print_out_to", FnNamespace::Internal, FnAccess::Public,
&[core::any::TypeId::of::<ImmutableString>()],
Some(&["x: &str"]), &[core::any::TypeId::of::<ImmutableString>()],
print_out_to_token().into());
if flatten {} else {}
}
@ -1018,6 +1066,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(print_out_to_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: &str"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<ImmutableString>()].into_boxed_slice()
}
@ -1025,6 +1076,9 @@ mod generate_tests {
pub fn print_out_to_token_callable() -> CallableFunction {
print_out_to_token().into()
}
pub fn print_out_to_token_input_names() -> Box<[&'static str]> {
print_out_to_token().input_names()
}
pub fn print_out_to_token_input_types() -> Box<[TypeId]> {
print_out_to_token().input_types()
}
@ -1062,7 +1116,7 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("print_out_to", FnNamespace::Internal, FnAccess::Public,
&[core::any::TypeId::of::<ImmutableString>()],
Some(&["x: String"]), &[core::any::TypeId::of::<ImmutableString>()],
print_out_to_token().into());
if flatten {} else {}
}
@ -1081,6 +1135,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(print_out_to_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: String"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<ImmutableString>()].into_boxed_slice()
}
@ -1088,6 +1145,9 @@ mod generate_tests {
pub fn print_out_to_token_callable() -> CallableFunction {
print_out_to_token().into()
}
pub fn print_out_to_token_input_names() -> Box<[&'static str]> {
print_out_to_token().input_names()
}
pub fn print_out_to_token_input_types() -> Box<[TypeId]> {
print_out_to_token().input_types()
}
@ -1125,7 +1185,7 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("increment", FnNamespace::Internal, FnAccess::Public,
&[core::any::TypeId::of::<FLOAT>()],
Some(&["x: &mut FLOAT"]), &[core::any::TypeId::of::<FLOAT>()],
increment_token().into());
if flatten {} else {}
}
@ -1144,6 +1204,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(increment_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: &mut FLOAT"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<FLOAT>()].into_boxed_slice()
}
@ -1151,6 +1214,9 @@ mod generate_tests {
pub fn increment_token_callable() -> CallableFunction {
increment_token().into()
}
pub fn increment_token_input_names() -> Box<[&'static str]> {
increment_token().input_names()
}
pub fn increment_token_input_types() -> Box<[TypeId]> {
increment_token().input_types()
}
@ -1191,7 +1257,7 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("increment", FnNamespace::Internal, FnAccess::Public,
&[core::any::TypeId::of::<FLOAT>()],
Some(&["x: &mut FLOAT"]), &[core::any::TypeId::of::<FLOAT>()],
increment_token().into());
if flatten {} else {}
}
@ -1210,6 +1276,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(increment_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: &mut FLOAT"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<FLOAT>()].into_boxed_slice()
}
@ -1217,6 +1286,9 @@ mod generate_tests {
pub fn increment_token_callable() -> CallableFunction {
increment_token().into()
}
pub fn increment_token_input_names() -> Box<[&'static str]> {
increment_token().input_names()
}
pub fn increment_token_input_types() -> Box<[TypeId]> {
increment_token().input_types()
}
@ -1278,7 +1350,7 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("increment", FnNamespace::Internal, FnAccess::Public,
&[core::any::TypeId::of::<FLOAT>()],
Some(&["x: &mut FLOAT"]), &[core::any::TypeId::of::<FLOAT>()],
increment_token().into());
if flatten {} else {}
}
@ -1297,6 +1369,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(increment_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: &mut FLOAT"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<FLOAT>()].into_boxed_slice()
}
@ -1304,6 +1379,9 @@ mod generate_tests {
pub fn increment_token_callable() -> CallableFunction {
increment_token().into()
}
pub fn increment_token_input_names() -> Box<[&'static str]> {
increment_token().input_names()
}
pub fn increment_token_input_types() -> Box<[TypeId]> {
increment_token().input_types()
}
@ -1363,7 +1441,7 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<u64>()],
m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64"]), &[core::any::TypeId::of::<u64>()],
int_foo_token().into());
if flatten {} else {}
}
@ -1382,6 +1460,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(int_foo_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: &mut u64"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<u64>()].into_boxed_slice()
}
@ -1389,6 +1470,9 @@ mod generate_tests {
pub fn int_foo_token_callable() -> CallableFunction {
int_foo_token().into()
}
pub fn int_foo_token_input_names() -> Box<[&'static str]> {
int_foo_token().input_names()
}
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
int_foo_token().input_types()
}
@ -1426,9 +1510,9 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("square", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<u64>()],
m.set_fn("square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64"]), &[core::any::TypeId::of::<u64>()],
int_foo_token().into());
m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<u64>()],
m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64"]), &[core::any::TypeId::of::<u64>()],
int_foo_token().into());
if flatten {} else {}
}
@ -1447,6 +1531,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(int_foo_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: &mut u64"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<u64>()].into_boxed_slice()
}
@ -1454,6 +1541,9 @@ mod generate_tests {
pub fn int_foo_token_callable() -> CallableFunction {
int_foo_token().into()
}
pub fn int_foo_token_input_names() -> Box<[&'static str]> {
int_foo_token().input_names()
}
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
int_foo_token().input_types()
}
@ -1491,9 +1581,8 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public,
&[core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<u64>()],
m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64"]),
&[core::any::TypeId::of::<u64>(), core::any::TypeId::of::<u64>()],
int_foo_token().into());
if flatten {} else {}
}
@ -1513,6 +1602,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(int_foo_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: &mut u64", "y: u64"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<u64>(), TypeId::of::<u64>()].into_boxed_slice()
}
@ -1520,6 +1612,9 @@ mod generate_tests {
pub fn int_foo_token_callable() -> CallableFunction {
int_foo_token().into()
}
pub fn int_foo_token_input_names() -> Box<[&'static str]> {
int_foo_token().input_names()
}
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
int_foo_token().input_types()
}
@ -1557,13 +1652,11 @@ mod generate_tests {
}
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("set_sq", FnNamespace::Internal, FnAccess::Public,
&[core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<u64>()],
m.set_fn("set_sq", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64"]),
&[core::any::TypeId::of::<u64>(), core::any::TypeId::of::<u64>()],
int_foo_token().into());
m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public,
&[core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<u64>()],
m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64"]),
&[core::any::TypeId::of::<u64>(), core::any::TypeId::of::<u64>()],
int_foo_token().into());
if flatten {} else {}
}
@ -1583,6 +1676,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(int_foo_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: &mut u64", "y: u64"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<u64>(), TypeId::of::<u64>()].into_boxed_slice()
}
@ -1590,6 +1686,9 @@ mod generate_tests {
pub fn int_foo_token_callable() -> CallableFunction {
int_foo_token().into()
}
pub fn int_foo_token_input_names() -> Box<[&'static str]> {
int_foo_token().input_names()
}
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
int_foo_token().input_types()
}
@ -1628,6 +1727,7 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("index$get$", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut MyCollection", "i: u64"]),
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>()],
get_by_index_token().into());
@ -1649,6 +1749,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(get_by_index_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: &mut MyCollection", "i: u64"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<MyCollection>(),
TypeId::of::<u64>()].into_boxed_slice()
@ -1657,6 +1760,9 @@ mod generate_tests {
pub fn get_by_index_token_callable() -> CallableFunction {
get_by_index_token().into()
}
pub fn get_by_index_token_input_names() -> Box<[&'static str]> {
get_by_index_token().input_names()
}
pub fn get_by_index_token_input_types() -> Box<[TypeId]> {
get_by_index_token().input_types()
}
@ -1695,10 +1801,12 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("get", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut MyCollection", "i: u64"]),
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>()],
get_by_index_token().into());
m.set_fn("index$get$", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut MyCollection", "i: u64"]),
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>()],
get_by_index_token().into());
@ -1720,6 +1828,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(get_by_index_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: &mut MyCollection", "i: u64"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<MyCollection>(),
TypeId::of::<u64>()].into_boxed_slice()
@ -1728,6 +1839,9 @@ mod generate_tests {
pub fn get_by_index_token_callable() -> CallableFunction {
get_by_index_token().into()
}
pub fn get_by_index_token_input_names() -> Box<[&'static str]> {
get_by_index_token().input_names()
}
pub fn get_by_index_token_input_types() -> Box<[TypeId]> {
get_by_index_token().input_types()
}
@ -1766,6 +1880,7 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("index$set$", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT"]),
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<FLOAT>()],
@ -1789,6 +1904,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(set_by_index_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: &mut MyCollection", "i: u64", "item: FLOAT"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<MyCollection>(),
TypeId::of::<u64>(),
@ -1798,6 +1916,9 @@ mod generate_tests {
pub fn set_by_index_token_callable() -> CallableFunction {
set_by_index_token().into()
}
pub fn set_by_index_token_input_names() -> Box<[&'static str]> {
set_by_index_token().input_names()
}
pub fn set_by_index_token_input_types() -> Box<[TypeId]> {
set_by_index_token().input_types()
}
@ -1836,11 +1957,13 @@ mod generate_tests {
#[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("set", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT"]),
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<FLOAT>()],
set_by_index_token().into());
m.set_fn("index$set$", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT"]),
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<FLOAT>()],
@ -1864,6 +1987,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(set_by_index_token())
}
fn input_names(&self) -> Box<[&'static str]> {
new_vec!["x: &mut MyCollection", "i: u64", "item: FLOAT"].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<MyCollection>(),
TypeId::of::<u64>(),
@ -1873,6 +1999,9 @@ mod generate_tests {
pub fn set_by_index_token_callable() -> CallableFunction {
set_by_index_token().into()
}
pub fn set_by_index_token_input_names() -> Box<[&'static str]> {
set_by_index_token().input_names()
}
pub fn set_by_index_token_input_types() -> Box<[TypeId]> {
set_by_index_token().input_types()
}

View File

@ -9,8 +9,6 @@ Keywords List
| `false` | boolean false literal | | no | |
| `let` | variable declaration | | no | |
| `const` | constant declaration | | no | |
| `is_def_var` | is a variable declared? | | yes | yes |
| `is_shared` | is a value shared? | [`no_closure`] | yes | no |
| `if` | if statement | | no | |
| `else` | else block of if statement | | no | |
| `switch` | matching | | no | |
@ -35,7 +33,6 @@ Keywords List
| `call` | call a [function pointer] | | yes | no |
| `curry` | curry a [function pointer] | | yes | no |
| `this` | reference to base object for method call | [`no_function`] | no | |
| `is_def_fn` | is a scripted function defined? | [`no_function`] | yes | yes |
| `type_of` | get type name of value | | yes | yes |
| `print` | print value | | yes | yes |
| `debug` | print value in debug format | | yes | yes |

View File

@ -42,6 +42,7 @@ fn print_help() {
println!("help => print this help");
println!("quit, exit => quit");
println!("scope => print all variables in the scope");
println!("functions => print all functions defined");
println!("ast => print the last AST");
println!("astu => print the last raw, un-optimized AST");
println!(r"end a line with '\' to continue to the next line.");
@ -133,6 +134,18 @@ fn main() {
println!("{:#?}\n", &ast);
continue;
}
"functions" => {
// print a list of all registered functions
engine
.gen_fn_signatures(false)
.into_iter()
.for_each(|f| println!("{}", f));
main_ast
.iter_functions()
.for_each(|(_, _, _, _, f)| println!("{}", f));
println!();
continue;
}
_ => (),
}

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