commit
c18a6451f4
20
RELEASES.md
20
RELEASES.md
@ -10,6 +10,9 @@ It also allows exposing selected module functions (usually methods) to the globa
|
||||
This is very convenient when encapsulating the API of a custom Rust type into a module while having methods
|
||||
and iterators registered on the custom type work normally.
|
||||
|
||||
A new `gen_fn_signatures` API enables enumerating the registered functions of an `Engine` for documentation purposes.
|
||||
It also prepares the way for a future reflection API.
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
@ -19,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`.
|
||||
* `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
|
||||
------------
|
||||
|
||||
* `switch` statement.
|
||||
* `do ... while` and `do ... until` statement.
|
||||
* `Engine::register_module` to register a module as a sub-module in the global namespace.
|
||||
* `set_exported_global_fn!` macro to register a plugin function and expose it to the global namespace.
|
||||
* New `switch` statement.
|
||||
* New `do ... while` and `do ... until` statements.
|
||||
* New `Engine::gen_fn_signatures`, `Module::gen_fn_signatures` and `PackagesCollection::gen_fn_signatures` to generate a list of signatures for functions registered.
|
||||
* New `Engine::register_module` to register a module as a sub-module in the global namespace.
|
||||
* New `set_exported_global_fn!` macro to register a plugin function and expose it to the global namespace.
|
||||
* `Module::set_fn_XXX_mut` can expose a module function to the global namespace. This is convenient when registering an API for a custom type.
|
||||
* `Module::set_getter_fn`, `Module::set_setter_fn`, `Module::set_indexer_get_fn`, `Module::set_indexer_set_fn` all expose the function to the global namespace by default. This is convenient when registering an API for a custom type.
|
||||
* `#[rhai_fn(global)]` and `#[rhai_fn(internal)]` attributes to determine whether a function defined in a plugin module should be exposed to the global namespace. This is convenient when defining an API for a custom type.
|
||||
* New `Module::update_fn_param_names` to update a module function's parameter names and types.
|
||||
* New `#[rhai_fn(global)]` and `#[rhai_fn(internal)]` attributes to determine whether a function defined in a plugin module should be exposed to the global namespace. This is convenient when defining an API for a custom type.
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
|
@ -12,7 +12,7 @@ use std::format;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use quote::{quote, quote_spanned};
|
||||
use quote::{quote, quote_spanned, ToTokens};
|
||||
use syn::{
|
||||
parse::{Parse, ParseStream, Parser},
|
||||
spanned::Spanned,
|
||||
@ -83,6 +83,10 @@ pub(crate) fn flatten_type_groups(ty: &syn::Type) -> &syn::Type {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_type(ty: &syn::Type) -> String {
|
||||
ty.to_token_stream().to_string().replace("& ", "&")
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct ExportedFnParams {
|
||||
pub name: Option<Vec<String>>,
|
||||
@ -576,6 +580,7 @@ impl ExportedFn {
|
||||
syn::Ident::new(&format!("rhai_fn_{}", self.name()), self.name().span());
|
||||
let impl_block = self.generate_impl("Token");
|
||||
let callable_block = self.generate_callable("Token");
|
||||
let input_names_block = self.generate_input_names("Token");
|
||||
let input_types_block = self.generate_input_types("Token");
|
||||
let dyn_result_fn_block = self.generate_dynamic_fn();
|
||||
quote! {
|
||||
@ -585,6 +590,7 @@ impl ExportedFn {
|
||||
struct Token();
|
||||
#impl_block
|
||||
#callable_block
|
||||
#input_names_block
|
||||
#input_types_block
|
||||
#dyn_result_fn_block
|
||||
}
|
||||
@ -655,6 +661,19 @@ impl ExportedFn {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_input_names(&self, on_type_name: &str) -> proc_macro2::TokenStream {
|
||||
let token_name: syn::Ident = syn::Ident::new(on_type_name, self.name().span());
|
||||
let input_names_fn_name: syn::Ident = syn::Ident::new(
|
||||
format!("{}_input_names", on_type_name.to_lowercase()).as_str(),
|
||||
self.name().span(),
|
||||
);
|
||||
quote! {
|
||||
pub fn #input_names_fn_name() -> Box<[&'static str]> {
|
||||
#token_name().input_names()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_input_types(&self, on_type_name: &str) -> proc_macro2::TokenStream {
|
||||
let token_name: syn::Ident = syn::Ident::new(on_type_name, self.name().span());
|
||||
let input_types_fn_name: syn::Ident = syn::Ident::new(
|
||||
@ -680,6 +699,7 @@ impl ExportedFn {
|
||||
|
||||
let mut unpack_stmts: Vec<syn::Stmt> = Vec::new();
|
||||
let mut unpack_exprs: Vec<syn::Expr> = Vec::new();
|
||||
let mut input_type_names: Vec<String> = Vec::new();
|
||||
let mut input_type_exprs: Vec<syn::Expr> = Vec::new();
|
||||
let skip_first_arg;
|
||||
|
||||
@ -693,8 +713,9 @@ impl ExportedFn {
|
||||
let first_arg = self.arg_list().next().unwrap();
|
||||
let var = syn::Ident::new("arg0", proc_macro2::Span::call_site());
|
||||
match first_arg {
|
||||
syn::FnArg::Typed(pattern) => {
|
||||
let arg_type = match flatten_type_groups(pattern.ty.as_ref()) {
|
||||
syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => {
|
||||
let arg_name = format!("{}: {}", pat.to_token_stream(), print_type(ty));
|
||||
let arg_type = match flatten_type_groups(ty.as_ref()) {
|
||||
syn::Type::Reference(syn::TypeReference { ref elem, .. }) => elem.as_ref(),
|
||||
p => p,
|
||||
};
|
||||
@ -706,6 +727,7 @@ impl ExportedFn {
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
input_type_names.push(arg_name);
|
||||
input_type_exprs.push(
|
||||
syn::parse2::<syn::Expr>(quote_spanned!(
|
||||
arg_type.span()=> TypeId::of::<#arg_type>()
|
||||
@ -731,9 +753,10 @@ impl ExportedFn {
|
||||
let is_string;
|
||||
let is_ref;
|
||||
match arg {
|
||||
syn::FnArg::Typed(pattern) => {
|
||||
let arg_type = pattern.ty.as_ref();
|
||||
let downcast_span = match flatten_type_groups(pattern.ty.as_ref()) {
|
||||
syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => {
|
||||
let arg_name = format!("{}: {}", pat.to_token_stream(), print_type(ty));
|
||||
let arg_type = ty.as_ref();
|
||||
let downcast_span = match flatten_type_groups(arg_type) {
|
||||
syn::Type::Reference(syn::TypeReference {
|
||||
mutability: None,
|
||||
ref elem,
|
||||
@ -767,6 +790,7 @@ impl ExportedFn {
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
input_type_names.push(arg_name);
|
||||
if !is_string {
|
||||
input_type_exprs.push(
|
||||
syn::parse2::<syn::Expr>(quote_spanned!(
|
||||
@ -837,6 +861,9 @@ impl ExportedFn {
|
||||
fn is_method_call(&self) -> bool { #is_method_call }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(#type_name()) }
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec![#(#input_type_names),*].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![#(#input_type_exprs),*].into_boxed_slice()
|
||||
}
|
||||
|
@ -340,6 +340,7 @@ pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream
|
||||
let gen_mod_path = crate::register::generated_module_path(&rust_modpath);
|
||||
let tokens = quote! {
|
||||
#module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public,
|
||||
Some(#gen_mod_path::token_input_names().as_ref()),
|
||||
#gen_mod_path::token_input_types().as_ref(),
|
||||
#gen_mod_path::token_callable());
|
||||
};
|
||||
@ -381,6 +382,7 @@ pub fn set_exported_global_fn(args: proc_macro::TokenStream) -> proc_macro::Toke
|
||||
let gen_mod_path = crate::register::generated_module_path(&rust_modpath);
|
||||
let tokens = quote! {
|
||||
#module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public,
|
||||
Some(#gen_mod_path::token_input_names().as_ref()),
|
||||
#gen_mod_path::token_input_types().as_ref(),
|
||||
#gen_mod_path::token_callable());
|
||||
};
|
||||
|
@ -3,8 +3,9 @@ use std::collections::HashMap;
|
||||
use quote::{quote, ToTokens};
|
||||
|
||||
use crate::attrs::ExportScope;
|
||||
use crate::function::flatten_type_groups;
|
||||
use crate::function::{ExportedFn, FnNamespaceAccess, FnSpecialAccess};
|
||||
use crate::function::{
|
||||
flatten_type_groups, print_type, ExportedFn, FnNamespaceAccess, FnSpecialAccess,
|
||||
};
|
||||
use crate::module::Module;
|
||||
|
||||
pub(crate) type ExportedConst = (String, Box<syn::Type>, syn::Expr);
|
||||
@ -82,6 +83,16 @@ pub(crate) fn generate_body(
|
||||
let reg_names = function.exported_names();
|
||||
let mut namespace = FnNamespaceAccess::Internal;
|
||||
|
||||
let fn_input_names: Vec<String> = function
|
||||
.arg_list()
|
||||
.map(|fnarg| match fnarg {
|
||||
syn::FnArg::Receiver(_) => panic!("internal error: receiver fn outside impl!?"),
|
||||
syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => {
|
||||
format!("{}: {}", pat.to_token_stream(), print_type(ty))
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let fn_input_types: Vec<syn::Expr> = function
|
||||
.arg_list()
|
||||
.map(|fnarg| match fnarg {
|
||||
@ -117,6 +128,7 @@ pub(crate) fn generate_body(
|
||||
},
|
||||
t => t.clone(),
|
||||
};
|
||||
|
||||
syn::parse2::<syn::Expr>(quote! {
|
||||
core::any::TypeId::of::<#arg_type>()})
|
||||
.unwrap()
|
||||
@ -138,7 +150,8 @@ pub(crate) fn generate_body(
|
||||
);
|
||||
set_fn_stmts.push(
|
||||
syn::parse2::<syn::Stmt>(quote! {
|
||||
m.set_fn(#fn_literal, FnNamespace::#ns_str, FnAccess::Public, &[#(#fn_input_types),*],
|
||||
m.set_fn(#fn_literal, FnNamespace::#ns_str, FnAccess::Public,
|
||||
Some(&[#(#fn_input_names),*]), &[#(#fn_input_types),*],
|
||||
#fn_token_name().into());
|
||||
})
|
||||
.unwrap(),
|
||||
@ -151,6 +164,7 @@ pub(crate) fn generate_body(
|
||||
});
|
||||
gen_fn_tokens.push(function.generate_impl(&fn_token_name.to_string()));
|
||||
gen_fn_tokens.push(function.generate_callable(&fn_token_name.to_string()));
|
||||
gen_fn_tokens.push(function.generate_input_names(&fn_token_name.to_string()));
|
||||
gen_fn_tokens.push(function.generate_input_types(&fn_token_name.to_string()));
|
||||
}
|
||||
|
||||
@ -162,6 +176,7 @@ pub(crate) fn generate_body(
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[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| {
|
||||
let type_string: String = match fnarg {
|
||||
syn::FnArg::Receiver(_) => unimplemented!("receiver rhai_fns not implemented"),
|
||||
syn::FnArg::Typed(syn::PatType { ref ty, .. }) => {
|
||||
ty.as_ref().to_token_stream().to_string()
|
||||
}
|
||||
syn::FnArg::Typed(syn::PatType { ref ty, .. }) => print_type(ty),
|
||||
};
|
||||
argstr.push('.');
|
||||
argstr.push_str(&type_string);
|
||||
|
@ -286,6 +286,9 @@ mod generate_tests {
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec![].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![].into_boxed_slice()
|
||||
}
|
||||
@ -293,6 +296,9 @@ mod generate_tests {
|
||||
pub fn token_callable() -> CallableFunction {
|
||||
Token().into()
|
||||
}
|
||||
pub fn token_input_names() -> Box<[&'static str]> {
|
||||
Token().input_names()
|
||||
}
|
||||
pub fn token_input_types() -> Box<[TypeId]> {
|
||||
Token().input_types()
|
||||
}
|
||||
@ -328,6 +334,9 @@ mod generate_tests {
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: usize"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<usize>()].into_boxed_slice()
|
||||
}
|
||||
@ -335,6 +344,9 @@ mod generate_tests {
|
||||
pub fn token_callable() -> CallableFunction {
|
||||
Token().into()
|
||||
}
|
||||
pub fn token_input_names() -> Box<[&'static str]> {
|
||||
Token().input_names()
|
||||
}
|
||||
pub fn token_input_types() -> Box<[TypeId]> {
|
||||
Token().input_types()
|
||||
}
|
||||
@ -370,6 +382,9 @@ mod generate_tests {
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: usize"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<usize>()].into_boxed_slice()
|
||||
}
|
||||
@ -377,6 +392,9 @@ mod generate_tests {
|
||||
pub fn token_callable() -> CallableFunction {
|
||||
Token().into()
|
||||
}
|
||||
pub fn token_input_names() -> Box<[&'static str]> {
|
||||
Token().input_names()
|
||||
}
|
||||
pub fn token_input_types() -> Box<[TypeId]> {
|
||||
Token().input_types()
|
||||
}
|
||||
@ -414,6 +432,9 @@ mod generate_tests {
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec![].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![].into_boxed_slice()
|
||||
}
|
||||
@ -421,6 +442,9 @@ mod generate_tests {
|
||||
pub fn token_callable() -> CallableFunction {
|
||||
Token().into()
|
||||
}
|
||||
pub fn token_input_names() -> Box<[&'static str]> {
|
||||
Token().input_names()
|
||||
}
|
||||
pub fn token_input_types() -> Box<[TypeId]> {
|
||||
Token().input_types()
|
||||
}
|
||||
@ -452,6 +476,9 @@ mod generate_tests {
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(MyType()) }
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: usize"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<usize>()].into_boxed_slice()
|
||||
}
|
||||
@ -485,6 +512,9 @@ mod generate_tests {
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: usize", "y: usize"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<usize>(),
|
||||
TypeId::of::<usize>()].into_boxed_slice()
|
||||
@ -493,6 +523,9 @@ mod generate_tests {
|
||||
pub fn token_callable() -> CallableFunction {
|
||||
Token().into()
|
||||
}
|
||||
pub fn token_input_names() -> Box<[&'static str]> {
|
||||
Token().input_names()
|
||||
}
|
||||
pub fn token_input_types() -> Box<[TypeId]> {
|
||||
Token().input_types()
|
||||
}
|
||||
@ -529,6 +562,9 @@ mod generate_tests {
|
||||
fn is_method_call(&self) -> bool { true }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: &mut usize", "y: usize"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<usize>(),
|
||||
TypeId::of::<usize>()].into_boxed_slice()
|
||||
@ -537,6 +573,9 @@ mod generate_tests {
|
||||
pub fn token_callable() -> CallableFunction {
|
||||
Token().into()
|
||||
}
|
||||
pub fn token_input_names() -> Box<[&'static str]> {
|
||||
Token().input_names()
|
||||
}
|
||||
pub fn token_input_types() -> Box<[TypeId]> {
|
||||
Token().input_types()
|
||||
}
|
||||
@ -573,6 +612,9 @@ mod generate_tests {
|
||||
fn is_method_call(&self) -> bool { false }
|
||||
fn is_variadic(&self) -> bool { false }
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["message: &str"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<ImmutableString>()].into_boxed_slice()
|
||||
}
|
||||
@ -580,6 +622,9 @@ mod generate_tests {
|
||||
pub fn token_callable() -> CallableFunction {
|
||||
Token().into()
|
||||
}
|
||||
pub fn token_input_names() -> Box<[&'static str]> {
|
||||
Token().input_names()
|
||||
}
|
||||
pub fn token_input_types() -> Box<[TypeId]> {
|
||||
Token().input_types()
|
||||
}
|
||||
|
@ -257,6 +257,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -291,11 +292,12 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, &[],
|
||||
m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, Some(&[]), &[],
|
||||
get_mystic_number_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
@ -313,6 +315,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(get_mystic_number_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec![].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![].into_boxed_slice()
|
||||
}
|
||||
@ -320,6 +325,9 @@ mod generate_tests {
|
||||
pub fn get_mystic_number_token_callable() -> CallableFunction {
|
||||
get_mystic_number_token().into()
|
||||
}
|
||||
pub fn get_mystic_number_token_input_names() -> Box<[&'static str]> {
|
||||
get_mystic_number_token().input_names()
|
||||
}
|
||||
pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> {
|
||||
get_mystic_number_token().input_types()
|
||||
}
|
||||
@ -352,11 +360,12 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("add_one_to", FnNamespace::Global, FnAccess::Public, &[core::any::TypeId::of::<INT>()],
|
||||
m.set_fn("add_one_to", FnNamespace::Global, FnAccess::Public, Some(&["x: INT"]), &[core::any::TypeId::of::<INT>()],
|
||||
add_one_to_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
@ -375,6 +384,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(add_one_to_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: INT"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<INT>()].into_boxed_slice()
|
||||
}
|
||||
@ -382,6 +394,9 @@ mod generate_tests {
|
||||
pub fn add_one_to_token_callable() -> CallableFunction {
|
||||
add_one_to_token().into()
|
||||
}
|
||||
pub fn add_one_to_token_input_names() -> Box<[&'static str]> {
|
||||
add_one_to_token().input_names()
|
||||
}
|
||||
pub fn add_one_to_token_input_types() -> Box<[TypeId]> {
|
||||
add_one_to_token().input_types()
|
||||
}
|
||||
@ -413,11 +428,12 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("add_one_to", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<INT>()],
|
||||
m.set_fn("add_one_to", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT"]), &[core::any::TypeId::of::<INT>()],
|
||||
add_one_to_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
@ -436,6 +452,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(add_one_to_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: INT"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<INT>()].into_boxed_slice()
|
||||
}
|
||||
@ -443,6 +462,9 @@ mod generate_tests {
|
||||
pub fn add_one_to_token_callable() -> CallableFunction {
|
||||
add_one_to_token().into()
|
||||
}
|
||||
pub fn add_one_to_token_input_names() -> Box<[&'static str]> {
|
||||
add_one_to_token().input_names()
|
||||
}
|
||||
pub fn add_one_to_token_input_types() -> Box<[TypeId]> {
|
||||
add_one_to_token().input_types()
|
||||
}
|
||||
@ -485,14 +507,15 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<INT>()],
|
||||
m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT"]), &[core::any::TypeId::of::<INT>()],
|
||||
add_one_to_token().into());
|
||||
m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<INT>(),
|
||||
core::any::TypeId::of::<INT>()],
|
||||
m.set_fn("add_n", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]),
|
||||
&[core::any::TypeId::of::<INT>(), core::any::TypeId::of::<INT>()],
|
||||
add_n_to_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
@ -511,6 +534,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(add_one_to_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: INT"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<INT>()].into_boxed_slice()
|
||||
}
|
||||
@ -518,6 +544,9 @@ mod generate_tests {
|
||||
pub fn add_one_to_token_callable() -> CallableFunction {
|
||||
add_one_to_token().into()
|
||||
}
|
||||
pub fn add_one_to_token_input_names() -> Box<[&'static str]> {
|
||||
add_one_to_token().input_names()
|
||||
}
|
||||
pub fn add_one_to_token_input_types() -> Box<[TypeId]> {
|
||||
add_one_to_token().input_types()
|
||||
}
|
||||
@ -538,6 +567,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(add_n_to_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: INT", "y: INT"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<INT>(),
|
||||
TypeId::of::<INT>()].into_boxed_slice()
|
||||
@ -546,6 +578,9 @@ mod generate_tests {
|
||||
pub fn add_n_to_token_callable() -> CallableFunction {
|
||||
add_n_to_token().into()
|
||||
}
|
||||
pub fn add_n_to_token_input_names() -> Box<[&'static str]> {
|
||||
add_n_to_token().input_names()
|
||||
}
|
||||
pub fn add_n_to_token_input_types() -> Box<[TypeId]> {
|
||||
add_n_to_token().input_types()
|
||||
}
|
||||
@ -577,12 +612,13 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<INT>(),
|
||||
core::any::TypeId::of::<INT>()],
|
||||
m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]),
|
||||
&[core::any::TypeId::of::<INT>(), core::any::TypeId::of::<INT>()],
|
||||
add_together_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
@ -602,6 +638,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(add_together_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: INT", "y: INT"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<INT>(),
|
||||
TypeId::of::<INT>()].into_boxed_slice()
|
||||
@ -610,6 +649,9 @@ mod generate_tests {
|
||||
pub fn add_together_token_callable() -> CallableFunction {
|
||||
add_together_token().into()
|
||||
}
|
||||
pub fn add_together_token_input_names() -> Box<[&'static str]> {
|
||||
add_together_token().input_names()
|
||||
}
|
||||
pub fn add_together_token_input_types() -> Box<[TypeId]> {
|
||||
add_together_token().input_types()
|
||||
}
|
||||
@ -642,18 +684,19 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("add", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<INT>(),
|
||||
core::any::TypeId::of::<INT>()],
|
||||
m.set_fn("add", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]),
|
||||
&[core::any::TypeId::of::<INT>(), core::any::TypeId::of::<INT>()],
|
||||
add_together_token().into());
|
||||
m.set_fn("+", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<INT>(),
|
||||
core::any::TypeId::of::<INT>()],
|
||||
m.set_fn("+", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]),
|
||||
&[core::any::TypeId::of::<INT>(), core::any::TypeId::of::<INT>()],
|
||||
add_together_token().into());
|
||||
m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<INT>(),
|
||||
core::any::TypeId::of::<INT>()],
|
||||
m.set_fn("add_together", FnNamespace::Internal, FnAccess::Public, Some(&["x: INT", "y: INT"]),
|
||||
&[core::any::TypeId::of::<INT>(), core::any::TypeId::of::<INT>()],
|
||||
add_together_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
@ -673,6 +716,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(add_together_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: INT", "y: INT"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<INT>(),
|
||||
TypeId::of::<INT>()].into_boxed_slice()
|
||||
@ -681,6 +727,9 @@ mod generate_tests {
|
||||
pub fn add_together_token_callable() -> CallableFunction {
|
||||
add_together_token().into()
|
||||
}
|
||||
pub fn add_together_token_input_names() -> Box<[&'static str]> {
|
||||
add_together_token().input_names()
|
||||
}
|
||||
pub fn add_together_token_input_types() -> Box<[TypeId]> {
|
||||
add_together_token().input_types()
|
||||
}
|
||||
@ -714,6 +763,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -745,6 +795,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -778,6 +829,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -813,6 +865,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -848,6 +901,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -889,11 +943,12 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, &[],
|
||||
m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public, Some(&[]), &[],
|
||||
get_mystic_number_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
@ -911,6 +966,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(get_mystic_number_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec![].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![].into_boxed_slice()
|
||||
}
|
||||
@ -918,6 +976,9 @@ mod generate_tests {
|
||||
pub fn get_mystic_number_token_callable() -> CallableFunction {
|
||||
get_mystic_number_token().into()
|
||||
}
|
||||
pub fn get_mystic_number_token_input_names() -> Box<[&'static str]> {
|
||||
get_mystic_number_token().input_names()
|
||||
}
|
||||
pub fn get_mystic_number_token_input_types() -> Box<[TypeId]> {
|
||||
get_mystic_number_token().input_types()
|
||||
}
|
||||
@ -945,6 +1006,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -979,12 +1041,13 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("print_out_to", FnNamespace::Internal, FnAccess::Public,
|
||||
&[core::any::TypeId::of::<ImmutableString>()],
|
||||
Some(&["x: &str"]), &[core::any::TypeId::of::<ImmutableString>()],
|
||||
print_out_to_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
@ -1003,6 +1066,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(print_out_to_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: &str"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<ImmutableString>()].into_boxed_slice()
|
||||
}
|
||||
@ -1010,6 +1076,9 @@ mod generate_tests {
|
||||
pub fn print_out_to_token_callable() -> CallableFunction {
|
||||
print_out_to_token().into()
|
||||
}
|
||||
pub fn print_out_to_token_input_names() -> Box<[&'static str]> {
|
||||
print_out_to_token().input_names()
|
||||
}
|
||||
pub fn print_out_to_token_input_types() -> Box<[TypeId]> {
|
||||
print_out_to_token().input_types()
|
||||
}
|
||||
@ -1041,12 +1110,13 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("print_out_to", FnNamespace::Internal, FnAccess::Public,
|
||||
&[core::any::TypeId::of::<ImmutableString>()],
|
||||
Some(&["x: String"]), &[core::any::TypeId::of::<ImmutableString>()],
|
||||
print_out_to_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
@ -1065,6 +1135,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(print_out_to_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: String"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<ImmutableString>()].into_boxed_slice()
|
||||
}
|
||||
@ -1072,6 +1145,9 @@ mod generate_tests {
|
||||
pub fn print_out_to_token_callable() -> CallableFunction {
|
||||
print_out_to_token().into()
|
||||
}
|
||||
pub fn print_out_to_token_input_names() -> Box<[&'static str]> {
|
||||
print_out_to_token().input_names()
|
||||
}
|
||||
pub fn print_out_to_token_input_types() -> Box<[TypeId]> {
|
||||
print_out_to_token().input_types()
|
||||
}
|
||||
@ -1103,12 +1179,13 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("increment", FnNamespace::Internal, FnAccess::Public,
|
||||
&[core::any::TypeId::of::<FLOAT>()],
|
||||
Some(&["x: &mut FLOAT"]), &[core::any::TypeId::of::<FLOAT>()],
|
||||
increment_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
@ -1127,6 +1204,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(increment_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: &mut FLOAT"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<FLOAT>()].into_boxed_slice()
|
||||
}
|
||||
@ -1134,6 +1214,9 @@ mod generate_tests {
|
||||
pub fn increment_token_callable() -> CallableFunction {
|
||||
increment_token().into()
|
||||
}
|
||||
pub fn increment_token_input_names() -> Box<[&'static str]> {
|
||||
increment_token().input_names()
|
||||
}
|
||||
pub fn increment_token_input_types() -> Box<[TypeId]> {
|
||||
increment_token().input_types()
|
||||
}
|
||||
@ -1168,12 +1251,13 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("increment", FnNamespace::Internal, FnAccess::Public,
|
||||
&[core::any::TypeId::of::<FLOAT>()],
|
||||
Some(&["x: &mut FLOAT"]), &[core::any::TypeId::of::<FLOAT>()],
|
||||
increment_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
@ -1192,6 +1276,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(increment_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: &mut FLOAT"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<FLOAT>()].into_boxed_slice()
|
||||
}
|
||||
@ -1199,6 +1286,9 @@ mod generate_tests {
|
||||
pub fn increment_token_callable() -> CallableFunction {
|
||||
increment_token().into()
|
||||
}
|
||||
pub fn increment_token_input_names() -> Box<[&'static str]> {
|
||||
increment_token().input_names()
|
||||
}
|
||||
pub fn increment_token_input_types() -> Box<[TypeId]> {
|
||||
increment_token().input_types()
|
||||
}
|
||||
@ -1209,6 +1299,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -1253,12 +1344,13 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("increment", FnNamespace::Internal, FnAccess::Public,
|
||||
&[core::any::TypeId::of::<FLOAT>()],
|
||||
Some(&["x: &mut FLOAT"]), &[core::any::TypeId::of::<FLOAT>()],
|
||||
increment_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
@ -1277,6 +1369,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(increment_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: &mut FLOAT"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<FLOAT>()].into_boxed_slice()
|
||||
}
|
||||
@ -1284,6 +1379,9 @@ mod generate_tests {
|
||||
pub fn increment_token_callable() -> CallableFunction {
|
||||
increment_token().into()
|
||||
}
|
||||
pub fn increment_token_input_names() -> Box<[&'static str]> {
|
||||
increment_token().input_names()
|
||||
}
|
||||
pub fn increment_token_input_types() -> Box<[TypeId]> {
|
||||
increment_token().input_types()
|
||||
}
|
||||
@ -1294,6 +1392,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -1337,11 +1436,12 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<u64>()],
|
||||
m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64"]), &[core::any::TypeId::of::<u64>()],
|
||||
int_foo_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
@ -1360,6 +1460,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(int_foo_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: &mut u64"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<u64>()].into_boxed_slice()
|
||||
}
|
||||
@ -1367,6 +1470,9 @@ mod generate_tests {
|
||||
pub fn int_foo_token_callable() -> CallableFunction {
|
||||
int_foo_token().into()
|
||||
}
|
||||
pub fn int_foo_token_input_names() -> Box<[&'static str]> {
|
||||
int_foo_token().input_names()
|
||||
}
|
||||
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
|
||||
int_foo_token().input_types()
|
||||
}
|
||||
@ -1399,13 +1505,14 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("square", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<u64>()],
|
||||
m.set_fn("square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64"]), &[core::any::TypeId::of::<u64>()],
|
||||
int_foo_token().into());
|
||||
m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, &[core::any::TypeId::of::<u64>()],
|
||||
m.set_fn("get$square", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64"]), &[core::any::TypeId::of::<u64>()],
|
||||
int_foo_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
@ -1424,6 +1531,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(int_foo_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: &mut u64"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<u64>()].into_boxed_slice()
|
||||
}
|
||||
@ -1431,6 +1541,9 @@ mod generate_tests {
|
||||
pub fn int_foo_token_callable() -> CallableFunction {
|
||||
int_foo_token().into()
|
||||
}
|
||||
pub fn int_foo_token_input_names() -> Box<[&'static str]> {
|
||||
int_foo_token().input_names()
|
||||
}
|
||||
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
|
||||
int_foo_token().input_types()
|
||||
}
|
||||
@ -1463,13 +1576,13 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public,
|
||||
&[core::any::TypeId::of::<u64>(),
|
||||
core::any::TypeId::of::<u64>()],
|
||||
m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64"]),
|
||||
&[core::any::TypeId::of::<u64>(), core::any::TypeId::of::<u64>()],
|
||||
int_foo_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
@ -1489,6 +1602,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(int_foo_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: &mut u64", "y: u64"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<u64>(), TypeId::of::<u64>()].into_boxed_slice()
|
||||
}
|
||||
@ -1496,6 +1612,9 @@ mod generate_tests {
|
||||
pub fn int_foo_token_callable() -> CallableFunction {
|
||||
int_foo_token().into()
|
||||
}
|
||||
pub fn int_foo_token_input_names() -> Box<[&'static str]> {
|
||||
int_foo_token().input_names()
|
||||
}
|
||||
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
|
||||
int_foo_token().input_types()
|
||||
}
|
||||
@ -1528,17 +1647,16 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("set_sq", FnNamespace::Internal, FnAccess::Public,
|
||||
&[core::any::TypeId::of::<u64>(),
|
||||
core::any::TypeId::of::<u64>()],
|
||||
m.set_fn("set_sq", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64"]),
|
||||
&[core::any::TypeId::of::<u64>(), core::any::TypeId::of::<u64>()],
|
||||
int_foo_token().into());
|
||||
m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public,
|
||||
&[core::any::TypeId::of::<u64>(),
|
||||
core::any::TypeId::of::<u64>()],
|
||||
m.set_fn("set$squared", FnNamespace::Internal, FnAccess::Public, Some(&["x: &mut u64", "y: u64"]),
|
||||
&[core::any::TypeId::of::<u64>(), core::any::TypeId::of::<u64>()],
|
||||
int_foo_token().into());
|
||||
if flatten {} else {}
|
||||
}
|
||||
@ -1558,6 +1676,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(int_foo_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: &mut u64", "y: u64"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<u64>(), TypeId::of::<u64>()].into_boxed_slice()
|
||||
}
|
||||
@ -1565,6 +1686,9 @@ mod generate_tests {
|
||||
pub fn int_foo_token_callable() -> CallableFunction {
|
||||
int_foo_token().into()
|
||||
}
|
||||
pub fn int_foo_token_input_names() -> Box<[&'static str]> {
|
||||
int_foo_token().input_names()
|
||||
}
|
||||
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
|
||||
int_foo_token().input_types()
|
||||
}
|
||||
@ -1597,11 +1721,13 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("index$get$", FnNamespace::Internal, FnAccess::Public,
|
||||
Some(&["x: &mut MyCollection", "i: u64"]),
|
||||
&[core::any::TypeId::of::<MyCollection>(),
|
||||
core::any::TypeId::of::<u64>()],
|
||||
get_by_index_token().into());
|
||||
@ -1623,6 +1749,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(get_by_index_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: &mut MyCollection", "i: u64"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<MyCollection>(),
|
||||
TypeId::of::<u64>()].into_boxed_slice()
|
||||
@ -1631,6 +1760,9 @@ mod generate_tests {
|
||||
pub fn get_by_index_token_callable() -> CallableFunction {
|
||||
get_by_index_token().into()
|
||||
}
|
||||
pub fn get_by_index_token_input_names() -> Box<[&'static str]> {
|
||||
get_by_index_token().input_names()
|
||||
}
|
||||
pub fn get_by_index_token_input_types() -> Box<[TypeId]> {
|
||||
get_by_index_token().input_types()
|
||||
}
|
||||
@ -1663,15 +1795,18 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("get", FnNamespace::Internal, FnAccess::Public,
|
||||
Some(&["x: &mut MyCollection", "i: u64"]),
|
||||
&[core::any::TypeId::of::<MyCollection>(),
|
||||
core::any::TypeId::of::<u64>()],
|
||||
get_by_index_token().into());
|
||||
m.set_fn("index$get$", FnNamespace::Internal, FnAccess::Public,
|
||||
Some(&["x: &mut MyCollection", "i: u64"]),
|
||||
&[core::any::TypeId::of::<MyCollection>(),
|
||||
core::any::TypeId::of::<u64>()],
|
||||
get_by_index_token().into());
|
||||
@ -1693,6 +1828,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(get_by_index_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: &mut MyCollection", "i: u64"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<MyCollection>(),
|
||||
TypeId::of::<u64>()].into_boxed_slice()
|
||||
@ -1701,6 +1839,9 @@ mod generate_tests {
|
||||
pub fn get_by_index_token_callable() -> CallableFunction {
|
||||
get_by_index_token().into()
|
||||
}
|
||||
pub fn get_by_index_token_input_names() -> Box<[&'static str]> {
|
||||
get_by_index_token().input_names()
|
||||
}
|
||||
pub fn get_by_index_token_input_types() -> Box<[TypeId]> {
|
||||
get_by_index_token().input_types()
|
||||
}
|
||||
@ -1733,11 +1874,13 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("index$set$", FnNamespace::Internal, FnAccess::Public,
|
||||
Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT"]),
|
||||
&[core::any::TypeId::of::<MyCollection>(),
|
||||
core::any::TypeId::of::<u64>(),
|
||||
core::any::TypeId::of::<FLOAT>()],
|
||||
@ -1761,6 +1904,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(set_by_index_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: &mut MyCollection", "i: u64", "item: FLOAT"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<MyCollection>(),
|
||||
TypeId::of::<u64>(),
|
||||
@ -1770,6 +1916,9 @@ mod generate_tests {
|
||||
pub fn set_by_index_token_callable() -> CallableFunction {
|
||||
set_by_index_token().into()
|
||||
}
|
||||
pub fn set_by_index_token_input_names() -> Box<[&'static str]> {
|
||||
set_by_index_token().input_names()
|
||||
}
|
||||
pub fn set_by_index_token_input_types() -> Box<[TypeId]> {
|
||||
set_by_index_token().input_types()
|
||||
}
|
||||
@ -1802,16 +1951,19 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||
m.set_fn("set", FnNamespace::Internal, FnAccess::Public,
|
||||
Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT"]),
|
||||
&[core::any::TypeId::of::<MyCollection>(),
|
||||
core::any::TypeId::of::<u64>(),
|
||||
core::any::TypeId::of::<FLOAT>()],
|
||||
set_by_index_token().into());
|
||||
m.set_fn("index$set$", FnNamespace::Internal, FnAccess::Public,
|
||||
Some(&["x: &mut MyCollection", "i: u64", "item: FLOAT"]),
|
||||
&[core::any::TypeId::of::<MyCollection>(),
|
||||
core::any::TypeId::of::<u64>(),
|
||||
core::any::TypeId::of::<FLOAT>()],
|
||||
@ -1835,6 +1987,9 @@ mod generate_tests {
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
|
||||
Box::new(set_by_index_token())
|
||||
}
|
||||
fn input_names(&self) -> Box<[&'static str]> {
|
||||
new_vec!["x: &mut MyCollection", "i: u64", "item: FLOAT"].into_boxed_slice()
|
||||
}
|
||||
fn input_types(&self) -> Box<[TypeId]> {
|
||||
new_vec![TypeId::of::<MyCollection>(),
|
||||
TypeId::of::<u64>(),
|
||||
@ -1844,6 +1999,9 @@ mod generate_tests {
|
||||
pub fn set_by_index_token_callable() -> CallableFunction {
|
||||
set_by_index_token().into()
|
||||
}
|
||||
pub fn set_by_index_token_input_names() -> Box<[&'static str]> {
|
||||
set_by_index_token().input_names()
|
||||
}
|
||||
pub fn set_by_index_token_input_types() -> Box<[TypeId]> {
|
||||
set_by_index_token().input_types()
|
||||
}
|
||||
@ -1874,6 +2032,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -1888,6 +2047,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -1928,6 +2088,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -1944,6 +2105,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -1958,6 +2120,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -2024,6 +2187,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -2040,6 +2204,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -2054,6 +2219,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -2077,6 +2243,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -2091,6 +2258,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -2116,6 +2284,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -2132,6 +2301,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -2146,6 +2316,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
@ -2167,6 +2338,7 @@ mod generate_tests {
|
||||
pub fn rhai_module_generate() -> Module {
|
||||
let mut m = Module::new();
|
||||
rhai_generate_into_module(&mut m, false);
|
||||
m.build_index();
|
||||
m
|
||||
}
|
||||
#[allow(unused_mut)]
|
||||
|
@ -97,7 +97,7 @@ The Rhai Scripting Language
|
||||
19. [Modules](language/modules/index.md)
|
||||
1. [Export Variables, Functions and Sub-Modules](language/modules/export.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)
|
||||
1. [Checked Arithmetic](safety/checked.md)
|
||||
2. [Sand-Boxing](safety/sandbox.md)
|
||||
|
@ -9,8 +9,6 @@ Keywords List
|
||||
| `false` | boolean false literal | | no | |
|
||||
| `let` | variable declaration | | no | |
|
||||
| `const` | constant declaration | | no | |
|
||||
| `is_def_var` | is a variable declared? | | yes | yes |
|
||||
| `is_shared` | is a value shared? | [`no_closure`] | yes | no |
|
||||
| `if` | if statement | | no | |
|
||||
| `else` | else block of if statement | | no | |
|
||||
| `switch` | matching | | no | |
|
||||
@ -35,7 +33,6 @@ Keywords List
|
||||
| `call` | call a [function pointer] | | yes | no |
|
||||
| `curry` | curry a [function pointer] | | yes | no |
|
||||
| `this` | reference to base object for method call | [`no_function`] | no | |
|
||||
| `is_def_fn` | is a scripted function defined? | [`no_function`] | yes | yes |
|
||||
| `type_of` | get type name of value | | yes | yes |
|
||||
| `print` | print value | | yes | yes |
|
||||
| `debug` | print value in debug format | | yes | yes |
|
||||
@ -49,6 +46,8 @@ Reserved Keywords
|
||||
| --------- | --------------------- |
|
||||
| `var` | variable declaration |
|
||||
| `static` | variable declaration |
|
||||
| `begin` | block scope |
|
||||
| `end` | block scope |
|
||||
| `shared` | share value |
|
||||
| `each` | looping |
|
||||
| `then` | control flow |
|
||||
|
@ -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).
|
||||
|
||||
```rust
|
||||
use rhai::{Engine, Scope};
|
||||
use rhai::{Engine, Scope, RegisterFn};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
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_get_set("value",
|
||||
|obj: &mut TestStruct| obj.0, // property getter
|
||||
|obj: &mut TestStruct, value: i64| obj.0 = value // property setter
|
||||
.register_get("value", |obj: &mut TestStruct| obj.0), // property getter
|
||||
.register_fn("update_value",
|
||||
|obj: &mut TestStruct, value: i64| obj.0 = value // mutating method
|
||||
);
|
||||
|
||||
let mut scope = Scope::new(); // create custom scope
|
||||
|
||||
scope.push_constant("MY_NUMBER", TestStruct(123_i64)); // add constant variable
|
||||
|
||||
engine.consume_with_scope(&mut scope, r"
|
||||
MY_NUMBER.value = 42; // constant objects can be modified
|
||||
// Beware: constant objects can still be modified via a method call!
|
||||
engine.consume_with_scope(&mut scope,
|
||||
r"
|
||||
MY_NUMBER.update_value(42);
|
||||
print(MY_NUMBER.value); // prints 42
|
||||
")?;
|
||||
```
|
||||
|
@ -1,4 +1,4 @@
|
||||
`eval` Statement
|
||||
`eval` Function
|
||||
===============
|
||||
|
||||
{{#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),
|
||||
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
|
||||
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())
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
`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
|
||||
```
|
||||
|
@ -104,7 +104,7 @@ This is similar to Rust and many other modern languages, such as JavaScript's `f
|
||||
`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.
|
||||
|
||||
```rust
|
||||
|
@ -6,13 +6,14 @@ Keywords
|
||||
The following are reserved keywords in Rhai:
|
||||
|
||||
| Active keywords | Reserved keywords | Usage | Inactive under feature |
|
||||
| ------------------------------------------------- | ---------------------------------------------------------- | ---------------------- | :--------------------: |
|
||||
| `true`, `false` | | boolean constants | |
|
||||
| `let`, `const` | `var`, `static` | variable declarations | |
|
||||
| ---------------------------------------------------------------- | ---------------------------------------------------------- | ---------------------- | :--------------------: |
|
||||
| `true`, `false` | | constants | |
|
||||
| `let`, `const` | `var`, `static` | variables | |
|
||||
| | `begin`, `end` | block scopes | |
|
||||
| `is_shared` | | shared values | [`no_closure`] |
|
||||
| `if`, `else` | `then`, `goto`, `exit` | control flow | |
|
||||
| | `switch`, `match`, `case` | matching | |
|
||||
| `while`, `loop`, `for`, `in`, `continue`, `break` | `do`, `each` | looping | |
|
||||
| `if`, `else` | `then`, `unless`, `goto`, `exit` | control flow | |
|
||||
| `switch` | `match`, `case` | switching and matching | |
|
||||
| `do`, `while`, `loop`, `until`, `for`, `in`, `continue`, `break` | `each` | looping | |
|
||||
| `fn`, `private` | `public`, `new` | functions | [`no_function`] |
|
||||
| `return` | | return values | |
|
||||
| `throw`, `try`, `catch` | | throw/catch exceptions | |
|
||||
|
@ -9,7 +9,7 @@ Terminated by '`;`'
|
||||
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.
|
||||
|
||||
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).
|
||||
|
||||
```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
|
||||
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 [`()`].
|
||||
|
@ -19,7 +19,6 @@ Built-In Packages
|
||||
| `BasicArrayPackage` | basic [array] functions (not available under `no_index`) | no | yes |
|
||||
| `BasicMapPackage` | basic [object map] functions (not available under `no_object`) | no | yes |
|
||||
| `BasicFnPackage` | basic methods for [function pointers]. | yes | yes |
|
||||
| `EvalPackage` | disable [`eval`] | no | no |
|
||||
| `CorePackage` | basic essentials | yes | yes |
|
||||
| `StandardPackage` | standard library (default for `Engine::new`) | no | yes |
|
||||
|
||||
|
@ -42,6 +42,7 @@ fn print_help() {
|
||||
println!("help => print this help");
|
||||
println!("quit, exit => quit");
|
||||
println!("scope => print all variables in the scope");
|
||||
println!("functions => print all functions defined");
|
||||
println!("ast => print the last AST");
|
||||
println!("astu => print the last raw, un-optimized AST");
|
||||
println!(r"end a line with '\' to continue to the next line.");
|
||||
@ -133,6 +134,21 @@ fn main() {
|
||||
println!("{:#?}\n", &ast);
|
||||
continue;
|
||||
}
|
||||
"functions" => {
|
||||
// print a list of all registered functions
|
||||
engine
|
||||
.gen_fn_signatures(false)
|
||||
.into_iter()
|
||||
.for_each(|f| println!("{}", f));
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
main_ast
|
||||
.iter_functions()
|
||||
.for_each(|(_, _, _, _, f)| println!("{}", f));
|
||||
|
||||
println!();
|
||||
continue;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,7 @@ impl fmt::Display for ScriptFnDef {
|
||||
.iter()
|
||||
.map(|s| s.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
.join(",")
|
||||
.join(", ")
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1154,8 +1154,8 @@ mod tests {
|
||||
assert_eq!(size_of::<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::LexError>(), 32);
|
||||
assert_eq!(size_of::<crate::LexError>(), 56);
|
||||
assert_eq!(size_of::<crate::ParseError>(), 16);
|
||||
assert_eq!(size_of::<crate::EvalAltResult>(), 64);
|
||||
assert_eq!(size_of::<crate::EvalAltResult>(), 72);
|
||||
}
|
||||
}
|
||||
|
@ -95,24 +95,25 @@ impl Imports {
|
||||
self.0.as_mut().unwrap().truncate(size);
|
||||
}
|
||||
}
|
||||
/// Get an iterator to this stack of imported modules.
|
||||
/// Get an iterator to this stack of imported modules in reverse order.
|
||||
#[allow(dead_code)]
|
||||
pub fn iter(&self) -> impl Iterator<Item = (&str, Shared<Module>)> {
|
||||
self.0.iter().flat_map(|lib| {
|
||||
lib.iter()
|
||||
.rev()
|
||||
.map(|(name, module)| (name.as_str(), module.clone()))
|
||||
})
|
||||
}
|
||||
/// Get an iterator to this stack of imported modules.
|
||||
/// Get an iterator to this stack of imported modules in reverse order.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn iter_raw<'a>(
|
||||
&'a self,
|
||||
) -> impl Iterator<Item = (ImmutableString, Shared<Module>)> + 'a {
|
||||
self.0.iter().flat_map(|lib| lib.iter().cloned())
|
||||
self.0.iter().flat_map(|lib| lib.iter().rev().cloned())
|
||||
}
|
||||
/// Get a consuming iterator to this stack of imported modules.
|
||||
/// Get a consuming iterator to this stack of imported modules in reverse order.
|
||||
pub fn into_iter(self) -> impl Iterator<Item = (ImmutableString, Shared<Module>)> {
|
||||
self.0.into_iter().flat_map(|lib| lib.into_iter())
|
||||
self.0.into_iter().flat_map(|lib| lib.into_iter().rev())
|
||||
}
|
||||
/// Add a stream of imported modules.
|
||||
pub fn extend(&mut self, stream: impl Iterator<Item = (ImmutableString, Shared<Module>)>) {
|
||||
@ -178,9 +179,7 @@ pub const KEYWORD_FN_PTR_CURRY: &str = "curry";
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
pub const KEYWORD_IS_SHARED: &str = "is_shared";
|
||||
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 FN_TO_STRING: &str = "to_string";
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
pub const FN_GET: &str = "get$";
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
|
@ -7,8 +7,10 @@ use crate::optimize::OptimizationLevel;
|
||||
use crate::stdlib::{
|
||||
any::{type_name, TypeId},
|
||||
boxed::Box,
|
||||
format,
|
||||
hash::{Hash, Hasher},
|
||||
string::String,
|
||||
vec::Vec,
|
||||
};
|
||||
use crate::utils::get_hasher;
|
||||
use crate::{
|
||||
@ -1515,7 +1517,7 @@ impl Engine {
|
||||
.into()
|
||||
});
|
||||
}
|
||||
/// Call a script function defined in an [`AST`] with multiple `Dynamic` arguments
|
||||
/// Call a script function defined in an [`AST`] with multiple [`Dynamic`] arguments
|
||||
/// and optionally a value for binding to the `this` pointer.
|
||||
///
|
||||
/// ## WARNING
|
||||
@ -1578,7 +1580,7 @@ impl Engine {
|
||||
|
||||
self.call_fn_dynamic_raw(scope, &[lib.as_ref()], name, &mut this_ptr, args.as_mut())
|
||||
}
|
||||
/// Call a script function defined in an [`AST`] with multiple `Dynamic` arguments.
|
||||
/// Call a script function defined in an [`AST`] with multiple [`Dynamic`] arguments.
|
||||
///
|
||||
/// ## WARNING
|
||||
///
|
||||
@ -1646,6 +1648,27 @@ impl Engine {
|
||||
let stmt = crate::stdlib::mem::take(ast.statements_mut());
|
||||
crate::optimize::optimize_into_ast(self, scope, stmt, lib, optimization_level)
|
||||
}
|
||||
/// Generate a list of all registered functions.
|
||||
///
|
||||
/// The ordering is:
|
||||
/// 1) Functions registered into the global namespace
|
||||
/// 2) Functions in registered sub-modules
|
||||
/// 3) Functions in packages
|
||||
pub fn gen_fn_signatures(&self, include_packages: bool) -> Vec<String> {
|
||||
let mut signatures: Vec<_> = Default::default();
|
||||
|
||||
signatures.extend(self.global_namespace.gen_fn_signatures());
|
||||
|
||||
self.global_sub_modules.iter().for_each(|(name, m)| {
|
||||
signatures.extend(m.gen_fn_signatures().map(|f| format!("{}::{}", name, f)))
|
||||
});
|
||||
|
||||
if include_packages {
|
||||
signatures.extend(self.packages.gen_fn_signatures());
|
||||
}
|
||||
|
||||
signatures
|
||||
}
|
||||
/// Provide a callback that will be invoked before each variable access.
|
||||
///
|
||||
/// ## Return Value of Callback
|
||||
|
@ -3,8 +3,7 @@
|
||||
use crate::ast::{Expr, Stmt};
|
||||
use crate::engine::{
|
||||
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_PRINT, KEYWORD_TYPE_OF,
|
||||
KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
||||
};
|
||||
use crate::fn_native::FnCallArgs;
|
||||
use crate::module::NamespaceRef;
|
||||
@ -419,7 +418,7 @@ impl Engine {
|
||||
#[inline]
|
||||
pub(crate) fn has_override_by_name_and_arguments(
|
||||
&self,
|
||||
mods: &Imports,
|
||||
mods: Option<&Imports>,
|
||||
lib: &[&Module],
|
||||
fn_name: &str,
|
||||
arg_types: impl AsRef<[TypeId]>,
|
||||
@ -436,7 +435,7 @@ impl Engine {
|
||||
#[inline(always)]
|
||||
pub(crate) fn has_override(
|
||||
&self,
|
||||
mods: &Imports,
|
||||
mods: Option<&Imports>,
|
||||
lib: &[&Module],
|
||||
hash_fn: u64,
|
||||
hash_script: u64,
|
||||
@ -454,8 +453,7 @@ impl Engine {
|
||||
|| self.packages.contains_fn(hash_script)
|
||||
|| self.packages.contains_fn(hash_fn)
|
||||
// Then check imported modules
|
||||
|| mods.contains_fn(hash_script)
|
||||
|| mods.contains_fn(hash_fn)
|
||||
|| mods.map(|m| m.contains_fn(hash_script) || m.contains_fn(hash_fn)).unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Perform an actual function call, native Rust or scripted, taking care of special functions.
|
||||
@ -494,7 +492,7 @@ impl Engine {
|
||||
// type_of
|
||||
KEYWORD_TYPE_OF
|
||||
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((
|
||||
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.
|
||||
KEYWORD_FN_PTR | KEYWORD_EVAL
|
||||
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(
|
||||
format!(
|
||||
@ -521,7 +519,7 @@ impl Engine {
|
||||
|
||||
// Script-like function found
|
||||
#[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
|
||||
let func = lib
|
||||
.iter()
|
||||
@ -856,7 +854,7 @@ impl Engine {
|
||||
let hash_fn =
|
||||
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
|
||||
return self
|
||||
.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?
|
||||
@ -912,7 +910,7 @@ impl Engine {
|
||||
|
||||
if name == KEYWORD_FN_PTR_CALL
|
||||
&& 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)?;
|
||||
|
||||
@ -942,7 +940,7 @@ impl Engine {
|
||||
if name == KEYWORD_IS_DEF_VAR && args_expr.len() == 1 {
|
||||
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 =
|
||||
self.eval_expr(scope, mods, state, lib, this_ptr, &args_expr[0], level)?;
|
||||
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()
|
||||
if name == KEYWORD_EVAL && args_expr.len() == 1 {
|
||||
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
|
||||
let prev_len = scope.len();
|
||||
let script =
|
||||
|
@ -49,8 +49,8 @@ pub type Locked<T> = crate::stdlib::sync::RwLock<T>;
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct NativeCallContext<'e, 'a, 'm, 'pm: 'm> {
|
||||
engine: &'e Engine,
|
||||
mods: Option<&'a Imports>,
|
||||
lib: &'m [&'pm Module],
|
||||
pub(crate) mods: Option<&'a Imports>,
|
||||
pub(crate) lib: &'m [&'pm Module],
|
||||
}
|
||||
|
||||
impl<'e, 'a, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized> From<(&'e Engine, &'a Imports, &'m M)>
|
||||
|
@ -187,7 +187,7 @@ macro_rules! def_register {
|
||||
{
|
||||
#[inline]
|
||||
fn register_fn(&mut self, name: &str, f: FN) -> &mut Self {
|
||||
self.global_namespace.set_fn(name, FnNamespace::Global, FnAccess::Public,
|
||||
self.global_namespace.set_fn(name, FnNamespace::Global, FnAccess::Public, None,
|
||||
&[$(map_type_id::<$par>()),*],
|
||||
CallableFunction::$abi(make_func!(f : map_dynamic ; $($par => $let => $clone => $arg),*))
|
||||
);
|
||||
@ -202,7 +202,7 @@ macro_rules! def_register {
|
||||
{
|
||||
#[inline]
|
||||
fn register_result_fn(&mut self, name: &str, f: FN) -> &mut Self {
|
||||
self.global_namespace.set_fn(name, FnNamespace::Global, FnAccess::Public,
|
||||
self.global_namespace.set_fn(name, FnNamespace::Global, FnAccess::Public, None,
|
||||
&[$(map_type_id::<$par>()),*],
|
||||
CallableFunction::$abi(make_func!(f : map_result ; $($par => $let => $clone => $arg),*))
|
||||
);
|
||||
|
@ -2,9 +2,7 @@
|
||||
|
||||
use crate::ast::{FnAccess, IdentX};
|
||||
use crate::dynamic::Variant;
|
||||
use crate::fn_native::{
|
||||
shared_make_mut, shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, SendSync,
|
||||
};
|
||||
use crate::fn_native::{shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, SendSync};
|
||||
use crate::fn_register::by_value as cast_arg;
|
||||
use crate::stdlib::{
|
||||
any::TypeId,
|
||||
@ -81,7 +79,31 @@ pub struct FuncInfo {
|
||||
/// Number of parameters.
|
||||
pub params: usize,
|
||||
/// Parameter types (if applicable).
|
||||
pub types: Option<StaticVec<TypeId>>,
|
||||
pub param_types: Option<StaticVec<TypeId>>,
|
||||
/// Parameter names (if available).
|
||||
pub param_names: Option<StaticVec<ImmutableString>>,
|
||||
}
|
||||
|
||||
impl FuncInfo {
|
||||
/// Generate a signature of the function.
|
||||
pub fn gen_signature(&self) -> String {
|
||||
let mut sig = format!("{}(", self.name);
|
||||
|
||||
if let Some(ref names) = self.param_names {
|
||||
let params: Vec<_> = names.iter().map(ImmutableString::to_string).collect();
|
||||
sig.push_str(¶ms.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,
|
||||
@ -232,6 +254,14 @@ impl Module {
|
||||
self.indexed
|
||||
}
|
||||
|
||||
/// Generate signatures for all the functions in the module.
|
||||
pub fn gen_fn_signatures<'a>(&'a self) -> impl Iterator<Item = String> + 'a {
|
||||
self.functions
|
||||
.values()
|
||||
.filter(|FuncInfo { access, .. }| !access.is_private())
|
||||
.map(FuncInfo::gen_signature)
|
||||
}
|
||||
|
||||
/// Does a variable exist in the module?
|
||||
///
|
||||
/// # Example
|
||||
@ -331,7 +361,8 @@ impl Module {
|
||||
namespace: FnNamespace::Internal,
|
||||
access: fn_def.access,
|
||||
params: num_params,
|
||||
types: None,
|
||||
param_types: None,
|
||||
param_names: Some(fn_def.params.clone()),
|
||||
func: fn_def.into(),
|
||||
},
|
||||
);
|
||||
@ -399,23 +430,6 @@ impl Module {
|
||||
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.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// If there is an existing Rust function of the same hash, it is replaced.
|
||||
@ -481,6 +506,7 @@ impl Module {
|
||||
name: impl Into<String>,
|
||||
namespace: FnNamespace,
|
||||
access: FnAccess,
|
||||
arg_names: Option<&[&str]>,
|
||||
arg_types: &[TypeId],
|
||||
func: CallableFunction,
|
||||
) -> u64 {
|
||||
@ -507,7 +533,8 @@ impl Module {
|
||||
namespace,
|
||||
access,
|
||||
params: params.len(),
|
||||
types: Some(params),
|
||||
param_types: Some(params),
|
||||
param_names: arg_names.map(|p| p.iter().map(|&v| v.into()).collect()),
|
||||
func: func.into(),
|
||||
},
|
||||
);
|
||||
@ -595,6 +622,7 @@ impl Module {
|
||||
name,
|
||||
namespace,
|
||||
access,
|
||||
None,
|
||||
arg_types,
|
||||
CallableFunction::from_method(Box::new(f)),
|
||||
)
|
||||
@ -625,6 +653,7 @@ impl Module {
|
||||
name,
|
||||
FnNamespace::Internal,
|
||||
FnAccess::Public,
|
||||
None,
|
||||
&arg_types,
|
||||
CallableFunction::from_pure(Box::new(f)),
|
||||
)
|
||||
@ -657,6 +686,7 @@ impl Module {
|
||||
name,
|
||||
FnNamespace::Internal,
|
||||
FnAccess::Public,
|
||||
None,
|
||||
&arg_types,
|
||||
CallableFunction::from_pure(Box::new(f)),
|
||||
)
|
||||
@ -692,6 +722,7 @@ impl Module {
|
||||
name,
|
||||
namespace,
|
||||
FnAccess::Public,
|
||||
None,
|
||||
&arg_types,
|
||||
CallableFunction::from_method(Box::new(f)),
|
||||
)
|
||||
@ -757,6 +788,7 @@ impl Module {
|
||||
name,
|
||||
FnNamespace::Internal,
|
||||
FnAccess::Public,
|
||||
None,
|
||||
&arg_types,
|
||||
CallableFunction::from_pure(Box::new(f)),
|
||||
)
|
||||
@ -799,6 +831,7 @@ impl Module {
|
||||
name,
|
||||
namespace,
|
||||
FnAccess::Public,
|
||||
None,
|
||||
&arg_types,
|
||||
CallableFunction::from_method(Box::new(f)),
|
||||
)
|
||||
@ -919,6 +952,7 @@ impl Module {
|
||||
name,
|
||||
FnNamespace::Internal,
|
||||
FnAccess::Public,
|
||||
None,
|
||||
&arg_types,
|
||||
CallableFunction::from_pure(Box::new(f)),
|
||||
)
|
||||
@ -967,6 +1001,7 @@ impl Module {
|
||||
name,
|
||||
namespace,
|
||||
FnAccess::Public,
|
||||
None,
|
||||
&arg_types,
|
||||
CallableFunction::from_method(Box::new(f)),
|
||||
)
|
||||
@ -1027,6 +1062,7 @@ impl Module {
|
||||
crate::engine::FN_IDX_SET,
|
||||
FnNamespace::Internal,
|
||||
FnAccess::Public,
|
||||
None,
|
||||
&arg_types,
|
||||
CallableFunction::from_method(Box::new(f)),
|
||||
)
|
||||
@ -1119,6 +1155,7 @@ impl Module {
|
||||
name,
|
||||
FnNamespace::Internal,
|
||||
FnAccess::Public,
|
||||
None,
|
||||
&arg_types,
|
||||
CallableFunction::from_pure(Box::new(f)),
|
||||
)
|
||||
@ -1174,6 +1211,7 @@ impl Module {
|
||||
name,
|
||||
namespace,
|
||||
FnAccess::Public,
|
||||
None,
|
||||
&arg_types,
|
||||
CallableFunction::from_method(Box::new(f)),
|
||||
)
|
||||
@ -1537,6 +1575,8 @@ impl Module {
|
||||
});
|
||||
}
|
||||
|
||||
module.build_index();
|
||||
|
||||
Ok(module)
|
||||
}
|
||||
|
||||
@ -1544,8 +1584,7 @@ impl Module {
|
||||
/// variables and functions as one flattened namespace.
|
||||
///
|
||||
/// If the module is already indexed, this method has no effect.
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
pub fn build_index(&mut self) {
|
||||
pub fn build_index(&mut self) -> &mut Self {
|
||||
// Collect a particular module.
|
||||
fn index_module<'a>(
|
||||
module: &'a Module,
|
||||
@ -1586,7 +1625,7 @@ impl Module {
|
||||
name,
|
||||
namespace,
|
||||
params,
|
||||
types,
|
||||
param_types: types,
|
||||
func,
|
||||
..
|
||||
},
|
||||
@ -1645,6 +1684,8 @@ impl Module {
|
||||
self.all_type_iterators = type_iterators;
|
||||
self.indexed = true;
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Does a type iterator exist in the entire module tree?
|
||||
|
@ -159,12 +159,10 @@ impl ModuleResolver for FileModuleResolver {
|
||||
_ => 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))
|
||||
})?;
|
||||
|
||||
m.build_index();
|
||||
|
||||
module = Some(m.into());
|
||||
module_ref = module.clone();
|
||||
};
|
||||
|
@ -1,10 +1,7 @@
|
||||
//! Module implementing the AST optimizer.
|
||||
|
||||
use crate::ast::{Expr, ScriptFnDef, Stmt};
|
||||
use crate::engine::{
|
||||
KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_IS_DEF_FN, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT,
|
||||
KEYWORD_TYPE_OF,
|
||||
};
|
||||
use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF};
|
||||
use crate::fn_call::run_builtin_binary_op;
|
||||
use crate::parser::map_dynamic_to_expr;
|
||||
use crate::stdlib::{
|
||||
@ -470,8 +467,6 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
|
||||
KEYWORD_PRINT, // side effects
|
||||
KEYWORD_DEBUG, // side effects
|
||||
KEYWORD_EVAL, // arbitrary scripts
|
||||
KEYWORD_IS_DEF_FN, // functions collection is volatile
|
||||
KEYWORD_IS_DEF_VAR, // variables scope is volatile
|
||||
];
|
||||
|
||||
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();
|
||||
|
||||
// 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])
|
||||
.ok().flatten()
|
||||
.and_then(|result| map_dynamic_to_expr(result, *pos))
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
@ -48,7 +48,8 @@ macro_rules! reg_range {
|
||||
($lib:expr, $x:expr, $( $y:ty ),*) => (
|
||||
$(
|
||||
$lib.set_iterator::<Range<$y>>();
|
||||
$lib.set_fn_2($x, get_range::<$y>);
|
||||
let hash = $lib.set_fn_2($x, get_range::<$y>);
|
||||
$lib.update_fn_param_names(hash, &[concat!("from: ", stringify!($y)), concat!("to: ", stringify!($y))]);
|
||||
)*
|
||||
)
|
||||
}
|
||||
@ -59,14 +60,16 @@ macro_rules! reg_step {
|
||||
($lib:expr, $x:expr, $( $y:ty ),*) => (
|
||||
$(
|
||||
$lib.set_iterator::<StepRange<$y>>();
|
||||
$lib.set_fn_3($x, get_step_range::<$y>);
|
||||
let hash = $lib.set_fn_3($x, get_step_range::<$y>);
|
||||
$lib.update_fn_param_names(hash, &[concat!("from: ", stringify!($y)), concat!("to: ", stringify!($y)), concat!("step: ", stringify!($y))]);
|
||||
)*
|
||||
)
|
||||
}
|
||||
|
||||
def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
|
||||
lib.set_iterator::<Range<INT>>();
|
||||
lib.set_fn_2("range", get_range::<INT>);
|
||||
let hash = lib.set_fn_2("range", get_range::<INT>);
|
||||
lib.update_fn_param_names(hash, &["from: INT", "to: INT"]);
|
||||
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
#[cfg(not(feature = "only_i64"))]
|
||||
@ -79,7 +82,8 @@ def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, {
|
||||
}
|
||||
|
||||
lib.set_iterator::<StepRange<INT>>();
|
||||
lib.set_fn_3("range", get_step_range::<INT>);
|
||||
let hash = lib.set_fn_3("range", get_step_range::<INT>);
|
||||
lib.update_fn_param_names(hash, &["from: INT", "to: INT", "step: INT"]);
|
||||
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
#[cfg(not(feature = "only_i64"))]
|
||||
|
@ -1,12 +1,11 @@
|
||||
//! Module containing all built-in _packages_ available to Rhai, plus facilities to define custom packages.
|
||||
|
||||
use crate::fn_native::{CallableFunction, IteratorFn};
|
||||
use crate::stdlib::any::TypeId;
|
||||
use crate::stdlib::{any::TypeId, string::String};
|
||||
use crate::{Module, Shared, StaticVec};
|
||||
|
||||
pub(crate) mod arithmetic;
|
||||
mod array_basic;
|
||||
mod eval;
|
||||
mod fn_basic;
|
||||
mod iter_basic;
|
||||
mod logic;
|
||||
@ -21,7 +20,6 @@ mod time_basic;
|
||||
pub use arithmetic::ArithmeticPackage;
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
pub use array_basic::BasicArrayPackage;
|
||||
pub use eval::EvalPackage;
|
||||
pub use fn_basic::BasicFnPackage;
|
||||
pub use iter_basic::BasicIteratorPackage;
|
||||
pub use logic::LogicPackage;
|
||||
@ -89,6 +87,15 @@ impl PackagesCollection {
|
||||
.as_ref()
|
||||
.and_then(|x| x.iter().find_map(|p| p.get_iter(id)))
|
||||
}
|
||||
/// Get an iterator over all the packages in the [`PackagesCollection`].
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = &PackageLibrary> {
|
||||
self.0.iter().flat_map(|p| p.iter())
|
||||
}
|
||||
|
||||
/// Generate signatures for all the functions in the [`PackagesCollection`].
|
||||
pub fn gen_fn_signatures<'a>(&'a self) -> impl Iterator<Item = String> + 'a {
|
||||
self.iter().flat_map(|m| m.gen_fn_signatures())
|
||||
}
|
||||
}
|
||||
|
||||
/// Macro that makes it easy to define a _package_ (which is basically a shared module)
|
||||
@ -133,6 +140,7 @@ macro_rules! def_package {
|
||||
pub fn new() -> Self {
|
||||
let mut module = $root::Module::new_with_capacity(1024);
|
||||
<Self as $root::packages::Package>::init(&mut module);
|
||||
module.build_index();
|
||||
Self(module.into())
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,34 @@ use super::iter_basic::BasicIteratorPackage;
|
||||
use super::logic::LogicPackage;
|
||||
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, {
|
||||
#[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);
|
||||
LogicPackage::init(lib);
|
||||
BasicStringPackage::init(lib);
|
||||
|
@ -1,6 +1,6 @@
|
||||
#![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::stdlib::{
|
||||
fmt::{Debug, Display},
|
||||
@ -32,7 +32,7 @@ macro_rules! gen_functions {
|
||||
|
||||
macro_rules! reg_print_functions {
|
||||
($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);
|
||||
)* }
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ pub enum LexError {
|
||||
/// An identifier is in an invalid format.
|
||||
MalformedIdentifier(String),
|
||||
/// Bad symbol encountered when tokenizing the script text.
|
||||
ImproperSymbol(String),
|
||||
ImproperSymbol(String, String),
|
||||
}
|
||||
|
||||
impl Error for LexError {}
|
||||
@ -47,7 +47,10 @@ impl fmt::Display for LexError {
|
||||
Self::MalformedIdentifier(s) => write!(f, "{}: '{}'", self.desc(), s),
|
||||
Self::UnterminatedString => f.write_str(self.desc()),
|
||||
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::MalformedChar(_) => "Invalid character",
|
||||
Self::MalformedIdentifier(_) => "Variable name is not proper",
|
||||
Self::ImproperSymbol(_) => "Invalid symbol encountered",
|
||||
Self::ImproperSymbol(_, _) => "Invalid symbol encountered",
|
||||
}
|
||||
}
|
||||
/// Convert a `&LexError` into a [`ParseError`].
|
||||
|
@ -46,11 +46,11 @@ struct ParseState<'e> {
|
||||
strings: HashMap<String, ImmutableString>,
|
||||
/// Encapsulates a local stack with variable names to simulate an actual runtime scope.
|
||||
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).
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
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
|
||||
/// up until the nearest consumed Identifier token.
|
||||
/// 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,
|
||||
strings: HashMap::with_capacity(64),
|
||||
stack: Vec::with_capacity(16),
|
||||
always_search: false,
|
||||
entry_stack_len: 0,
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
modules: Default::default(),
|
||||
}
|
||||
@ -110,12 +110,22 @@ impl<'e> ParseState<'e> {
|
||||
/// Return `None` when the variable name is not found in the `stack`.
|
||||
#[inline]
|
||||
fn access_var(&mut self, name: &str, _pos: Position) -> Option<NonZeroUsize> {
|
||||
let mut barrier = false;
|
||||
|
||||
let index = self
|
||||
.stack
|
||||
.iter()
|
||||
.rev()
|
||||
.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));
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
@ -127,7 +137,7 @@ impl<'e> ParseState<'e> {
|
||||
self.allow_capture = true
|
||||
}
|
||||
|
||||
if self.always_search {
|
||||
if barrier {
|
||||
None
|
||||
} else {
|
||||
index
|
||||
@ -985,11 +995,8 @@ fn parse_primary(
|
||||
// Access to `this` as a variable is OK
|
||||
Token::Reserved(s) if s == KEYWORD_THIS && *next_token != Token::LeftParen => {
|
||||
if !settings.is_function_scope {
|
||||
return Err(PERR::BadInput(LexError::ImproperSymbol(format!(
|
||||
"'{}' can only be used in functions",
|
||||
s
|
||||
)))
|
||||
.into_err(settings.pos));
|
||||
let msg = format!("'{}' can only be used in functions", s);
|
||||
return Err(PERR::BadInput(LexError::ImproperSymbol(s, msg)).into_err(settings.pos));
|
||||
} else {
|
||||
let var_name_def = IdentX::new(state.get_interned_string(s), settings.pos);
|
||||
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)
|
||||
} else {
|
||||
PERR::BadInput(LexError::ImproperSymbol(
|
||||
"!".to_string(),
|
||||
"'!' cannot be used to call module functions".to_string(),
|
||||
))
|
||||
.into_err(token_pos)
|
||||
@ -1323,6 +1331,7 @@ fn make_assignment_stmt<'a>(
|
||||
}
|
||||
// ??? && ??? = rhs, ??? || ??? = rhs
|
||||
Expr::And(_, _) | Expr::Or(_, _) => Err(PERR::BadInput(LexError::ImproperSymbol(
|
||||
"=".to_string(),
|
||||
"Possibly a typo of '=='?".to_string(),
|
||||
))
|
||||
.into_err(pos)),
|
||||
@ -1428,10 +1437,13 @@ fn make_dot_expr(
|
||||
&& [crate::engine::KEYWORD_FN_PTR, crate::engine::KEYWORD_EVAL]
|
||||
.contains(&x.name.as_ref()) =>
|
||||
{
|
||||
return Err(PERR::BadInput(LexError::ImproperSymbol(format!(
|
||||
return Err(PERR::BadInput(LexError::ImproperSymbol(
|
||||
x.name.to_string(),
|
||||
format!(
|
||||
"'{}' should not be called in method style. Try {}(...);",
|
||||
x.name, x.name
|
||||
)))
|
||||
),
|
||||
))
|
||||
.into_err(pos));
|
||||
}
|
||||
// lhs.func!(...)
|
||||
@ -1789,11 +1801,13 @@ fn parse_custom_syntax(
|
||||
// Adjust the variables stack
|
||||
match syntax.scope_delta {
|
||||
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.len() + delta as usize,
|
||||
("".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
|
||||
@ -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> {
|
||||
match input.peek().unwrap() {
|
||||
(Token::Equals, pos) => Err(PERR::BadInput(LexError::ImproperSymbol(
|
||||
"=".to_string(),
|
||||
"Possibly a typo of '=='?".to_string(),
|
||||
))
|
||||
.into_err(*pos)),
|
||||
(Token::PlusAssign, pos)
|
||||
| (Token::MinusAssign, pos)
|
||||
| (Token::MultiplyAssign, pos)
|
||||
| (Token::DivideAssign, pos)
|
||||
| (Token::LeftShiftAssign, pos)
|
||||
| (Token::RightShiftAssign, pos)
|
||||
| (Token::ModuloAssign, pos)
|
||||
| (Token::PowerOfAssign, pos)
|
||||
| (Token::AndAssign, pos)
|
||||
| (Token::OrAssign, pos)
|
||||
| (Token::XOrAssign, pos) => Err(PERR::BadInput(LexError::ImproperSymbol(
|
||||
(token @ Token::PlusAssign, pos)
|
||||
| (token @ Token::MinusAssign, pos)
|
||||
| (token @ Token::MultiplyAssign, pos)
|
||||
| (token @ Token::DivideAssign, pos)
|
||||
| (token @ Token::LeftShiftAssign, pos)
|
||||
| (token @ Token::RightShiftAssign, pos)
|
||||
| (token @ Token::ModuloAssign, pos)
|
||||
| (token @ Token::PowerOfAssign, pos)
|
||||
| (token @ Token::AndAssign, pos)
|
||||
| (token @ Token::OrAssign, pos)
|
||||
| (token @ Token::XOrAssign, pos) => Err(PERR::BadInput(LexError::ImproperSymbol(
|
||||
token.syntax().to_string(),
|
||||
"Expecting a boolean expression, not an assignment".to_string(),
|
||||
))
|
||||
.into_err(*pos)),
|
||||
@ -2293,8 +2309,9 @@ fn parse_block(
|
||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||
|
||||
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"))]
|
||||
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"))]
|
||||
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))
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,9 @@ pub trait PluginFunction {
|
||||
/// Convert a plugin function into a boxed trait object.
|
||||
fn clone_boxed(&self) -> Box<dyn PluginFunction>;
|
||||
|
||||
/// Return a boxed slice of the names of the function's parameters.
|
||||
fn input_names(&self) -> Box<[&'static str]>;
|
||||
|
||||
/// Return a boxed slice of type ID's of the function's parameters.
|
||||
fn input_types(&self) -> Box<[TypeId]>;
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ pub fn from_dynamic<'de, T: Deserialize<'de>>(
|
||||
impl Error for Box<EvalAltResult> {
|
||||
fn custom<T: fmt::Display>(err: T) -> Self {
|
||||
EvalAltResult::ErrorParsing(
|
||||
ParseErrorType::BadInput(LexError::ImproperSymbol(err.to_string())),
|
||||
ParseErrorType::BadInput(LexError::ImproperSymbol("".to_string(), err.to_string())),
|
||||
Position::NONE,
|
||||
)
|
||||
.into()
|
||||
|
@ -137,11 +137,14 @@ impl Engine {
|
||||
.map(|v| v.is_keyword() || v.is_reserved())
|
||||
.unwrap_or(false) =>
|
||||
{
|
||||
return Err(LexError::ImproperSymbol(format!(
|
||||
return Err(LexError::ImproperSymbol(
|
||||
s.to_string(),
|
||||
format!(
|
||||
"Improper symbol for custom syntax at position #{}: '{}'",
|
||||
segments.len() + 1,
|
||||
s
|
||||
))
|
||||
),
|
||||
)
|
||||
.into_err(Position::NONE)
|
||||
.into());
|
||||
}
|
||||
@ -154,11 +157,14 @@ impl Engine {
|
||||
}
|
||||
// Anything else is an error
|
||||
_ => {
|
||||
return Err(LexError::ImproperSymbol(format!(
|
||||
return Err(LexError::ImproperSymbol(
|
||||
s.to_string(),
|
||||
format!(
|
||||
"Improper symbol for custom syntax at position #{}: '{}'",
|
||||
segments.len() + 1,
|
||||
s
|
||||
))
|
||||
),
|
||||
)
|
||||
.into_err(Position::NONE)
|
||||
.into());
|
||||
}
|
||||
|
58
src/token.rs
58
src/token.rs
@ -2,7 +2,7 @@
|
||||
|
||||
use crate::engine::{
|
||||
KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY,
|
||||
KEYWORD_IS_DEF_FN, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_THIS, KEYWORD_TYPE_OF,
|
||||
KEYWORD_PRINT, KEYWORD_THIS, KEYWORD_TYPE_OF,
|
||||
};
|
||||
use crate::stdlib::{
|
||||
borrow::Cow,
|
||||
@ -532,18 +532,13 @@ impl Token {
|
||||
"import" | "export" | "as" => Reserved(syntax.into()),
|
||||
|
||||
"===" | "!==" | "->" | "<-" | ":=" | "::<" | "(*" | "*)" | "#" | "public" | "new"
|
||||
| "use" | "module" | "package" | "var" | "static" | "shared" | "with" | "each"
|
||||
| "then" | "goto" | "unless" | "exit" | "match" | "case" | "default" | "void"
|
||||
| "null" | "nil" | "spawn" | "thread" | "go" | "sync" | "async" | "await" | "yield" => {
|
||||
Reserved(syntax.into())
|
||||
}
|
||||
| "use" | "module" | "package" | "var" | "static" | "begin" | "end" | "shared"
|
||||
| "with" | "each" | "then" | "goto" | "unless" | "exit" | "match" | "case"
|
||||
| "default" | "void" | "null" | "nil" | "spawn" | "thread" | "go" | "sync"
|
||||
| "async" | "await" | "yield" => Reserved(syntax.into()),
|
||||
|
||||
KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR
|
||||
| KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_IS_DEF_VAR
|
||||
| KEYWORD_IS_DEF_FN | KEYWORD_THIS => Reserved(syntax.into()),
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
crate::engine::KEYWORD_IS_SHARED => Reserved(syntax.into()),
|
||||
| KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_THIS => Reserved(syntax.into()),
|
||||
|
||||
_ => return None,
|
||||
})
|
||||
@ -1514,12 +1509,8 @@ fn get_identifier(
|
||||
#[inline(always)]
|
||||
pub fn is_keyword_function(name: &str) -> bool {
|
||||
match name {
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
crate::engine::KEYWORD_IS_SHARED => true,
|
||||
KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR
|
||||
| KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_IS_DEF_VAR | KEYWORD_IS_DEF_FN => {
|
||||
true
|
||||
}
|
||||
| KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -1529,8 +1520,7 @@ pub fn is_keyword_function(name: &str) -> bool {
|
||||
#[inline(always)]
|
||||
pub fn can_override_keyword(name: &str) -> bool {
|
||||
match name {
|
||||
KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR
|
||||
| KEYWORD_IS_DEF_VAR | KEYWORD_IS_DEF_FN => true,
|
||||
KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -1658,39 +1648,41 @@ impl<'a> Iterator for TokenIterator<'a, '_> {
|
||||
Some((Token::Reserved(s), pos)) => Some((match
|
||||
(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(),
|
||||
)),
|
||||
("!==", 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(),
|
||||
)),
|
||||
("->", false) => Token::LexError(LERR::ImproperSymbol(
|
||||
("->", false) => Token::LexError(LERR::ImproperSymbol(s,
|
||||
"'->' 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(),
|
||||
)),
|
||||
(":=", false) => Token::LexError(LERR::ImproperSymbol(
|
||||
"':=' is not a valid assignment operator. This is not Go! Should it be simply '='?".to_string(),
|
||||
(":=", false) => Token::LexError(LERR::ImproperSymbol(s,
|
||||
"':=' 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(),
|
||||
)),
|
||||
("(*", 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(),
|
||||
)),
|
||||
("#", false) => Token::LexError(LERR::ImproperSymbol(
|
||||
("#", false) => Token::LexError(LERR::ImproperSymbol(s,
|
||||
"'#' is not a valid symbol. Should it be '#{'?".to_string(),
|
||||
)),
|
||||
// Reserved keyword/operator that is custom.
|
||||
(_, true) => Token::Custom(s),
|
||||
// Reserved operator that is not custom.
|
||||
(token, false) if !is_valid_identifier(token.chars()) => Token::LexError(LERR::ImproperSymbol(
|
||||
format!("'{}' is a reserved symbol", token)
|
||||
)),
|
||||
(token, false) if !is_valid_identifier(token.chars()) => {
|
||||
let msg = format!("'{}' is a reserved symbol", token);
|
||||
Token::LexError(LERR::ImproperSymbol(s, msg))
|
||||
},
|
||||
// Reserved keyword that is not custom and disabled.
|
||||
(token, false) if self.engine.disabled_symbols.contains(token) => Token::LexError(LERR::ImproperSymbol(
|
||||
format!("reserved symbol '{}' is disabled", token)
|
||||
)),
|
||||
(token, false) if self.engine.disabled_symbols.contains(token) => {
|
||||
let msg = format!("reserved symbol '{}' is disabled", token);
|
||||
Token::LexError(LERR::ImproperSymbol(s, msg))
|
||||
},
|
||||
// Reserved keyword/operator that is not custom.
|
||||
(_, false) => Token::Reserved(s),
|
||||
}, pos)),
|
||||
|
@ -1,4 +1,4 @@
|
||||
use rhai::{Engine, EvalAltResult, ParseErrorType, Scope, INT};
|
||||
use rhai::{Engine, EvalAltResult, ParseErrorType, RegisterFn, Scope, INT};
|
||||
|
||||
#[test]
|
||||
fn test_constant() -> Result<(), Box<EvalAltResult>> {
|
||||
@ -62,3 +62,36 @@ fn test_var_is_def() -> Result<(), Box<EvalAltResult>> {
|
||||
|
||||
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(())
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use rhai::{Engine, EvalAltResult, Scope, INT};
|
||||
use rhai::{Engine, EvalAltResult, LexError, ParseErrorType, RegisterFn, Scope, INT};
|
||||
|
||||
#[test]
|
||||
fn test_eval() -> Result<(), Box<EvalAltResult>> {
|
||||
@ -103,5 +103,29 @@ fn test_eval_override() -> Result<(), Box<EvalAltResult>> {
|
||||
"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(())
|
||||
}
|
||||
|
@ -79,6 +79,7 @@ fn test_custom_syntax() -> Result<(), Box<EvalAltResult>> {
|
||||
.expect_err("should error")
|
||||
.0,
|
||||
ParseErrorType::BadInput(LexError::ImproperSymbol(
|
||||
"!".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(
|
||||
Box::new(ParseErrorType::BadInput(LexError::ImproperSymbol(
|
||||
s.to_string(),
|
||||
"".to_string(),
|
||||
))),
|
||||
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.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(())
|
||||
|
Loading…
Reference in New Issue
Block a user