Merge pull request #296 from schungx/master

gen_fn_signatures API.
This commit is contained in:
Stephen Chung 2020-11-22 17:59:43 +08:00 committed by GitHub
commit c18a6451f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 709 additions and 310 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 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. 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 Bug fixes
--------- ---------
@ -19,18 +22,23 @@ 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`, `Module::set_raw_fn` and `Module::set_fn_XXX_mut` all take an additional parameter of `FnNamespace`.
* `unless` is now a reserved keyword. * `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`.
New features New features
------------ ------------
* `switch` statement. * New `switch` statement.
* `do ... while` and `do ... until` statement. * New `do ... while` and `do ... until` statements.
* `Engine::register_module` to register a module as a sub-module in the global namespace. * New `Engine::gen_fn_signatures`, `Module::gen_fn_signatures` and `PackagesCollection::gen_fn_signatures` to generate a list of signatures for functions registered.
* `set_exported_global_fn!` macro to register a plugin function and expose it to the global namespace. * 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_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. * `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 Enhancements
------------ ------------

View File

@ -12,7 +12,7 @@ use std::format;
use std::borrow::Cow; use std::borrow::Cow;
use quote::{quote, quote_spanned}; use quote::{quote, quote_spanned, ToTokens};
use syn::{ use syn::{
parse::{Parse, ParseStream, Parser}, parse::{Parse, ParseStream, Parser},
spanned::Spanned, 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)] #[derive(Debug, Default)]
pub(crate) struct ExportedFnParams { pub(crate) struct ExportedFnParams {
pub name: Option<Vec<String>>, pub name: Option<Vec<String>>,
@ -576,6 +580,7 @@ impl ExportedFn {
syn::Ident::new(&format!("rhai_fn_{}", self.name()), self.name().span()); syn::Ident::new(&format!("rhai_fn_{}", self.name()), self.name().span());
let impl_block = self.generate_impl("Token"); let impl_block = self.generate_impl("Token");
let callable_block = self.generate_callable("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 input_types_block = self.generate_input_types("Token");
let dyn_result_fn_block = self.generate_dynamic_fn(); let dyn_result_fn_block = self.generate_dynamic_fn();
quote! { quote! {
@ -585,6 +590,7 @@ impl ExportedFn {
struct Token(); struct Token();
#impl_block #impl_block
#callable_block #callable_block
#input_names_block
#input_types_block #input_types_block
#dyn_result_fn_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 { 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 token_name: syn::Ident = syn::Ident::new(on_type_name, self.name().span());
let input_types_fn_name: syn::Ident = syn::Ident::new( 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_stmts: Vec<syn::Stmt> = Vec::new();
let mut unpack_exprs: Vec<syn::Expr> = 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 mut input_type_exprs: Vec<syn::Expr> = Vec::new();
let skip_first_arg; let skip_first_arg;
@ -693,8 +713,9 @@ impl ExportedFn {
let first_arg = self.arg_list().next().unwrap(); let first_arg = self.arg_list().next().unwrap();
let var = syn::Ident::new("arg0", proc_macro2::Span::call_site()); let var = syn::Ident::new("arg0", proc_macro2::Span::call_site());
match first_arg { match first_arg {
syn::FnArg::Typed(pattern) => { syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => {
let arg_type = match flatten_type_groups(pattern.ty.as_ref()) { 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(), syn::Type::Reference(syn::TypeReference { ref elem, .. }) => elem.as_ref(),
p => p, p => p,
}; };
@ -706,6 +727,7 @@ impl ExportedFn {
}) })
.unwrap(), .unwrap(),
); );
input_type_names.push(arg_name);
input_type_exprs.push( input_type_exprs.push(
syn::parse2::<syn::Expr>(quote_spanned!( syn::parse2::<syn::Expr>(quote_spanned!(
arg_type.span()=> TypeId::of::<#arg_type>() arg_type.span()=> TypeId::of::<#arg_type>()
@ -731,9 +753,10 @@ impl ExportedFn {
let is_string; let is_string;
let is_ref; let is_ref;
match arg { match arg {
syn::FnArg::Typed(pattern) => { syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => {
let arg_type = pattern.ty.as_ref(); let arg_name = format!("{}: {}", pat.to_token_stream(), print_type(ty));
let downcast_span = match flatten_type_groups(pattern.ty.as_ref()) { let arg_type = ty.as_ref();
let downcast_span = match flatten_type_groups(arg_type) {
syn::Type::Reference(syn::TypeReference { syn::Type::Reference(syn::TypeReference {
mutability: None, mutability: None,
ref elem, ref elem,
@ -767,6 +790,7 @@ impl ExportedFn {
}) })
.unwrap(), .unwrap(),
); );
input_type_names.push(arg_name);
if !is_string { if !is_string {
input_type_exprs.push( input_type_exprs.push(
syn::parse2::<syn::Expr>(quote_spanned!( syn::parse2::<syn::Expr>(quote_spanned!(
@ -837,6 +861,9 @@ impl ExportedFn {
fn is_method_call(&self) -> bool { #is_method_call } fn is_method_call(&self) -> bool { #is_method_call }
fn is_variadic(&self) -> bool { false } fn is_variadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(#type_name()) } 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![#(#input_type_exprs),*].into_boxed_slice() 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 gen_mod_path = crate::register::generated_module_path(&rust_modpath);
let tokens = quote! { let tokens = quote! {
#module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public, #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_input_types().as_ref(),
#gen_mod_path::token_callable()); #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 gen_mod_path = crate::register::generated_module_path(&rust_modpath);
let tokens = quote! { let tokens = quote! {
#module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public, #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_input_types().as_ref(),
#gen_mod_path::token_callable()); #gen_mod_path::token_callable());
}; };

View File

@ -3,8 +3,9 @@ use std::collections::HashMap;
use quote::{quote, ToTokens}; use quote::{quote, ToTokens};
use crate::attrs::ExportScope; use crate::attrs::ExportScope;
use crate::function::flatten_type_groups; use crate::function::{
use crate::function::{ExportedFn, FnNamespaceAccess, FnSpecialAccess}; flatten_type_groups, print_type, ExportedFn, FnNamespaceAccess, FnSpecialAccess,
};
use crate::module::Module; use crate::module::Module;
pub(crate) type ExportedConst = (String, Box<syn::Type>, syn::Expr); 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 reg_names = function.exported_names();
let mut namespace = FnNamespaceAccess::Internal; 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 let fn_input_types: Vec<syn::Expr> = function
.arg_list() .arg_list()
.map(|fnarg| match fnarg { .map(|fnarg| match fnarg {
@ -117,6 +128,7 @@ pub(crate) fn generate_body(
}, },
t => t.clone(), t => t.clone(),
}; };
syn::parse2::<syn::Expr>(quote! { syn::parse2::<syn::Expr>(quote! {
core::any::TypeId::of::<#arg_type>()}) core::any::TypeId::of::<#arg_type>()})
.unwrap() .unwrap()
@ -138,7 +150,8 @@ pub(crate) fn generate_body(
); );
set_fn_stmts.push( set_fn_stmts.push(
syn::parse2::<syn::Stmt>(quote! { 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()); #fn_token_name().into());
}) })
.unwrap(), .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_impl(&fn_token_name.to_string()));
gen_fn_tokens.push(function.generate_callable(&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())); gen_fn_tokens.push(function.generate_input_types(&fn_token_name.to_string()));
} }
@ -162,6 +176,7 @@ pub(crate) fn generate_body(
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -194,9 +209,7 @@ pub(crate) fn check_rename_collisions(fns: &Vec<ExportedFn>) -> Result<(), syn::
.fold(name.to_string(), |mut argstr, fnarg| { .fold(name.to_string(), |mut argstr, fnarg| {
let type_string: String = match fnarg { let type_string: String = match fnarg {
syn::FnArg::Receiver(_) => unimplemented!("receiver rhai_fns not implemented"), syn::FnArg::Receiver(_) => unimplemented!("receiver rhai_fns not implemented"),
syn::FnArg::Typed(syn::PatType { ref ty, .. }) => { syn::FnArg::Typed(syn::PatType { ref ty, .. }) => print_type(ty),
ty.as_ref().to_token_stream().to_string()
}
}; };
argstr.push('.'); argstr.push('.');
argstr.push_str(&type_string); argstr.push_str(&type_string);

View File

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

View File

@ -257,6 +257,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -291,11 +292,12 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { 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()); get_mystic_number_token().into());
if flatten {} else {} if flatten {} else {}
} }
@ -313,6 +315,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(get_mystic_number_token()) Box::new(get_mystic_number_token())
} }
fn input_names(&self) -> Box<[&'static str]> {
new_vec![].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![].into_boxed_slice() new_vec![].into_boxed_slice()
} }
@ -320,6 +325,9 @@ mod generate_tests {
pub fn get_mystic_number_token_callable() -> CallableFunction { pub fn get_mystic_number_token_callable() -> CallableFunction {
get_mystic_number_token().into() 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]> { pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> {
get_mystic_number_token().input_types() get_mystic_number_token().input_types()
} }
@ -352,11 +360,12 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { 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()); add_one_to_token().into());
if flatten {} else {} if flatten {} else {}
} }
@ -375,6 +384,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(add_one_to_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<INT>()].into_boxed_slice() new_vec![TypeId::of::<INT>()].into_boxed_slice()
} }
@ -382,6 +394,9 @@ mod generate_tests {
pub fn add_one_to_token_callable() -> CallableFunction { pub fn add_one_to_token_callable() -> CallableFunction {
add_one_to_token().into() 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]> { pub fn add_one_to_token_input_types() -> Box<[TypeId]> {
add_one_to_token().input_types() add_one_to_token().input_types()
} }
@ -413,11 +428,12 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { 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()); add_one_to_token().into());
if flatten {} else {} if flatten {} else {}
} }
@ -436,6 +452,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(add_one_to_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<INT>()].into_boxed_slice() new_vec![TypeId::of::<INT>()].into_boxed_slice()
} }
@ -443,6 +462,9 @@ mod generate_tests {
pub fn add_one_to_token_callable() -> CallableFunction { pub fn add_one_to_token_callable() -> CallableFunction {
add_one_to_token().into() 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]> { pub fn add_one_to_token_input_types() -> Box<[TypeId]> {
add_one_to_token().input_types() add_one_to_token().input_types()
} }
@ -485,14 +507,15 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { 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()); add_one_to_token().into());
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", "y: INT"]),
core::any::TypeId::of::<INT>()], &[core::any::TypeId::of::<INT>(), core::any::TypeId::of::<INT>()],
add_n_to_token().into()); add_n_to_token().into());
if flatten {} else {} if flatten {} else {}
} }
@ -511,6 +534,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(add_one_to_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<INT>()].into_boxed_slice() new_vec![TypeId::of::<INT>()].into_boxed_slice()
} }
@ -518,6 +544,9 @@ mod generate_tests {
pub fn add_one_to_token_callable() -> CallableFunction { pub fn add_one_to_token_callable() -> CallableFunction {
add_one_to_token().into() 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]> { pub fn add_one_to_token_input_types() -> Box<[TypeId]> {
add_one_to_token().input_types() add_one_to_token().input_types()
} }
@ -538,6 +567,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(add_n_to_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<INT>(), new_vec![TypeId::of::<INT>(),
TypeId::of::<INT>()].into_boxed_slice() TypeId::of::<INT>()].into_boxed_slice()
@ -546,6 +578,9 @@ mod generate_tests {
pub fn add_n_to_token_callable() -> CallableFunction { pub fn add_n_to_token_callable() -> CallableFunction {
add_n_to_token().into() 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]> { pub fn add_n_to_token_input_types() -> Box<[TypeId]> {
add_n_to_token().input_types() add_n_to_token().input_types()
} }
@ -577,12 +612,13 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { 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>(), m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]),
core::any::TypeId::of::<INT>()], &[core::any::TypeId::of::<INT>(), core::any::TypeId::of::<INT>()],
add_together_token().into()); add_together_token().into());
if flatten {} else {} if flatten {} else {}
} }
@ -602,6 +638,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(add_together_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<INT>(), new_vec![TypeId::of::<INT>(),
TypeId::of::<INT>()].into_boxed_slice() TypeId::of::<INT>()].into_boxed_slice()
@ -610,6 +649,9 @@ mod generate_tests {
pub fn add_together_token_callable() -> CallableFunction { pub fn add_together_token_callable() -> CallableFunction {
add_together_token().into() 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]> { pub fn add_together_token_input_types() -> Box<[TypeId]> {
add_together_token().input_types() add_together_token().input_types()
} }
@ -642,18 +684,19 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("add", FnNamespace::Internal, FnAccess::Public, &[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>(), core::any::TypeId::of::<INT>()],
add_together_token().into()); add_together_token().into());
m.set_fn("+", FnNamespace::Internal, FnAccess::Public, &[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>(), core::any::TypeId::of::<INT>()],
add_together_token().into()); add_together_token().into());
m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, &[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>(), core::any::TypeId::of::<INT>()],
add_together_token().into()); add_together_token().into());
if flatten {} else {} if flatten {} else {}
} }
@ -673,6 +716,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(add_together_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<INT>(), new_vec![TypeId::of::<INT>(),
TypeId::of::<INT>()].into_boxed_slice() TypeId::of::<INT>()].into_boxed_slice()
@ -681,6 +727,9 @@ mod generate_tests {
pub fn add_together_token_callable() -> CallableFunction { pub fn add_together_token_callable() -> CallableFunction {
add_together_token().into() 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]> { pub fn add_together_token_input_types() -> Box<[TypeId]> {
add_together_token().input_types() add_together_token().input_types()
} }
@ -714,6 +763,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -745,6 +795,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -778,6 +829,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -813,6 +865,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -848,6 +901,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -889,11 +943,12 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { 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()); get_mystic_number_token().into());
if flatten {} else {} if flatten {} else {}
} }
@ -911,6 +966,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(get_mystic_number_token()) Box::new(get_mystic_number_token())
} }
fn input_names(&self) -> Box<[&'static str]> {
new_vec![].into_boxed_slice()
}
fn input_types(&self) -> Box<[TypeId]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![].into_boxed_slice() new_vec![].into_boxed_slice()
} }
@ -918,6 +976,9 @@ mod generate_tests {
pub fn get_mystic_number_token_callable() -> CallableFunction { pub fn get_mystic_number_token_callable() -> CallableFunction {
get_mystic_number_token().into() 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]> { pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> {
get_mystic_number_token().input_types() get_mystic_number_token().input_types()
} }
@ -945,6 +1006,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -979,12 +1041,13 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("print_out_to", FnNamespace::Internal, FnAccess::Public, 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()); print_out_to_token().into());
if flatten {} else {} if flatten {} else {}
} }
@ -1003,6 +1066,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(print_out_to_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<ImmutableString>()].into_boxed_slice() new_vec![TypeId::of::<ImmutableString>()].into_boxed_slice()
} }
@ -1010,6 +1076,9 @@ mod generate_tests {
pub fn print_out_to_token_callable() -> CallableFunction { pub fn print_out_to_token_callable() -> CallableFunction {
print_out_to_token().into() 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]> { pub fn print_out_to_token_input_types() -> Box<[TypeId]> {
print_out_to_token().input_types() print_out_to_token().input_types()
} }
@ -1041,12 +1110,13 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("print_out_to", FnNamespace::Internal, FnAccess::Public, 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()); print_out_to_token().into());
if flatten {} else {} if flatten {} else {}
} }
@ -1065,6 +1135,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(print_out_to_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<ImmutableString>()].into_boxed_slice() new_vec![TypeId::of::<ImmutableString>()].into_boxed_slice()
} }
@ -1072,6 +1145,9 @@ mod generate_tests {
pub fn print_out_to_token_callable() -> CallableFunction { pub fn print_out_to_token_callable() -> CallableFunction {
print_out_to_token().into() 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]> { pub fn print_out_to_token_input_types() -> Box<[TypeId]> {
print_out_to_token().input_types() print_out_to_token().input_types()
} }
@ -1103,12 +1179,13 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("increment", FnNamespace::Internal, FnAccess::Public, 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()); increment_token().into());
if flatten {} else {} if flatten {} else {}
} }
@ -1127,6 +1204,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(increment_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<FLOAT>()].into_boxed_slice() new_vec![TypeId::of::<FLOAT>()].into_boxed_slice()
} }
@ -1134,6 +1214,9 @@ mod generate_tests {
pub fn increment_token_callable() -> CallableFunction { pub fn increment_token_callable() -> CallableFunction {
increment_token().into() increment_token().into()
} }
pub fn increment_token_input_names() -> Box<[&'static str]> {
increment_token().input_names()
}
pub fn increment_token_input_types() -> Box<[TypeId]> { pub fn increment_token_input_types() -> Box<[TypeId]> {
increment_token().input_types() increment_token().input_types()
} }
@ -1168,12 +1251,13 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("increment", FnNamespace::Internal, FnAccess::Public, 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()); increment_token().into());
if flatten {} else {} if flatten {} else {}
} }
@ -1192,6 +1276,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(increment_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<FLOAT>()].into_boxed_slice() new_vec![TypeId::of::<FLOAT>()].into_boxed_slice()
} }
@ -1199,6 +1286,9 @@ mod generate_tests {
pub fn increment_token_callable() -> CallableFunction { pub fn increment_token_callable() -> CallableFunction {
increment_token().into() increment_token().into()
} }
pub fn increment_token_input_names() -> Box<[&'static str]> {
increment_token().input_names()
}
pub fn increment_token_input_types() -> Box<[TypeId]> { pub fn increment_token_input_types() -> Box<[TypeId]> {
increment_token().input_types() increment_token().input_types()
} }
@ -1209,6 +1299,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -1253,12 +1344,13 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("increment", FnNamespace::Internal, FnAccess::Public, 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()); increment_token().into());
if flatten {} else {} if flatten {} else {}
} }
@ -1277,6 +1369,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(increment_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<FLOAT>()].into_boxed_slice() new_vec![TypeId::of::<FLOAT>()].into_boxed_slice()
} }
@ -1284,6 +1379,9 @@ mod generate_tests {
pub fn increment_token_callable() -> CallableFunction { pub fn increment_token_callable() -> CallableFunction {
increment_token().into() increment_token().into()
} }
pub fn increment_token_input_names() -> Box<[&'static str]> {
increment_token().input_names()
}
pub fn increment_token_input_types() -> Box<[TypeId]> { pub fn increment_token_input_types() -> Box<[TypeId]> {
increment_token().input_types() increment_token().input_types()
} }
@ -1294,6 +1392,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -1337,11 +1436,12 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { 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()); int_foo_token().into());
if flatten {} else {} if flatten {} else {}
} }
@ -1360,6 +1460,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(int_foo_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<u64>()].into_boxed_slice() new_vec![TypeId::of::<u64>()].into_boxed_slice()
} }
@ -1367,6 +1470,9 @@ mod generate_tests {
pub fn int_foo_token_callable() -> CallableFunction { pub fn int_foo_token_callable() -> CallableFunction {
int_foo_token().into() 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]> { pub fn int_foo_token_input_types() -> Box<[TypeId]> {
int_foo_token().input_types() int_foo_token().input_types()
} }
@ -1399,13 +1505,14 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { 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()); 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()); int_foo_token().into());
if flatten {} else {} if flatten {} else {}
} }
@ -1424,6 +1531,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(int_foo_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<u64>()].into_boxed_slice() new_vec![TypeId::of::<u64>()].into_boxed_slice()
} }
@ -1431,6 +1541,9 @@ mod generate_tests {
pub fn int_foo_token_callable() -> CallableFunction { pub fn int_foo_token_callable() -> CallableFunction {
int_foo_token().into() 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]> { pub fn int_foo_token_input_types() -> Box<[TypeId]> {
int_foo_token().input_types() int_foo_token().input_types()
} }
@ -1463,13 +1576,13 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public, 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>(), core::any::TypeId::of::<u64>()],
core::any::TypeId::of::<u64>()],
int_foo_token().into()); int_foo_token().into());
if flatten {} else {} if flatten {} else {}
} }
@ -1489,6 +1602,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(int_foo_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<u64>(), TypeId::of::<u64>()].into_boxed_slice() new_vec![TypeId::of::<u64>(), TypeId::of::<u64>()].into_boxed_slice()
} }
@ -1496,6 +1612,9 @@ mod generate_tests {
pub fn int_foo_token_callable() -> CallableFunction { pub fn int_foo_token_callable() -> CallableFunction {
int_foo_token().into() 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]> { pub fn int_foo_token_input_types() -> Box<[TypeId]> {
int_foo_token().input_types() int_foo_token().input_types()
} }
@ -1528,17 +1647,16 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("set_sq", FnNamespace::Internal, FnAccess::Public, 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>(), core::any::TypeId::of::<u64>()],
core::any::TypeId::of::<u64>()],
int_foo_token().into()); int_foo_token().into());
m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public, 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>(), core::any::TypeId::of::<u64>()],
core::any::TypeId::of::<u64>()],
int_foo_token().into()); int_foo_token().into());
if flatten {} else {} if flatten {} else {}
} }
@ -1558,6 +1676,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(int_foo_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<u64>(), TypeId::of::<u64>()].into_boxed_slice() new_vec![TypeId::of::<u64>(), TypeId::of::<u64>()].into_boxed_slice()
} }
@ -1565,6 +1686,9 @@ mod generate_tests {
pub fn int_foo_token_callable() -> CallableFunction { pub fn int_foo_token_callable() -> CallableFunction {
int_foo_token().into() 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]> { pub fn int_foo_token_input_types() -> Box<[TypeId]> {
int_foo_token().input_types() int_foo_token().input_types()
} }
@ -1597,11 +1721,13 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("index$get$", FnNamespace::Internal, FnAccess::Public, m.set_fn("index$get$", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut MyCollection", "i: u64"]),
&[core::any::TypeId::of::<MyCollection>(), &[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>()], core::any::TypeId::of::<u64>()],
get_by_index_token().into()); get_by_index_token().into());
@ -1623,6 +1749,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(get_by_index_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<MyCollection>(), new_vec![TypeId::of::<MyCollection>(),
TypeId::of::<u64>()].into_boxed_slice() TypeId::of::<u64>()].into_boxed_slice()
@ -1631,6 +1760,9 @@ mod generate_tests {
pub fn get_by_index_token_callable() -> CallableFunction { pub fn get_by_index_token_callable() -> CallableFunction {
get_by_index_token().into() 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]> { pub fn get_by_index_token_input_types() -> Box<[TypeId]> {
get_by_index_token().input_types() get_by_index_token().input_types()
} }
@ -1663,15 +1795,18 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("get", FnNamespace::Internal, FnAccess::Public, m.set_fn("get", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut MyCollection", "i: u64"]),
&[core::any::TypeId::of::<MyCollection>(), &[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>()], core::any::TypeId::of::<u64>()],
get_by_index_token().into()); get_by_index_token().into());
m.set_fn("index$get$", FnNamespace::Internal, FnAccess::Public, m.set_fn("index$get$", FnNamespace::Internal, FnAccess::Public,
Some(&["x: &mut MyCollection", "i: u64"]),
&[core::any::TypeId::of::<MyCollection>(), &[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>()], core::any::TypeId::of::<u64>()],
get_by_index_token().into()); get_by_index_token().into());
@ -1693,6 +1828,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(get_by_index_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<MyCollection>(), new_vec![TypeId::of::<MyCollection>(),
TypeId::of::<u64>()].into_boxed_slice() TypeId::of::<u64>()].into_boxed_slice()
@ -1701,6 +1839,9 @@ mod generate_tests {
pub fn get_by_index_token_callable() -> CallableFunction { pub fn get_by_index_token_callable() -> CallableFunction {
get_by_index_token().into() 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]> { pub fn get_by_index_token_input_types() -> Box<[TypeId]> {
get_by_index_token().input_types() get_by_index_token().input_types()
} }
@ -1733,11 +1874,13 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("index$set$", FnNamespace::Internal, FnAccess::Public, 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::<MyCollection>(),
core::any::TypeId::of::<u64>(), core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<FLOAT>()], core::any::TypeId::of::<FLOAT>()],
@ -1761,6 +1904,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(set_by_index_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<MyCollection>(), new_vec![TypeId::of::<MyCollection>(),
TypeId::of::<u64>(), TypeId::of::<u64>(),
@ -1770,6 +1916,9 @@ mod generate_tests {
pub fn set_by_index_token_callable() -> CallableFunction { pub fn set_by_index_token_callable() -> CallableFunction {
set_by_index_token().into() 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]> { pub fn set_by_index_token_input_types() -> Box<[TypeId]> {
set_by_index_token().input_types() set_by_index_token().input_types()
} }
@ -1802,16 +1951,19 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn("set", FnNamespace::Internal, FnAccess::Public, 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::<MyCollection>(),
core::any::TypeId::of::<u64>(), core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<FLOAT>()], core::any::TypeId::of::<FLOAT>()],
set_by_index_token().into()); set_by_index_token().into());
m.set_fn("index$set$", FnNamespace::Internal, FnAccess::Public, 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::<MyCollection>(),
core::any::TypeId::of::<u64>(), core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<FLOAT>()], core::any::TypeId::of::<FLOAT>()],
@ -1835,6 +1987,9 @@ mod generate_tests {
fn clone_boxed(&self) -> Box<dyn PluginFunction> { fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(set_by_index_token()) 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]> { fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<MyCollection>(), new_vec![TypeId::of::<MyCollection>(),
TypeId::of::<u64>(), TypeId::of::<u64>(),
@ -1844,6 +1999,9 @@ mod generate_tests {
pub fn set_by_index_token_callable() -> CallableFunction { pub fn set_by_index_token_callable() -> CallableFunction {
set_by_index_token().into() 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]> { pub fn set_by_index_token_input_types() -> Box<[TypeId]> {
set_by_index_token().input_types() set_by_index_token().input_types()
} }
@ -1874,6 +2032,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -1888,6 +2047,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -1928,6 +2088,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -1944,6 +2105,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -1958,6 +2120,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -2024,6 +2187,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -2040,6 +2204,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -2054,6 +2219,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -2077,6 +2243,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -2091,6 +2258,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -2116,6 +2284,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -2132,6 +2301,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -2146,6 +2316,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]
@ -2167,6 +2338,7 @@ mod generate_tests {
pub fn rhai_module_generate() -> Module { pub fn rhai_module_generate() -> Module {
let mut m = Module::new(); let mut m = Module::new();
rhai_generate_into_module(&mut m, false); rhai_generate_into_module(&mut m, false);
m.build_index();
m m
} }
#[allow(unused_mut)] #[allow(unused_mut)]

View File

@ -97,7 +97,7 @@ The Rhai Scripting Language
19. [Modules](language/modules/index.md) 19. [Modules](language/modules/index.md)
1. [Export Variables, Functions and Sub-Modules](language/modules/export.md) 1. [Export Variables, Functions and Sub-Modules](language/modules/export.md)
2. [Import Modules](language/modules/import.md) 2. [Import Modules](language/modules/import.md)
20. [Eval Statement](language/eval.md) 20. [Eval Function](language/eval.md)
6. [Safety and Protection](safety/index.md) 6. [Safety and Protection](safety/index.md)
1. [Checked Arithmetic](safety/checked.md) 1. [Checked Arithmetic](safety/checked.md)
2. [Sand-Boxing](safety/sandbox.md) 2. [Sand-Boxing](safety/sandbox.md)

View File

@ -9,8 +9,6 @@ Keywords List
| `false` | boolean false literal | | no | | | `false` | boolean false literal | | no | |
| `let` | variable declaration | | no | | | `let` | variable declaration | | no | |
| `const` | constant 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 | | | `if` | if statement | | no | |
| `else` | else block of if statement | | no | | | `else` | else block of if statement | | no | |
| `switch` | matching | | no | | | `switch` | matching | | no | |
@ -35,7 +33,6 @@ Keywords List
| `call` | call a [function pointer] | | yes | no | | `call` | call a [function pointer] | | yes | no |
| `curry` | curry a [function pointer] | | yes | no | | `curry` | curry a [function pointer] | | yes | no |
| `this` | reference to base object for method call | [`no_function`] | 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 | | `type_of` | get type name of value | | yes | yes |
| `print` | print value | | yes | yes | | `print` | print value | | yes | yes |
| `debug` | print value in debug format | | yes | yes | | `debug` | print value in debug format | | yes | yes |
@ -49,6 +46,8 @@ Reserved Keywords
| --------- | --------------------- | | --------- | --------------------- |
| `var` | variable declaration | | `var` | variable declaration |
| `static` | variable declaration | | `static` | variable declaration |
| `begin` | block scope |
| `end` | block scope |
| `shared` | share value | | `shared` | share value |
| `each` | looping | | `each` | looping |
| `then` | control flow | | `then` | control flow |

View File

@ -34,23 +34,28 @@ It is very useful to have a constant value hold a [custom type], which essential
as a [_singleton_](../patterns/singleton.md). as a [_singleton_](../patterns/singleton.md).
```rust ```rust
use rhai::{Engine, Scope}; use rhai::{Engine, Scope, RegisterFn};
#[derive(Debug, Clone)]
struct TestStruct(i64); // custom type struct TestStruct(i64); // custom type
let engine = Engine::new() let mut engine = Engine::new();
engine
.register_type_with_name::<TestStruct>("TestStruct") // register custom type .register_type_with_name::<TestStruct>("TestStruct") // register custom type
.register_get_set("value", .register_get("value", |obj: &mut TestStruct| obj.0), // property getter
|obj: &mut TestStruct| obj.0, // property getter .register_fn("update_value",
|obj: &mut TestStruct, value: i64| obj.0 = value // property setter |obj: &mut TestStruct, value: i64| obj.0 = value // mutating method
); );
let mut scope = Scope::new(); // create custom scope let mut scope = Scope::new(); // create custom scope
scope.push_constant("MY_NUMBER", TestStruct(123_i64)); // add constant variable scope.push_constant("MY_NUMBER", TestStruct(123_i64)); // add constant variable
engine.consume_with_scope(&mut scope, r" // Beware: constant objects can still be modified via a method call!
MY_NUMBER.value = 42; // constant objects can be modified engine.consume_with_scope(&mut scope,
r"
MY_NUMBER.update_value(42);
print(MY_NUMBER.value); // prints 42 print(MY_NUMBER.value); // prints 42
")?; ")?;
``` ```

View File

@ -1,4 +1,4 @@
`eval` Statement `eval` Function
=============== ===============
{{#include ../links.md}} {{#include ../links.md}}
@ -60,7 +60,13 @@ print(x);
-------------- --------------
For those who subscribe to the (very sensible) motto of ["`eval` is evil"](http://linterrors.com/js/eval-is-evil), For those who subscribe to the (very sensible) motto of ["`eval` is evil"](http://linterrors.com/js/eval-is-evil),
disable `eval` by overloading it, probably with something that throws. disable `eval` using [`Engine::disable_symbol`][disable keywords and operators]:
```rust
engine.disable_symbol("eval"); // disable usage of 'eval'
```
`eval` can also be disabled by overloading it, probably with something that throws:
```rust ```rust
fn eval(script) { throw "eval is evil! I refuse to run " + script } fn eval(script) { throw "eval is evil! I refuse to run " + script }
@ -75,20 +81,3 @@ engine.register_result_fn("eval", |script: String| -> Result<(), Box<EvalAltResu
Err(format!("eval is evil! I refuse to run {}", script).into()) Err(format!("eval is evil! I refuse to run {}", script).into())
}); });
``` ```
`EvalPackage`
-------------
There is even a package named [`EvalPackage`][packages] which implements the disabling override:
```rust
use rhai::Engine;
use rhai::packages::Package // load the 'Package' trait to use packages
use rhai::packages::EvalPackage; // the 'eval' package disables 'eval'
let mut engine = Engine::new();
let package = EvalPackage::new(); // create the package
engine.load_package(package.get()); // load the package
```

View File

@ -104,7 +104,7 @@ This is similar to Rust and many other modern languages, such as JavaScript's `f
`is_def_fn` `is_def_fn`
----------- -----------
Use `is_def_fn` to detect if a function is defined (and therefore callable), based on its name Use `is_def_fn` to detect if a Rhai function is defined (and therefore callable), based on its name
and the number of parameters. and the number of parameters.
```rust ```rust

View File

@ -5,21 +5,22 @@ Keywords
The following are reserved keywords in Rhai: The following are reserved keywords in Rhai:
| Active keywords | Reserved keywords | Usage | Inactive under feature | | Active keywords | Reserved keywords | Usage | Inactive under feature |
| ------------------------------------------------- | ---------------------------------------------------------- | ---------------------- | :--------------------: | | ---------------------------------------------------------------- | ---------------------------------------------------------- | ---------------------- | :--------------------: |
| `true`, `false` | | boolean constants | | | `true`, `false` | | constants | |
| `let`, `const` | `var`, `static` | variable declarations | | | `let`, `const` | `var`, `static` | variables | |
| `is_shared` | | shared values | [`no_closure`] | | | `begin`, `end` | block scopes | |
| `if`, `else` | `then`, `goto`, `exit` | control flow | | | `is_shared` | | shared values | [`no_closure`] |
| | `switch`, `match`, `case` | matching | | | `if`, `else` | `then`, `unless`, `goto`, `exit` | control flow | |
| `while`, `loop`, `for`, `in`, `continue`, `break` | `do`, `each` | looping | | | `switch` | `match`, `case` | switching and matching | |
| `fn`, `private` | `public`, `new` | functions | [`no_function`] | | `do`, `while`, `loop`, `until`, `for`, `in`, `continue`, `break` | `each` | looping | |
| `return` | | return values | | | `fn`, `private` | `public`, `new` | functions | [`no_function`] |
| `throw`, `try`, `catch` | | throw/catch exceptions | | | `return` | | return values | |
| `import`, `export`, `as` | `use`, `with`, `module`, `package` | modules/packages | [`no_module`] | | `throw`, `try`, `catch` | | throw/catch exceptions | |
| `Fn`, `call`, `curry` | | function pointers | | | `import`, `export`, `as` | `use`, `with`, `module`, `package` | modules/packages | [`no_module`] |
| | `spawn`, `thread`, `go`, `sync`, `async`, `await`, `yield` | threading/async | | | `Fn`, `call`, `curry` | | function pointers | |
| `type_of`, `print`, `debug`, `eval` | | special functions | | | | `spawn`, `thread`, `go`, `sync`, `async`, `await`, `yield` | threading/async | |
| | `default`, `void`, `null`, `nil` | special values | | | `type_of`, `print`, `debug`, `eval` | | special functions | |
| | `default`, `void`, `null`, `nil` | special values | |
Keywords cannot become the name of a [function] or [variable], even when they are disabled. Keywords cannot become the name of a [function] or [variable], even when they are disabled.

View File

@ -9,7 +9,7 @@ Terminated by '`;`'
Statements are terminated by semicolons '`;`' and they are mandatory, Statements are terminated by semicolons '`;`' and they are mandatory,
except for the _last_ statement in a _block_ (enclosed by '`{`' .. '`}`' pairs) where it can be omitted. except for the _last_ statement in a _block_ (enclosed by '`{`' .. '`}`' pairs) where it can be omitted.
Semicolons can also be omitted if the statement contains a block itself Semicolons can also be omitted if the statement ends with a block itself
(e.g. the `if`, `while`, `for` and `loop` statements). (e.g. the `if`, `while`, `for` and `loop` statements).
```rust ```rust
@ -35,6 +35,8 @@ Statement Expression
A statement can be used anywhere where an expression is expected. These are called, for lack of a more A statement can be used anywhere where an expression is expected. These are called, for lack of a more
creative name, "statement expressions." creative name, "statement expressions."
The _last_ statement of a statement block is _always_ the block's return value when used as a statement. The _last_ statement of a statement block is _always_ the block's return value when used as a statement,
_regardless_ of whether it is terminated by a semicolon or not. This is different from Rust where,
if the last statement is terminated by a semicolon, the block's return value is taken to be `()`.
If the last statement has no return value (e.g. variable definitions, assignments) then it is assumed to be [`()`]. If the last statement has no return value (e.g. variable definitions, assignments) then it is assumed to be [`()`].

View File

@ -50,7 +50,7 @@ impl ModuleResolver for MyModuleResolver {
// Return EvalAltResult::ErrorInModule upon loading error // Return EvalAltResult::ErrorInModule upon loading error
EvalAltResult::ErrorInModule(path.into(), Box::new(err), pos).into() EvalAltResult::ErrorInModule(path.into(), Box::new(err), pos).into()
)?; )?;
my_module.build_index(); // index it my_module.build_index(); // index it
Rc::new(my_module) // make it shared Rc::new(my_module) // make it shared
} else { } else {
// Return EvalAltResult::ErrorModuleNotFound if the path is invalid // Return EvalAltResult::ErrorModuleNotFound if the path is invalid

View File

@ -19,7 +19,6 @@ Built-In Packages
| `BasicArrayPackage` | basic [array] functions (not available under `no_index`) | no | yes | | `BasicArrayPackage` | basic [array] functions (not available under `no_index`) | no | yes |
| `BasicMapPackage` | basic [object map] functions (not available under `no_object`) | no | yes | | `BasicMapPackage` | basic [object map] functions (not available under `no_object`) | no | yes |
| `BasicFnPackage` | basic methods for [function pointers]. | yes | yes | | `BasicFnPackage` | basic methods for [function pointers]. | yes | yes |
| `EvalPackage` | disable [`eval`] | no | no |
| `CorePackage` | basic essentials | yes | yes | | `CorePackage` | basic essentials | yes | yes |
| `StandardPackage` | standard library (default for `Engine::new`) | no | yes | | `StandardPackage` | standard library (default for `Engine::new`) | no | yes |

View File

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

View File

@ -100,7 +100,7 @@ impl fmt::Display for ScriptFnDef {
.iter() .iter()
.map(|s| s.as_str()) .map(|s| s.as_str())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(",") .join(", ")
) )
} }
} }
@ -1154,8 +1154,8 @@ mod tests {
assert_eq!(size_of::<crate::ast::Stmt>(), 32); assert_eq!(size_of::<crate::ast::Stmt>(), 32);
assert_eq!(size_of::<Option<crate::ast::Stmt>>(), 32); assert_eq!(size_of::<Option<crate::ast::Stmt>>(), 32);
assert_eq!(size_of::<crate::Scope>(), 72); assert_eq!(size_of::<crate::Scope>(), 72);
assert_eq!(size_of::<crate::LexError>(), 32); assert_eq!(size_of::<crate::LexError>(), 56);
assert_eq!(size_of::<crate::ParseError>(), 16); assert_eq!(size_of::<crate::ParseError>(), 16);
assert_eq!(size_of::<crate::EvalAltResult>(), 64); assert_eq!(size_of::<crate::EvalAltResult>(), 72);
} }
} }

View File

@ -95,24 +95,25 @@ impl Imports {
self.0.as_mut().unwrap().truncate(size); 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)] #[allow(dead_code)]
pub fn iter(&self) -> impl Iterator<Item = (&str, Shared<Module>)> { pub fn iter(&self) -> impl Iterator<Item = (&str, Shared<Module>)> {
self.0.iter().flat_map(|lib| { self.0.iter().flat_map(|lib| {
lib.iter() lib.iter()
.rev()
.map(|(name, module)| (name.as_str(), module.clone())) .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)] #[allow(dead_code)]
pub(crate) fn iter_raw<'a>( pub(crate) fn iter_raw<'a>(
&'a self, &'a self,
) -> impl Iterator<Item = (ImmutableString, Shared<Module>)> + 'a { ) -> 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>)> { 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. /// Add a stream of imported modules.
pub fn extend(&mut self, stream: impl Iterator<Item = (ImmutableString, Shared<Module>)>) { pub fn extend(&mut self, stream: impl Iterator<Item = (ImmutableString, Shared<Module>)>) {
@ -178,9 +179,7 @@ pub const KEYWORD_FN_PTR_CURRY: &str = "curry";
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
pub const KEYWORD_IS_SHARED: &str = "is_shared"; pub const KEYWORD_IS_SHARED: &str = "is_shared";
pub const KEYWORD_IS_DEF_VAR: &str = "is_def_var"; pub const KEYWORD_IS_DEF_VAR: &str = "is_def_var";
pub const KEYWORD_IS_DEF_FN: &str = "is_def_fn";
pub const KEYWORD_THIS: &str = "this"; pub const KEYWORD_THIS: &str = "this";
pub const FN_TO_STRING: &str = "to_string";
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
pub const FN_GET: &str = "get$"; pub const FN_GET: &str = "get$";
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]

View File

@ -7,8 +7,10 @@ use crate::optimize::OptimizationLevel;
use crate::stdlib::{ use crate::stdlib::{
any::{type_name, TypeId}, any::{type_name, TypeId},
boxed::Box, boxed::Box,
format,
hash::{Hash, Hasher}, hash::{Hash, Hasher},
string::String, string::String,
vec::Vec,
}; };
use crate::utils::get_hasher; use crate::utils::get_hasher;
use crate::{ use crate::{
@ -1515,7 +1517,7 @@ impl Engine {
.into() .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. /// and optionally a value for binding to the `this` pointer.
/// ///
/// ## WARNING /// ## WARNING
@ -1578,7 +1580,7 @@ impl Engine {
self.call_fn_dynamic_raw(scope, &[lib.as_ref()], name, &mut this_ptr, args.as_mut()) 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 /// ## WARNING
/// ///
@ -1646,6 +1648,27 @@ impl Engine {
let stmt = crate::stdlib::mem::take(ast.statements_mut()); let stmt = crate::stdlib::mem::take(ast.statements_mut());
crate::optimize::optimize_into_ast(self, scope, stmt, lib, optimization_level) 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. /// Provide a callback that will be invoked before each variable access.
/// ///
/// ## Return Value of Callback /// ## Return Value of Callback

View File

@ -3,8 +3,7 @@
use crate::ast::{Expr, Stmt}; use crate::ast::{Expr, Stmt};
use crate::engine::{ use crate::engine::{
search_imports, Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, search_imports, Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR,
KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_FN, KEYWORD_IS_DEF_VAR, KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
KEYWORD_PRINT, KEYWORD_TYPE_OF,
}; };
use crate::fn_native::FnCallArgs; use crate::fn_native::FnCallArgs;
use crate::module::NamespaceRef; use crate::module::NamespaceRef;
@ -419,7 +418,7 @@ impl Engine {
#[inline] #[inline]
pub(crate) fn has_override_by_name_and_arguments( pub(crate) fn has_override_by_name_and_arguments(
&self, &self,
mods: &Imports, mods: Option<&Imports>,
lib: &[&Module], lib: &[&Module],
fn_name: &str, fn_name: &str,
arg_types: impl AsRef<[TypeId]>, arg_types: impl AsRef<[TypeId]>,
@ -436,7 +435,7 @@ impl Engine {
#[inline(always)] #[inline(always)]
pub(crate) fn has_override( pub(crate) fn has_override(
&self, &self,
mods: &Imports, mods: Option<&Imports>,
lib: &[&Module], lib: &[&Module],
hash_fn: u64, hash_fn: u64,
hash_script: u64, hash_script: u64,
@ -454,8 +453,7 @@ impl Engine {
|| self.packages.contains_fn(hash_script) || self.packages.contains_fn(hash_script)
|| self.packages.contains_fn(hash_fn) || self.packages.contains_fn(hash_fn)
// Then check imported modules // Then check imported modules
|| mods.contains_fn(hash_script) || mods.map(|m| m.contains_fn(hash_script) || m.contains_fn(hash_fn)).unwrap_or(false)
|| mods.contains_fn(hash_fn)
} }
/// Perform an actual function call, native Rust or scripted, taking care of special functions. /// Perform an actual function call, native Rust or scripted, taking care of special functions.
@ -494,7 +492,7 @@ impl Engine {
// type_of // type_of
KEYWORD_TYPE_OF KEYWORD_TYPE_OF
if args.len() == 1 if args.len() == 1
&& !self.has_override(mods, lib, hash_fn, hash_script, pub_only) => && !self.has_override(Some(mods), lib, hash_fn, hash_script, pub_only) =>
{ {
Ok(( Ok((
self.map_type_name(args[0].type_name()).to_string().into(), self.map_type_name(args[0].type_name()).to_string().into(),
@ -506,7 +504,7 @@ impl Engine {
// by a function pointer so it isn't caught at parse time. // by a function pointer so it isn't caught at parse time.
KEYWORD_FN_PTR | KEYWORD_EVAL KEYWORD_FN_PTR | KEYWORD_EVAL
if args.len() == 1 if args.len() == 1
&& !self.has_override(mods, lib, hash_fn, hash_script, pub_only) => && !self.has_override(Some(mods), lib, hash_fn, hash_script, pub_only) =>
{ {
EvalAltResult::ErrorRuntime( EvalAltResult::ErrorRuntime(
format!( format!(
@ -521,7 +519,7 @@ impl Engine {
// Script-like function found // Script-like function found
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
_ if self.has_override(mods, lib, 0, hash_script, pub_only) => { _ if self.has_override(Some(mods), lib, 0, hash_script, pub_only) => {
// Get function // Get function
let func = lib let func = lib
.iter() .iter()
@ -856,7 +854,7 @@ impl Engine {
let hash_fn = let hash_fn =
calc_native_fn_hash(empty(), fn_name, once(TypeId::of::<ImmutableString>())); calc_native_fn_hash(empty(), fn_name, once(TypeId::of::<ImmutableString>()));
if !self.has_override(mods, lib, hash_fn, hash_script, pub_only) { if !self.has_override(Some(mods), lib, hash_fn, hash_script, pub_only) {
// Fn - only in function call style // Fn - only in function call style
return self return self
.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)? .eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?
@ -912,7 +910,7 @@ impl Engine {
if name == KEYWORD_FN_PTR_CALL if name == KEYWORD_FN_PTR_CALL
&& args_expr.len() >= 1 && args_expr.len() >= 1
&& !self.has_override(mods, lib, 0, hash_script, pub_only) && !self.has_override(Some(mods), lib, 0, hash_script, pub_only)
{ {
let fn_ptr = self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?; let fn_ptr = self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?;
@ -942,7 +940,7 @@ impl Engine {
if name == KEYWORD_IS_DEF_VAR && args_expr.len() == 1 { if name == KEYWORD_IS_DEF_VAR && args_expr.len() == 1 {
let hash_fn = calc_native_fn_hash(empty(), name, once(TypeId::of::<ImmutableString>())); let hash_fn = calc_native_fn_hash(empty(), name, once(TypeId::of::<ImmutableString>()));
if !self.has_override(mods, lib, hash_fn, hash_script, pub_only) { if !self.has_override(Some(mods), lib, hash_fn, hash_script, pub_only) {
let var_name = let var_name =
self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?; self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?;
let var_name = var_name.as_str().map_err(|err| { let var_name = var_name.as_str().map_err(|err| {
@ -952,44 +950,11 @@ impl Engine {
} }
} }
// Handle is_def_fn()
if name == KEYWORD_IS_DEF_FN && args_expr.len() == 2 {
let hash_fn = calc_native_fn_hash(
empty(),
name,
[TypeId::of::<ImmutableString>(), TypeId::of::<INT>()]
.iter()
.cloned(),
);
if !self.has_override(mods, lib, hash_fn, hash_script, pub_only) {
let fn_name =
self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?;
let num_params =
self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[1], level)?;
let fn_name = fn_name.as_str().map_err(|err| {
self.make_type_mismatch_err::<ImmutableString>(err, args_expr[0].position())
})?;
let num_params = num_params.as_int().map_err(|err| {
self.make_type_mismatch_err::<INT>(err, args_expr[1].position())
})?;
return Ok(if num_params < 0 {
false
} else {
let hash = calc_script_fn_hash(empty(), fn_name, num_params as usize);
lib.iter().any(|&m| m.contains_fn(hash, false))
}
.into());
}
}
// Handle eval() // Handle eval()
if name == KEYWORD_EVAL && args_expr.len() == 1 { if name == KEYWORD_EVAL && args_expr.len() == 1 {
let hash_fn = calc_native_fn_hash(empty(), name, once(TypeId::of::<ImmutableString>())); let hash_fn = calc_native_fn_hash(empty(), name, once(TypeId::of::<ImmutableString>()));
if !self.has_override(mods, lib, hash_fn, hash_script, pub_only) { if !self.has_override(Some(mods), lib, hash_fn, hash_script, pub_only) {
// eval - only in function call style // eval - only in function call style
let prev_len = scope.len(); let prev_len = scope.len();
let script = let script =

View File

@ -49,8 +49,8 @@ pub type Locked<T> = crate::stdlib::sync::RwLock<T>;
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct NativeCallContext<'e, 'a, 'm, 'pm: 'm> { pub struct NativeCallContext<'e, 'a, 'm, 'pm: 'm> {
engine: &'e Engine, engine: &'e Engine,
mods: Option<&'a Imports>, pub(crate) mods: Option<&'a Imports>,
lib: &'m [&'pm Module], pub(crate) lib: &'m [&'pm Module],
} }
impl<'e, 'a, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized> From<(&'e Engine, &'a Imports, &'m M)> impl<'e, 'a, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized> From<(&'e Engine, &'a Imports, &'m M)>

View File

@ -187,7 +187,7 @@ macro_rules! def_register {
{ {
#[inline] #[inline]
fn register_fn(&mut self, name: &str, f: FN) -> &mut Self { 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>()),*], &[$(map_type_id::<$par>()),*],
CallableFunction::$abi(make_func!(f : map_dynamic ; $($par => $let => $clone => $arg),*)) CallableFunction::$abi(make_func!(f : map_dynamic ; $($par => $let => $clone => $arg),*))
); );
@ -202,7 +202,7 @@ macro_rules! def_register {
{ {
#[inline] #[inline]
fn register_result_fn(&mut self, name: &str, f: FN) -> &mut Self { 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>()),*], &[$(map_type_id::<$par>()),*],
CallableFunction::$abi(make_func!(f : map_result ; $($par => $let => $clone => $arg),*)) CallableFunction::$abi(make_func!(f : map_result ; $($par => $let => $clone => $arg),*))
); );

View File

@ -2,9 +2,7 @@
use crate::ast::{FnAccess, IdentX}; use crate::ast::{FnAccess, IdentX};
use crate::dynamic::Variant; use crate::dynamic::Variant;
use crate::fn_native::{ use crate::fn_native::{shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, SendSync};
shared_make_mut, shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, SendSync,
};
use crate::fn_register::by_value as cast_arg; use crate::fn_register::by_value as cast_arg;
use crate::stdlib::{ use crate::stdlib::{
any::TypeId, any::TypeId,
@ -81,7 +79,31 @@ pub struct FuncInfo {
/// Number of parameters. /// Number of parameters.
pub params: usize, pub params: usize,
/// Parameter types (if applicable). /// 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, /// A module which may contain variables, sub-modules, external Rust functions,
@ -232,6 +254,14 @@ impl Module {
self.indexed 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? /// Does a variable exist in the module?
/// ///
/// # Example /// # Example
@ -331,7 +361,8 @@ impl Module {
namespace: FnNamespace::Internal, namespace: FnNamespace::Internal,
access: fn_def.access, access: fn_def.access,
params: num_params, params: num_params,
types: None, param_types: None,
param_names: Some(fn_def.params.clone()),
func: fn_def.into(), func: fn_def.into(),
}, },
); );
@ -399,23 +430,6 @@ impl Module {
self.modules.get(name).map(|m| m.as_ref()) self.modules.get(name).map(|m| m.as_ref())
} }
/// Get a mutable reference to a sub-module.
///
/// # Example
///
/// ```
/// use rhai::Module;
///
/// let mut module = Module::new();
/// let sub_module = Module::new();
/// module.set_sub_module("question", sub_module);
/// assert!(module.get_sub_module_mut("question").is_some());
/// ```
#[inline(always)]
pub fn get_sub_module_mut(&mut self, name: &str) -> Option<&mut Module> {
self.modules.get_mut(name).map(shared_make_mut)
}
/// Set a sub-module into the module. /// Set a sub-module into the module.
/// ///
/// If there is an existing sub-module of the same name, it is replaced. /// If there is an existing sub-module of the same name, it is replaced.
@ -469,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. /// 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. /// If there is an existing Rust function of the same hash, it is replaced.
@ -481,6 +506,7 @@ impl Module {
name: impl Into<String>, name: impl Into<String>,
namespace: FnNamespace, namespace: FnNamespace,
access: FnAccess, access: FnAccess,
arg_names: Option<&[&str]>,
arg_types: &[TypeId], arg_types: &[TypeId],
func: CallableFunction, func: CallableFunction,
) -> u64 { ) -> u64 {
@ -507,7 +533,8 @@ impl Module {
namespace, namespace,
access, access,
params: params.len(), 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(), func: func.into(),
}, },
); );
@ -595,6 +622,7 @@ impl Module {
name, name,
namespace, namespace,
access, access,
None,
arg_types, arg_types,
CallableFunction::from_method(Box::new(f)), CallableFunction::from_method(Box::new(f)),
) )
@ -625,6 +653,7 @@ impl Module {
name, name,
FnNamespace::Internal, FnNamespace::Internal,
FnAccess::Public, FnAccess::Public,
None,
&arg_types, &arg_types,
CallableFunction::from_pure(Box::new(f)), CallableFunction::from_pure(Box::new(f)),
) )
@ -657,6 +686,7 @@ impl Module {
name, name,
FnNamespace::Internal, FnNamespace::Internal,
FnAccess::Public, FnAccess::Public,
None,
&arg_types, &arg_types,
CallableFunction::from_pure(Box::new(f)), CallableFunction::from_pure(Box::new(f)),
) )
@ -692,6 +722,7 @@ impl Module {
name, name,
namespace, namespace,
FnAccess::Public, FnAccess::Public,
None,
&arg_types, &arg_types,
CallableFunction::from_method(Box::new(f)), CallableFunction::from_method(Box::new(f)),
) )
@ -757,6 +788,7 @@ impl Module {
name, name,
FnNamespace::Internal, FnNamespace::Internal,
FnAccess::Public, FnAccess::Public,
None,
&arg_types, &arg_types,
CallableFunction::from_pure(Box::new(f)), CallableFunction::from_pure(Box::new(f)),
) )
@ -799,6 +831,7 @@ impl Module {
name, name,
namespace, namespace,
FnAccess::Public, FnAccess::Public,
None,
&arg_types, &arg_types,
CallableFunction::from_method(Box::new(f)), CallableFunction::from_method(Box::new(f)),
) )
@ -919,6 +952,7 @@ impl Module {
name, name,
FnNamespace::Internal, FnNamespace::Internal,
FnAccess::Public, FnAccess::Public,
None,
&arg_types, &arg_types,
CallableFunction::from_pure(Box::new(f)), CallableFunction::from_pure(Box::new(f)),
) )
@ -967,6 +1001,7 @@ impl Module {
name, name,
namespace, namespace,
FnAccess::Public, FnAccess::Public,
None,
&arg_types, &arg_types,
CallableFunction::from_method(Box::new(f)), CallableFunction::from_method(Box::new(f)),
) )
@ -1027,6 +1062,7 @@ impl Module {
crate::engine::FN_IDX_SET, crate::engine::FN_IDX_SET,
FnNamespace::Internal, FnNamespace::Internal,
FnAccess::Public, FnAccess::Public,
None,
&arg_types, &arg_types,
CallableFunction::from_method(Box::new(f)), CallableFunction::from_method(Box::new(f)),
) )
@ -1119,6 +1155,7 @@ impl Module {
name, name,
FnNamespace::Internal, FnNamespace::Internal,
FnAccess::Public, FnAccess::Public,
None,
&arg_types, &arg_types,
CallableFunction::from_pure(Box::new(f)), CallableFunction::from_pure(Box::new(f)),
) )
@ -1174,6 +1211,7 @@ impl Module {
name, name,
namespace, namespace,
FnAccess::Public, FnAccess::Public,
None,
&arg_types, &arg_types,
CallableFunction::from_method(Box::new(f)), CallableFunction::from_method(Box::new(f)),
) )
@ -1537,6 +1575,8 @@ impl Module {
}); });
} }
module.build_index();
Ok(module) Ok(module)
} }
@ -1544,8 +1584,7 @@ impl Module {
/// variables and functions as one flattened namespace. /// variables and functions as one flattened namespace.
/// ///
/// If the module is already indexed, this method has no effect. /// If the module is already indexed, this method has no effect.
#[cfg(not(feature = "no_module"))] pub fn build_index(&mut self) -> &mut Self {
pub fn build_index(&mut self) {
// Collect a particular module. // Collect a particular module.
fn index_module<'a>( fn index_module<'a>(
module: &'a Module, module: &'a Module,
@ -1586,7 +1625,7 @@ impl Module {
name, name,
namespace, namespace,
params, params,
types, param_types: types,
func, func,
.. ..
}, },
@ -1645,6 +1684,8 @@ impl Module {
self.all_type_iterators = type_iterators; self.all_type_iterators = type_iterators;
self.indexed = true; self.indexed = true;
} }
self
} }
/// Does a type iterator exist in the entire module tree? /// Does a type iterator exist in the entire module tree?

View File

@ -159,12 +159,10 @@ impl ModuleResolver for FileModuleResolver {
_ => Box::new(EvalAltResult::ErrorInModule(path.to_string(), err, pos)), _ => Box::new(EvalAltResult::ErrorInModule(path.to_string(), err, pos)),
})?; })?;
let mut m = Module::eval_ast_as_new(scope, &ast, engine).map_err(|err| { let m = Module::eval_ast_as_new(scope, &ast, engine).map_err(|err| {
Box::new(EvalAltResult::ErrorInModule(path.to_string(), err, pos)) Box::new(EvalAltResult::ErrorInModule(path.to_string(), err, pos))
})?; })?;
m.build_index();
module = Some(m.into()); module = Some(m.into());
module_ref = module.clone(); module_ref = module.clone();
}; };

View File

@ -1,10 +1,7 @@
//! Module implementing the AST optimizer. //! Module implementing the AST optimizer.
use crate::ast::{Expr, ScriptFnDef, Stmt}; use crate::ast::{Expr, ScriptFnDef, Stmt};
use crate::engine::{ use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF};
KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_IS_DEF_FN, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT,
KEYWORD_TYPE_OF,
};
use crate::fn_call::run_builtin_binary_op; use crate::fn_call::run_builtin_binary_op;
use crate::parser::map_dynamic_to_expr; use crate::parser::map_dynamic_to_expr;
use crate::stdlib::{ use crate::stdlib::{
@ -467,11 +464,9 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
fn optimize_expr(expr: &mut Expr, state: &mut State) { fn optimize_expr(expr: &mut Expr, state: &mut State) {
// These keywords are handled specially // These keywords are handled specially
const DONT_EVAL_KEYWORDS: &[&str] = &[ const DONT_EVAL_KEYWORDS: &[&str] = &[
KEYWORD_PRINT, // side effects KEYWORD_PRINT, // side effects
KEYWORD_DEBUG, // side effects KEYWORD_DEBUG, // side effects
KEYWORD_EVAL, // arbitrary scripts KEYWORD_EVAL, // arbitrary scripts
KEYWORD_IS_DEF_FN, // functions collection is volatile
KEYWORD_IS_DEF_VAR, // variables scope is volatile
]; ];
match expr { match expr {
@ -650,7 +645,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
let arg_types: StaticVec<_> = arg_values.iter().map(Dynamic::type_id).collect(); let arg_types: StaticVec<_> = arg_values.iter().map(Dynamic::type_id).collect();
// Search for overloaded operators (can override built-in). // Search for overloaded operators (can override built-in).
if !state.engine.has_override_by_name_and_arguments(&state.engine.global_sub_modules, state.lib, x.name.as_ref(), arg_types.as_ref(), false) { if !state.engine.has_override_by_name_and_arguments(Some(&state.engine.global_sub_modules), state.lib, x.name.as_ref(), arg_types.as_ref(), false) {
if let Some(result) = run_builtin_binary_op(x.name.as_ref(), &arg_values[0], &arg_values[1]) if let Some(result) = run_builtin_binary_op(x.name.as_ref(), &arg_values[0], &arg_values[1])
.ok().flatten() .ok().flatten()
.and_then(|result| map_dynamic_to_expr(result, *pos)) .and_then(|result| map_dynamic_to_expr(result, *pos))

View File

@ -1,14 +0,0 @@
use crate::plugin::*;
use crate::{def_package, Dynamic, EvalAltResult, ImmutableString};
def_package!(crate:EvalPackage:"Disable 'eval'.", lib, {
combine_with_exported_module!(lib, "eval", eval_override);
});
#[export_module]
mod eval_override {
#[rhai_fn(return_raw)]
pub fn eval(_script: ImmutableString) -> Result<Dynamic, Box<EvalAltResult>> {
Err("eval is evil!".into())
}
}

View File

@ -48,7 +48,8 @@ macro_rules! reg_range {
($lib:expr, $x:expr, $( $y:ty ),*) => ( ($lib:expr, $x:expr, $( $y:ty ),*) => (
$( $(
$lib.set_iterator::<Range<$y>>(); $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:expr, $x:expr, $( $y:ty ),*) => (
$( $(
$lib.set_iterator::<StepRange<$y>>(); $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, { def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
lib.set_iterator::<Range<INT>>(); 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_i32"))]
#[cfg(not(feature = "only_i64"))] #[cfg(not(feature = "only_i64"))]
@ -79,7 +82,8 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
} }
lib.set_iterator::<StepRange<INT>>(); 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_i32"))]
#[cfg(not(feature = "only_i64"))] #[cfg(not(feature = "only_i64"))]

View File

@ -1,12 +1,11 @@
//! Module containing all built-in _packages_ available to Rhai, plus facilities to define custom packages. //! Module containing all built-in _packages_ available to Rhai, plus facilities to define custom packages.
use crate::fn_native::{CallableFunction, IteratorFn}; use crate::fn_native::{CallableFunction, IteratorFn};
use crate::stdlib::any::TypeId; use crate::stdlib::{any::TypeId, string::String};
use crate::{Module, Shared, StaticVec}; use crate::{Module, Shared, StaticVec};
pub(crate) mod arithmetic; pub(crate) mod arithmetic;
mod array_basic; mod array_basic;
mod eval;
mod fn_basic; mod fn_basic;
mod iter_basic; mod iter_basic;
mod logic; mod logic;
@ -21,7 +20,6 @@ mod time_basic;
pub use arithmetic::ArithmeticPackage; pub use arithmetic::ArithmeticPackage;
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
pub use array_basic::BasicArrayPackage; pub use array_basic::BasicArrayPackage;
pub use eval::EvalPackage;
pub use fn_basic::BasicFnPackage; pub use fn_basic::BasicFnPackage;
pub use iter_basic::BasicIteratorPackage; pub use iter_basic::BasicIteratorPackage;
pub use logic::LogicPackage; pub use logic::LogicPackage;
@ -89,6 +87,15 @@ impl PackagesCollection {
.as_ref() .as_ref()
.and_then(|x| x.iter().find_map(|p| p.get_iter(id))) .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) /// Macro that makes it easy to define a _package_ (which is basically a shared module)
@ -133,6 +140,7 @@ macro_rules! def_package {
pub fn new() -> Self { pub fn new() -> Self {
let mut module = $root::Module::new_with_capacity(1024); let mut module = $root::Module::new_with_capacity(1024);
<Self as $root::packages::Package>::init(&mut module); <Self as $root::packages::Package>::init(&mut module);
module.build_index();
Self(module.into()) Self(module.into())
} }
} }

View File

@ -4,9 +4,34 @@ use super::iter_basic::BasicIteratorPackage;
use super::logic::LogicPackage; use super::logic::LogicPackage;
use super::string_basic::BasicStringPackage; use super::string_basic::BasicStringPackage;
use crate::def_package; use crate::fn_native::{CallableFunction, FnCallArgs};
use crate::stdlib::{any::TypeId, boxed::Box, iter::empty};
use crate::{
calc_script_fn_hash, def_package, FnAccess, FnNamespace, ImmutableString, NativeCallContext,
INT,
};
def_package!(crate:CorePackage:"_Core_ package containing basic facilities.", lib, { def_package!(crate:CorePackage:"_Core_ package containing basic facilities.", lib, {
#[cfg(not(feature = "no_function"))]
{
let f = |ctx: NativeCallContext, args: &mut FnCallArgs| {
let num_params = args[1].clone().cast::<INT>();
let fn_name = args[0].as_str().unwrap();
Ok(if num_params < 0 {
false.into()
} else {
let hash_script = calc_script_fn_hash(empty(), fn_name, num_params as usize);
ctx.engine().has_override(ctx.mods, ctx.lib, 0, hash_script, true).into()
})
};
lib.set_fn("is_def_fn", FnNamespace::Global, FnAccess::Public,
Some(&["fn_name: &str", "num_params: INT"]),
&[TypeId::of::<ImmutableString>(), TypeId::of::<INT>()],
CallableFunction::from_method(Box::new(f)));
}
ArithmeticPackage::init(lib); ArithmeticPackage::init(lib);
LogicPackage::init(lib); LogicPackage::init(lib);
BasicStringPackage::init(lib); BasicStringPackage::init(lib);

View File

@ -1,6 +1,6 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use crate::engine::{FN_TO_STRING, KEYWORD_DEBUG, KEYWORD_PRINT}; use crate::engine::{KEYWORD_DEBUG, KEYWORD_PRINT};
use crate::plugin::*; use crate::plugin::*;
use crate::stdlib::{ use crate::stdlib::{
fmt::{Debug, Display}, fmt::{Debug, Display},
@ -32,7 +32,7 @@ macro_rules! gen_functions {
macro_rules! reg_print_functions { macro_rules! reg_print_functions {
($mod_name:ident += $root:ident ; $($arg_type:ident),+) => { $( ($mod_name:ident += $root:ident ; $($arg_type:ident),+) => { $(
set_exported_fn!($mod_name, FN_TO_STRING, $root::$arg_type::to_string_func); set_exported_fn!($mod_name, "to_string", $root::$arg_type::to_string_func);
set_exported_fn!($mod_name, KEYWORD_PRINT, $root::$arg_type::to_string_func); set_exported_fn!($mod_name, KEYWORD_PRINT, $root::$arg_type::to_string_func);
)* } )* }
} }

View File

@ -32,7 +32,7 @@ pub enum LexError {
/// An identifier is in an invalid format. /// An identifier is in an invalid format.
MalformedIdentifier(String), MalformedIdentifier(String),
/// Bad symbol encountered when tokenizing the script text. /// Bad symbol encountered when tokenizing the script text.
ImproperSymbol(String), ImproperSymbol(String, String),
} }
impl Error for LexError {} impl Error for LexError {}
@ -47,7 +47,10 @@ impl fmt::Display for LexError {
Self::MalformedIdentifier(s) => write!(f, "{}: '{}'", self.desc(), s), Self::MalformedIdentifier(s) => write!(f, "{}: '{}'", self.desc(), s),
Self::UnterminatedString => f.write_str(self.desc()), Self::UnterminatedString => f.write_str(self.desc()),
Self::StringTooLong(max) => write!(f, "{} ({})", self.desc(), max), Self::StringTooLong(max) => write!(f, "{} ({})", self.desc(), max),
Self::ImproperSymbol(s) => f.write_str(s), Self::ImproperSymbol(s, d) if d.is_empty() => {
write!(f, "Invalid symbol encountered: '{}'", s)
}
Self::ImproperSymbol(_, d) => f.write_str(d),
} }
} }
} }
@ -62,7 +65,7 @@ impl LexError {
Self::MalformedNumber(_) => "Invalid number", Self::MalformedNumber(_) => "Invalid number",
Self::MalformedChar(_) => "Invalid character", Self::MalformedChar(_) => "Invalid character",
Self::MalformedIdentifier(_) => "Variable name is not proper", Self::MalformedIdentifier(_) => "Variable name is not proper",
Self::ImproperSymbol(_) => "Invalid symbol encountered", Self::ImproperSymbol(_, _) => "Invalid symbol encountered",
} }
} }
/// Convert a `&LexError` into a [`ParseError`]. /// Convert a `&LexError` into a [`ParseError`].

View File

@ -46,11 +46,11 @@ struct ParseState<'e> {
strings: HashMap<String, ImmutableString>, strings: HashMap<String, ImmutableString>,
/// Encapsulates a local stack with variable names to simulate an actual runtime scope. /// Encapsulates a local stack with variable names to simulate an actual runtime scope.
stack: Vec<(ImmutableString, ScopeEntryType)>, stack: Vec<(ImmutableString, ScopeEntryType)>,
/// Size of the local variables stack upon entry of the current block scope.
entry_stack_len: usize,
/// Tracks a list of external variables (variables that are not explicitly declared in the scope). /// Tracks a list of external variables (variables that are not explicitly declared in the scope).
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
externals: HashMap<ImmutableString, Position>, externals: HashMap<ImmutableString, Position>,
/// Always search for variables instead of direct indexing into the scope.
always_search: bool,
/// An indicator that disables variable capturing into externals one single time /// An indicator that disables variable capturing into externals one single time
/// up until the nearest consumed Identifier token. /// up until the nearest consumed Identifier token.
/// If set to false the next call to `access_var` will not capture the variable. /// If set to false the next call to `access_var` will not capture the variable.
@ -94,7 +94,7 @@ impl<'e> ParseState<'e> {
allow_capture: true, allow_capture: true,
strings: HashMap::with_capacity(64), strings: HashMap::with_capacity(64),
stack: Vec::with_capacity(16), stack: Vec::with_capacity(16),
always_search: false, entry_stack_len: 0,
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
modules: Default::default(), modules: Default::default(),
} }
@ -110,12 +110,22 @@ impl<'e> ParseState<'e> {
/// Return `None` when the variable name is not found in the `stack`. /// Return `None` when the variable name is not found in the `stack`.
#[inline] #[inline]
fn access_var(&mut self, name: &str, _pos: Position) -> Option<NonZeroUsize> { fn access_var(&mut self, name: &str, _pos: Position) -> Option<NonZeroUsize> {
let mut barrier = false;
let index = self let index = self
.stack .stack
.iter() .iter()
.rev() .rev()
.enumerate() .enumerate()
.find(|(_, (n, _))| *n == name) .find(|(_, (n, _))| {
if n.is_empty() {
// Do not go beyond empty variable names
barrier = true;
false
} else {
*n == name
}
})
.and_then(|(i, _)| NonZeroUsize::new(i + 1)); .and_then(|(i, _)| NonZeroUsize::new(i + 1));
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
@ -127,7 +137,7 @@ impl<'e> ParseState<'e> {
self.allow_capture = true self.allow_capture = true
} }
if self.always_search { if barrier {
None None
} else { } else {
index index
@ -985,11 +995,8 @@ fn parse_primary(
// Access to `this` as a variable is OK // Access to `this` as a variable is OK
Token::Reserved(s) if s == KEYWORD_THIS && *next_token != Token::LeftParen => { Token::Reserved(s) if s == KEYWORD_THIS && *next_token != Token::LeftParen => {
if !settings.is_function_scope { if !settings.is_function_scope {
return Err(PERR::BadInput(LexError::ImproperSymbol(format!( let msg = format!("'{}' can only be used in functions", s);
"'{}' can only be used in functions", return Err(PERR::BadInput(LexError::ImproperSymbol(s, msg)).into_err(settings.pos));
s
)))
.into_err(settings.pos));
} else { } else {
let var_name_def = IdentX::new(state.get_interned_string(s), settings.pos); let var_name_def = IdentX::new(state.get_interned_string(s), settings.pos);
Expr::Variable(Box::new((None, None, 0, var_name_def))) Expr::Variable(Box::new((None, None, 0, var_name_def)))
@ -1035,6 +1042,7 @@ fn parse_primary(
LexError::UnexpectedInput(Token::Bang.syntax().to_string()).into_err(token_pos) LexError::UnexpectedInput(Token::Bang.syntax().to_string()).into_err(token_pos)
} else { } else {
PERR::BadInput(LexError::ImproperSymbol( PERR::BadInput(LexError::ImproperSymbol(
"!".to_string(),
"'!' cannot be used to call module functions".to_string(), "'!' cannot be used to call module functions".to_string(),
)) ))
.into_err(token_pos) .into_err(token_pos)
@ -1323,6 +1331,7 @@ fn make_assignment_stmt<'a>(
} }
// ??? && ??? = rhs, ??? || ??? = rhs // ??? && ??? = rhs, ??? || ??? = rhs
Expr::And(_, _) | Expr::Or(_, _) => Err(PERR::BadInput(LexError::ImproperSymbol( Expr::And(_, _) | Expr::Or(_, _) => Err(PERR::BadInput(LexError::ImproperSymbol(
"=".to_string(),
"Possibly a typo of '=='?".to_string(), "Possibly a typo of '=='?".to_string(),
)) ))
.into_err(pos)), .into_err(pos)),
@ -1428,10 +1437,13 @@ fn make_dot_expr(
&& [crate::engine::KEYWORD_FN_PTR, crate::engine::KEYWORD_EVAL] && [crate::engine::KEYWORD_FN_PTR, crate::engine::KEYWORD_EVAL]
.contains(&x.name.as_ref()) => .contains(&x.name.as_ref()) =>
{ {
return Err(PERR::BadInput(LexError::ImproperSymbol(format!( return Err(PERR::BadInput(LexError::ImproperSymbol(
"'{}' should not be called in method style. Try {}(...);", x.name.to_string(),
x.name, x.name format!(
))) "'{}' should not be called in method style. Try {}(...);",
x.name, x.name
),
))
.into_err(pos)); .into_err(pos));
} }
// lhs.func!(...) // lhs.func!(...)
@ -1789,11 +1801,13 @@ fn parse_custom_syntax(
// Adjust the variables stack // Adjust the variables stack
match syntax.scope_delta { match syntax.scope_delta {
delta if delta > 0 => { delta if delta > 0 => {
// Add enough empty variable names to the stack.
// Empty variable names act as a barrier so earlier variables will not be matched.
// Variable searches stop at the first empty variable name.
state.stack.resize( state.stack.resize(
state.stack.len() + delta as usize, state.stack.len() + delta as usize,
("".into(), ScopeEntryType::Normal), ("".into(), ScopeEntryType::Normal),
); );
state.always_search = true;
} }
delta if delta < 0 && state.stack.len() <= delta.abs() as usize => state.stack.clear(), delta if delta < 0 && state.stack.len() <= delta.abs() as usize => state.stack.clear(),
delta if delta < 0 => state delta if delta < 0 => state
@ -1920,20 +1934,22 @@ fn ensure_not_statement_expr(input: &mut TokenStream, type_name: &str) -> Result
fn ensure_not_assignment(input: &mut TokenStream) -> Result<(), ParseError> { fn ensure_not_assignment(input: &mut TokenStream) -> Result<(), ParseError> {
match input.peek().unwrap() { match input.peek().unwrap() {
(Token::Equals, pos) => Err(PERR::BadInput(LexError::ImproperSymbol( (Token::Equals, pos) => Err(PERR::BadInput(LexError::ImproperSymbol(
"=".to_string(),
"Possibly a typo of '=='?".to_string(), "Possibly a typo of '=='?".to_string(),
)) ))
.into_err(*pos)), .into_err(*pos)),
(Token::PlusAssign, pos) (token @ Token::PlusAssign, pos)
| (Token::MinusAssign, pos) | (token @ Token::MinusAssign, pos)
| (Token::MultiplyAssign, pos) | (token @ Token::MultiplyAssign, pos)
| (Token::DivideAssign, pos) | (token @ Token::DivideAssign, pos)
| (Token::LeftShiftAssign, pos) | (token @ Token::LeftShiftAssign, pos)
| (Token::RightShiftAssign, pos) | (token @ Token::RightShiftAssign, pos)
| (Token::ModuloAssign, pos) | (token @ Token::ModuloAssign, pos)
| (Token::PowerOfAssign, pos) | (token @ Token::PowerOfAssign, pos)
| (Token::AndAssign, pos) | (token @ Token::AndAssign, pos)
| (Token::OrAssign, pos) | (token @ Token::OrAssign, pos)
| (Token::XOrAssign, pos) => Err(PERR::BadInput(LexError::ImproperSymbol( | (token @ Token::XOrAssign, pos) => Err(PERR::BadInput(LexError::ImproperSymbol(
token.syntax().to_string(),
"Expecting a boolean expression, not an assignment".to_string(), "Expecting a boolean expression, not an assignment".to_string(),
)) ))
.into_err(*pos)), .into_err(*pos)),
@ -2293,8 +2309,9 @@ fn parse_block(
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let mut statements = Vec::with_capacity(8); let mut statements = Vec::with_capacity(8);
let prev_always_search = state.always_search;
let prev_stack_len = state.stack.len(); let prev_entry_stack_len = state.entry_stack_len;
state.entry_stack_len = state.stack.len();
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
let prev_mods_len = state.modules.len(); let prev_mods_len = state.modules.len();
@ -2338,15 +2355,12 @@ fn parse_block(
} }
} }
state.stack.truncate(prev_stack_len); state.stack.truncate(state.entry_stack_len);
state.entry_stack_len = prev_entry_stack_len;
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
state.modules.truncate(prev_mods_len); state.modules.truncate(prev_mods_len);
// The impact of new local variables goes away at the end of a block
// because any new variables introduced will go out of scope
state.always_search = prev_always_search;
Ok(Stmt::Block(statements, settings.pos)) Ok(Stmt::Block(statements, settings.pos))
} }

View File

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

View File

@ -120,7 +120,7 @@ pub fn from_dynamic<'de, T: Deserialize<'de>>(
impl Error for Box<EvalAltResult> { impl Error for Box<EvalAltResult> {
fn custom<T: fmt::Display>(err: T) -> Self { fn custom<T: fmt::Display>(err: T) -> Self {
EvalAltResult::ErrorParsing( EvalAltResult::ErrorParsing(
ParseErrorType::BadInput(LexError::ImproperSymbol(err.to_string())), ParseErrorType::BadInput(LexError::ImproperSymbol("".to_string(), err.to_string())),
Position::NONE, Position::NONE,
) )
.into() .into()

View File

@ -137,11 +137,14 @@ impl Engine {
.map(|v| v.is_keyword() || v.is_reserved()) .map(|v| v.is_keyword() || v.is_reserved())
.unwrap_or(false) => .unwrap_or(false) =>
{ {
return Err(LexError::ImproperSymbol(format!( return Err(LexError::ImproperSymbol(
"Improper symbol for custom syntax at position #{}: '{}'", s.to_string(),
segments.len() + 1, format!(
s "Improper symbol for custom syntax at position #{}: '{}'",
)) segments.len() + 1,
s
),
)
.into_err(Position::NONE) .into_err(Position::NONE)
.into()); .into());
} }
@ -154,11 +157,14 @@ impl Engine {
} }
// Anything else is an error // Anything else is an error
_ => { _ => {
return Err(LexError::ImproperSymbol(format!( return Err(LexError::ImproperSymbol(
"Improper symbol for custom syntax at position #{}: '{}'", s.to_string(),
segments.len() + 1, format!(
s "Improper symbol for custom syntax at position #{}: '{}'",
)) segments.len() + 1,
s
),
)
.into_err(Position::NONE) .into_err(Position::NONE)
.into()); .into());
} }

View File

@ -2,7 +2,7 @@
use crate::engine::{ use crate::engine::{
KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, 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::{ use crate::stdlib::{
borrow::Cow, borrow::Cow,
@ -532,18 +532,13 @@ impl Token {
"import" | "export" | "as" => Reserved(syntax.into()), "import" | "export" | "as" => Reserved(syntax.into()),
"===" | "!==" | "->" | "<-" | ":=" | "::<" | "(*" | "*)" | "#" | "public" | "new" "===" | "!==" | "->" | "<-" | ":=" | "::<" | "(*" | "*)" | "#" | "public" | "new"
| "use" | "module" | "package" | "var" | "static" | "shared" | "with" | "each" | "use" | "module" | "package" | "var" | "static" | "begin" | "end" | "shared"
| "then" | "goto" | "unless" | "exit" | "match" | "case" | "default" | "void" | "with" | "each" | "then" | "goto" | "unless" | "exit" | "match" | "case"
| "null" | "nil" | "spawn" | "thread" | "go" | "sync" | "async" | "await" | "yield" => { | "default" | "void" | "null" | "nil" | "spawn" | "thread" | "go" | "sync"
Reserved(syntax.into()) | "async" | "await" | "yield" => Reserved(syntax.into()),
}
KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR 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_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_THIS => Reserved(syntax.into()),
| KEYWORD_IS_DEF_FN | KEYWORD_THIS => Reserved(syntax.into()),
#[cfg(not(feature = "no_closure"))]
crate::engine::KEYWORD_IS_SHARED => Reserved(syntax.into()),
_ => return None, _ => return None,
}) })
@ -1514,12 +1509,8 @@ fn get_identifier(
#[inline(always)] #[inline(always)]
pub fn is_keyword_function(name: &str) -> bool { pub fn is_keyword_function(name: &str) -> bool {
match name { 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_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_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY => true,
true
}
_ => false, _ => false,
} }
} }
@ -1529,8 +1520,7 @@ pub fn is_keyword_function(name: &str) -> bool {
#[inline(always)] #[inline(always)]
pub fn can_override_keyword(name: &str) -> bool { pub fn can_override_keyword(name: &str) -> bool {
match name { match name {
KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR => true,
| KEYWORD_IS_DEF_VAR | KEYWORD_IS_DEF_FN => true,
_ => false, _ => false,
} }
} }
@ -1658,39 +1648,41 @@ impl<'a> Iterator for TokenIterator<'a, '_> {
Some((Token::Reserved(s), pos)) => Some((match Some((Token::Reserved(s), pos)) => Some((match
(s.as_str(), self.engine.custom_keywords.contains_key(&s)) (s.as_str(), self.engine.custom_keywords.contains_key(&s))
{ {
("===", false) => Token::LexError(LERR::ImproperSymbol( ("===", false) => Token::LexError(LERR::ImproperSymbol(s,
"'===' is not a valid operator. This is not JavaScript! Should it be '=='?".to_string(), "'===' is not a valid operator. This is not JavaScript! Should it be '=='?".to_string(),
)), )),
("!==", false) => Token::LexError(LERR::ImproperSymbol( ("!==", false) => Token::LexError(LERR::ImproperSymbol(s,
"'!==' is not a valid operator. This is not JavaScript! Should it be '!='?".to_string(), "'!==' is not a valid operator. This is not JavaScript! Should it be '!='?".to_string(),
)), )),
("->", false) => Token::LexError(LERR::ImproperSymbol( ("->", false) => Token::LexError(LERR::ImproperSymbol(s,
"'->' is not a valid symbol. This is not C or C++!".to_string())), "'->' is not a valid symbol. This is not C or C++!".to_string())),
("<-", false) => Token::LexError(LERR::ImproperSymbol( ("<-", false) => Token::LexError(LERR::ImproperSymbol(s,
"'<-' is not a valid symbol. This is not Go! Should it be '<='?".to_string(), "'<-' is not a valid symbol. This is not Go! Should it be '<='?".to_string(),
)), )),
(":=", false) => Token::LexError(LERR::ImproperSymbol( (":=", false) => Token::LexError(LERR::ImproperSymbol(s,
"':=' is not a valid assignment operator. This is not Go! Should it be simply '='?".to_string(), "':=' is not a valid assignment operator. This is not Go or Pascal! Should it be simply '='?".to_string(),
)), )),
("::<", false) => Token::LexError(LERR::ImproperSymbol( ("::<", false) => Token::LexError(LERR::ImproperSymbol(s,
"'::<>' is not a valid symbol. This is not Rust! Should it be '::'?".to_string(), "'::<>' is not a valid symbol. This is not Rust! Should it be '::'?".to_string(),
)), )),
("(*", false) | ("*)", false) => Token::LexError(LERR::ImproperSymbol( ("(*", false) | ("*)", false) | ("begin", false) | ("end", false) => Token::LexError(LERR::ImproperSymbol(s,
"'(* .. *)' is not a valid comment format. This is not Pascal! Should it be '/* .. */'?".to_string(), "'(* .. *)' is not a valid comment format. This is not Pascal! Should it be '/* .. */'?".to_string(),
)), )),
("#", false) => Token::LexError(LERR::ImproperSymbol( ("#", false) => Token::LexError(LERR::ImproperSymbol(s,
"'#' is not a valid symbol. Should it be '#{'?".to_string(), "'#' is not a valid symbol. Should it be '#{'?".to_string(),
)), )),
// Reserved keyword/operator that is custom. // Reserved keyword/operator that is custom.
(_, true) => Token::Custom(s), (_, true) => Token::Custom(s),
// Reserved operator that is not custom. // Reserved operator that is not custom.
(token, false) if !is_valid_identifier(token.chars()) => Token::LexError(LERR::ImproperSymbol( (token, false) if !is_valid_identifier(token.chars()) => {
format!("'{}' is a reserved symbol", token) let msg = format!("'{}' is a reserved symbol", token);
)), Token::LexError(LERR::ImproperSymbol(s, msg))
},
// Reserved keyword that is not custom and disabled. // Reserved keyword that is not custom and disabled.
(token, false) if self.engine.disabled_symbols.contains(token) => Token::LexError(LERR::ImproperSymbol( (token, false) if self.engine.disabled_symbols.contains(token) => {
format!("reserved symbol '{}' is disabled", token) let msg = format!("reserved symbol '{}' is disabled", token);
)), Token::LexError(LERR::ImproperSymbol(s, msg))
},
// Reserved keyword/operator that is not custom. // Reserved keyword/operator that is not custom.
(_, false) => Token::Reserved(s), (_, false) => Token::Reserved(s),
}, pos)), }, pos)),

View File

@ -1,4 +1,4 @@
use rhai::{Engine, EvalAltResult, ParseErrorType, Scope, INT}; use rhai::{Engine, EvalAltResult, ParseErrorType, RegisterFn, Scope, INT};
#[test] #[test]
fn test_constant() -> Result<(), Box<EvalAltResult>> { fn test_constant() -> Result<(), Box<EvalAltResult>> {
@ -62,3 +62,36 @@ fn test_var_is_def() -> Result<(), Box<EvalAltResult>> {
Ok(()) Ok(())
} }
#[cfg(not(feature = "no_object"))]
#[test]
fn test_constant_mut() -> Result<(), Box<EvalAltResult>> {
#[derive(Debug, Clone)]
struct TestStruct(INT); // custom type
let mut engine = Engine::new();
engine
.register_type_with_name::<TestStruct>("TestStruct")
.register_get("value", |obj: &mut TestStruct| obj.0)
.register_fn("update_value", |obj: &mut TestStruct, value: INT| {
obj.0 = value
});
let mut scope = Scope::new();
scope.push_constant("MY_NUMBER", TestStruct(123));
assert_eq!(
engine.eval_with_scope::<INT>(
&mut scope,
r"
MY_NUMBER.update_value(42);
MY_NUMBER.value
",
)?,
42
);
Ok(())
}

View File

@ -1,4 +1,4 @@
use rhai::{Engine, EvalAltResult, Scope, INT}; use rhai::{Engine, EvalAltResult, LexError, ParseErrorType, RegisterFn, Scope, INT};
#[test] #[test]
fn test_eval() -> Result<(), Box<EvalAltResult>> { fn test_eval() -> Result<(), Box<EvalAltResult>> {
@ -98,10 +98,34 @@ fn test_eval_override() -> Result<(), Box<EvalAltResult>> {
fn eval(x) { x } // reflect the script back fn eval(x) { x } // reflect the script back
eval("40 + 2") eval("40 + 2")
"# "#
)?, )?,
"40 + 2" "40 + 2"
); );
let mut engine = Engine::new();
// Reflect the script back
engine.register_fn("eval", |script: &str| script.to_string());
assert_eq!(engine.eval::<String>(r#"eval("40 + 2")"#)?, "40 + 2");
Ok(())
}
#[test]
fn test_eval_disabled() -> Result<(), Box<EvalAltResult>> {
let mut engine = Engine::new();
engine.disable_symbol("eval");
assert!(matches!(
*engine
.compile(r#"eval("40 + 2")"#)
.expect_err("should error")
.0,
ParseErrorType::BadInput(LexError::ImproperSymbol(err, _)) if err == "eval"
));
Ok(()) Ok(())
} }

View File

@ -79,6 +79,7 @@ fn test_custom_syntax() -> Result<(), Box<EvalAltResult>> {
.expect_err("should error") .expect_err("should error")
.0, .0,
ParseErrorType::BadInput(LexError::ImproperSymbol( ParseErrorType::BadInput(LexError::ImproperSymbol(
"!".to_string(),
"Improper symbol for custom syntax at position #1: '!'".to_string() "Improper symbol for custom syntax at position #1: '!'".to_string()
)) ))
); );
@ -100,6 +101,7 @@ fn test_custom_syntax_raw() -> Result<(), Box<EvalAltResult>> {
s => Err(ParseError( s => Err(ParseError(
Box::new(ParseErrorType::BadInput(LexError::ImproperSymbol( Box::new(ParseErrorType::BadInput(LexError::ImproperSymbol(
s.to_string(), s.to_string(),
"".to_string(),
))), ))),
Position::NONE, Position::NONE,
)), )),
@ -128,7 +130,7 @@ fn test_custom_syntax_raw() -> Result<(), Box<EvalAltResult>> {
assert_eq!(engine.eval::<INT>("(hello kitty) + foo")?, 1041); assert_eq!(engine.eval::<INT>("(hello kitty) + foo")?, 1041);
assert_eq!( assert_eq!(
*engine.compile("hello hey").expect_err("should error").0, *engine.compile("hello hey").expect_err("should error").0,
ParseErrorType::BadInput(LexError::ImproperSymbol("hey".to_string())) ParseErrorType::BadInput(LexError::ImproperSymbol("hey".to_string(), "".to_string()))
); );
Ok(()) Ok(())