Skip to content

Commit

Permalink
Introduce FuncRegistration API.
Browse files Browse the repository at this point in the history
  • Loading branch information
schungx committed Jan 17, 2024
1 parent d247869 commit a55eac2
Show file tree
Hide file tree
Showing 17 changed files with 519 additions and 654 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Other bug fixes
New features
------------

* A new `FuncRegistration` API is added to assist in registering native Rust functions into modules with various settings. Some of the original `Module::set_fn...` API is now deprecated.
* Functions defined in plugin modules can now be marked as `volatile` which prevents it from being optimized away even under `OptimizationLevel::Full`.
* Added `Engine::max_functions` and `Engine::set_max_functions` to limit the maximum number of functions allowed in a script. This s to guard against DOS attacks -- e.g. a simple closure `||` (two characters) is a function. When `max_function` is exceeded during script compilation, a new parse error, `TooManyFunctions`, is returned.
* `Engine::get_interned_string` is made public instead of gated under `internals`.
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ num-traits = { version = "0.2.0", default-features = false }
once_cell = { version = "1.7.0", default-features = false, features = ["race"] }
bitflags = { version = "2.0.0", default-features = false }
smartstring = { version = "1.0.0", default-features = false }
rhai_codegen = { version = "1.7.0", path = "codegen" }
rhai_codegen = { version = "1.17.0", path = "codegen" }

no-std-compat = { git = "https://gitlab.com/jD91mZM2/no-std-compat", version = "0.4.1", default-features = false, features = ["alloc"], optional = true }
libm = { version = "0.2.0", default-features = false, optional = true }
Expand Down
2 changes: 1 addition & 1 deletion codegen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rhai_codegen"
version = "1.7.0"
version = "1.17.0"
edition = "2018"
resolver = "2"
authors = ["jhwgh1968", "Stephen Chung"]
Expand Down
46 changes: 22 additions & 24 deletions codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,19 +344,18 @@ pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream
Ok((module_expr, export_name, rust_mod_path)) => {
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);

#[cfg(feature = "metadata")]
let param_names = quote! {
Some(#gen_mod_path::Token::PARAM_NAMES)
let mut tokens = quote! {
let fx = FuncRegistration::new(#export_name).with_namespace(FnNamespace::Internal)
};
#[cfg(not(feature = "metadata"))]
let param_names = quote! { None };

proc_macro::TokenStream::from(quote! {
#module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public,
#param_names,
&#gen_mod_path::Token::param_types(),
#gen_mod_path::Token().into())
})
#[cfg(feature = "metadata")]
tokens.extend(quote! {
.with_params_info(#gen_mod_path::Token::PARAM_NAMES)
});
tokens.extend(quote! {
;
#module_expr.set_fn_raw_with_options(fx, &#gen_mod_path::Token::param_types(), #gen_mod_path::Token().into());
});
tokens.into()
}
Err(e) => e.to_compile_error().into(),
}
Expand Down Expand Up @@ -393,19 +392,18 @@ pub fn set_exported_global_fn(args: proc_macro::TokenStream) -> proc_macro::Toke
Ok((module_expr, export_name, rust_mod_path)) => {
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);

#[cfg(feature = "metadata")]
let param_names = quote! {
Some(#gen_mod_path::Token::PARAM_NAMES)
let mut tokens = quote! {
let fx = FuncRegistration::new(#export_name).with_namespace(FnNamespace::Global)
};
#[cfg(not(feature = "metadata"))]
let param_names = quote! { None };

proc_macro::TokenStream::from(quote! {
#module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public,
#param_names,
&#gen_mod_path::Token::param_types(),
#gen_mod_path::Token().into())
})
#[cfg(feature = "metadata")]
tokens.extend(quote! {
.with_params_info(#gen_mod_path::Token::PARAM_NAMES)
});
tokens.extend(quote! {
;
#module_expr.set_fn_raw_with_options(fx, &#gen_mod_path::Token::param_types(), #gen_mod_path::Token().into());
});
tokens.into()
}
Err(e) => e.to_compile_error().into(),
}
Expand Down
92 changes: 24 additions & 68 deletions codegen/src/rhai_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use std::collections::BTreeMap;

use crate::attrs::ExportScope;
use crate::function::{
flatten_type_groups, print_type, ExportedFn, FnNamespaceAccess, FnSpecialAccess, FN_GET,
FN_IDX_GET, FN_IDX_SET, FN_SET,
print_type, ExportedFn, FnNamespaceAccess, FnSpecialAccess, FN_GET, FN_IDX_GET, FN_IDX_SET,
FN_SET,
};
use crate::module::Module;

Expand Down Expand Up @@ -39,8 +39,6 @@ pub fn generate_body(
let mut set_const_statements = Vec::new();
let mut add_mod_blocks = Vec::new();
let mut set_flattened_mod_blocks = Vec::new();
let str_type_path = syn::parse2::<syn::Path>(quote! { str }).unwrap();
let string_type_path = syn::parse2::<syn::Path>(quote! { String }).unwrap();

for ExportedConst {
name: const_name,
Expand Down Expand Up @@ -146,49 +144,6 @@ pub fn generate_body(
);
let reg_names = function.exported_names();

let fn_input_types: Vec<_> = function
.arg_list()
.map(|fn_arg| match fn_arg {
syn::FnArg::Receiver(..) => unreachable!("receiver fn outside impl!?"),
syn::FnArg::Typed(syn::PatType { ref ty, .. }) => {
let arg_type = match flatten_type_groups(ty.as_ref()) {
syn::Type::Reference(syn::TypeReference {
mutability: None,
ref elem,
..
}) => match flatten_type_groups(elem.as_ref()) {
syn::Type::Path(ref p) if p.path == str_type_path => {
syn::parse2::<syn::Type>(quote! {
ImmutableString })
.unwrap()
}
_ => unreachable!("non-string shared reference!?"),
},
syn::Type::Path(ref p) if p.path == string_type_path => {
syn::parse2::<syn::Type>(quote! {
ImmutableString })
.unwrap()
}
syn::Type::Reference(syn::TypeReference {
mutability: Some(_),
ref elem,
..
}) => match flatten_type_groups(elem.as_ref()) {
syn::Type::Path(ref p) => syn::parse2::<syn::Type>(quote! {
#p })
.unwrap(),
_ => unreachable!("invalid mutable reference!?"),
},
t => t.clone(),
};

syn::parse2::<syn::Expr>(quote! {
TypeId::of::<#arg_type>()})
.unwrap()
}
})
.collect();

let cfg_attrs: Vec<_> = function
.cfg_attrs()
.iter()
Expand Down Expand Up @@ -226,33 +181,34 @@ pub fn generate_body(
fn_literal.span(),
);

let mut tokens = quote! {
#(#cfg_attrs)*
FuncRegistration::new(#fn_literal).with_namespace(FnNamespace::#ns_str)
};
#[cfg(feature = "metadata")]
let (param_names, comments) = (
quote! { Some(#fn_token_name::PARAM_NAMES) },
function
{
tokens.extend(quote! {
.with_params_info(#fn_token_name::PARAM_NAMES)
});

let comments = function
.comments()
.iter()
.map(|s| syn::LitStr::new(s, Span::call_site()))
.collect::<Vec<_>>(),
);
#[cfg(not(feature = "metadata"))]
let (param_names, comments) = (quote! { None }, Vec::<syn::LitStr>::new());
.collect::<Vec<_>>();

set_fn_statements.push(if comments.is_empty() {
syn::parse2::<syn::Stmt>(quote! {
#(#cfg_attrs)*
m.set_fn(#fn_literal, FnNamespace::#ns_str, FnAccess::Public,
#param_names, &[#(#fn_input_types),*], #fn_token_name().into());
})
.unwrap()
} else {
syn::parse2::<syn::Stmt>(quote! {
#(#cfg_attrs)*
m.set_fn_with_comments(#fn_literal, FnNamespace::#ns_str, FnAccess::Public,
#param_names, &[#(#fn_input_types),*], &[#(#comments),*], #fn_token_name().into());
})
.unwrap()
if !comments.is_empty() {
tokens.extend(quote! {
.with_comments(&[#(#comments),*])
});
}
}

tokens.extend(quote! {
.set_into_module_raw(m, &#fn_token_name::param_types(), #fn_token_name().into());
});

set_fn_statements.push(syn::parse2::<syn::Stmt>(tokens).unwrap());
}

gen_fn_tokens.push(quote! {
Expand Down
Loading

0 comments on commit a55eac2

Please sign in to comment.