Merge pull request #52 from jhwgh1968/rhai_fn_multi_names
Support multiple names in rhai_fn
This commit is contained in:
commit
38ccb9e8f6
@ -19,7 +19,7 @@ use crate::attrs::{ExportInfo, ExportScope, ExportedParams};
|
|||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub(crate) struct ExportedFnParams {
|
pub(crate) struct ExportedFnParams {
|
||||||
pub name: Option<String>,
|
pub name: Option<Vec<String>>,
|
||||||
pub return_raw: bool,
|
pub return_raw: bool,
|
||||||
pub skip: bool,
|
pub skip: bool,
|
||||||
pub span: Option<proc_macro2::Span>,
|
pub span: Option<proc_macro2::Span>,
|
||||||
@ -55,11 +55,12 @@ impl ExportedParams for ExportedFnParams {
|
|||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_info(
|
fn from_info(info: crate::attrs::ExportInfo) -> syn::Result<Self> {
|
||||||
info: crate::attrs::ExportInfo,
|
let ExportInfo {
|
||||||
) -> syn::Result<Self> {
|
item_span: span,
|
||||||
let ExportInfo { item_span: span, items: attrs } = info;
|
items: attrs,
|
||||||
let mut name = None;
|
} = info;
|
||||||
|
let mut name = Vec::new();
|
||||||
let mut return_raw = false;
|
let mut return_raw = false;
|
||||||
let mut skip = false;
|
let mut skip = false;
|
||||||
for attr in attrs {
|
for attr in attrs {
|
||||||
@ -73,15 +74,15 @@ impl ExportedParams for ExportedFnParams {
|
|||||||
"Rhai function names may not contain dot",
|
"Rhai function names may not contain dot",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
name = Some(s.value())
|
name.push(s.value())
|
||||||
}
|
}
|
||||||
("get", Some(s)) => name = Some(make_getter(&s.value())),
|
("get", Some(s)) => name.push(make_getter(&s.value())),
|
||||||
("set", Some(s)) => name = Some(make_setter(&s.value())),
|
("set", Some(s)) => name.push(make_setter(&s.value())),
|
||||||
("get", None) | ("set", None) | ("name", None) => {
|
("get", None) | ("set", None) | ("name", None) => {
|
||||||
return Err(syn::Error::new(key.span(), "requires value"))
|
return Err(syn::Error::new(key.span(), "requires value"))
|
||||||
}
|
}
|
||||||
("index_get", None) => name = Some(FN_IDX_GET.to_string()),
|
("index_get", None) => name.push(FN_IDX_GET.to_string()),
|
||||||
("index_set", None) => name = Some(FN_IDX_SET.to_string()),
|
("index_set", None) => name.push(FN_IDX_SET.to_string()),
|
||||||
("return_raw", None) => return_raw = true,
|
("return_raw", None) => return_raw = true,
|
||||||
("index_get", Some(s)) | ("index_set", Some(s)) | ("return_raw", Some(s)) => {
|
("index_get", Some(s)) | ("index_set", Some(s)) | ("return_raw", Some(s)) => {
|
||||||
return Err(syn::Error::new(s.span(), "extraneous value"))
|
return Err(syn::Error::new(s.span(), "extraneous value"))
|
||||||
@ -98,7 +99,7 @@ impl ExportedParams for ExportedFnParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(ExportedFnParams {
|
Ok(ExportedFnParams {
|
||||||
name,
|
name: if name.is_empty() { None } else { Some(name) },
|
||||||
return_raw,
|
return_raw,
|
||||||
skip,
|
skip,
|
||||||
span: Some(span),
|
span: Some(span),
|
||||||
@ -260,7 +261,7 @@ impl ExportedFn {
|
|||||||
|
|
||||||
pub(crate) fn exported_name<'n>(&'n self) -> Cow<'n, str> {
|
pub(crate) fn exported_name<'n>(&'n self) -> Cow<'n, str> {
|
||||||
if let Some(ref name) = self.params.name {
|
if let Some(ref name) = self.params.name {
|
||||||
Cow::Borrowed(name.as_str())
|
Cow::Borrowed(name.last().unwrap().as_str())
|
||||||
} else {
|
} else {
|
||||||
Cow::Owned(self.signature.ident.to_string())
|
Cow::Owned(self.signature.ident.to_string())
|
||||||
}
|
}
|
||||||
@ -346,7 +347,9 @@ impl ExportedFn {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let return_span = self.return_type().map(|r| r.span())
|
let return_span = self
|
||||||
|
.return_type()
|
||||||
|
.map(|r| r.span())
|
||||||
.unwrap_or_else(|| proc_macro2::Span::call_site());
|
.unwrap_or_else(|| proc_macro2::Span::call_site());
|
||||||
if !self.params.return_raw {
|
if !self.params.return_raw {
|
||||||
quote_spanned! { return_span=>
|
quote_spanned! { return_span=>
|
||||||
@ -393,11 +396,10 @@ impl ExportedFn {
|
|||||||
|
|
||||||
pub fn generate_impl(&self, on_type_name: &str) -> proc_macro2::TokenStream {
|
pub fn generate_impl(&self, on_type_name: &str) -> proc_macro2::TokenStream {
|
||||||
let sig_name = self.name().clone();
|
let sig_name = self.name().clone();
|
||||||
let name = self
|
let name = self.params.name.as_ref().map_or_else(
|
||||||
.params
|
|| self.name().to_string(),
|
||||||
.name
|
|names| names.last().unwrap().clone(),
|
||||||
.clone()
|
);
|
||||||
.unwrap_or_else(|| self.name().to_string());
|
|
||||||
|
|
||||||
let arg_count = self.arg_count();
|
let arg_count = self.arg_count();
|
||||||
let is_method_call = self.mutable_receiver();
|
let is_method_call = self.mutable_receiver();
|
||||||
@ -518,7 +520,9 @@ impl ExportedFn {
|
|||||||
// Handle "raw returns", aka cases where the result is a dynamic or an error.
|
// Handle "raw returns", aka cases where the result is a dynamic or an error.
|
||||||
//
|
//
|
||||||
// This allows skipping the Dynamic::from wrap.
|
// This allows skipping the Dynamic::from wrap.
|
||||||
let return_span = self.return_type().map(|r| r.span())
|
let return_span = self
|
||||||
|
.return_type()
|
||||||
|
.map(|r| r.span())
|
||||||
.unwrap_or_else(|| proc_macro2::Span::call_site());
|
.unwrap_or_else(|| proc_macro2::Span::call_site());
|
||||||
let return_expr = if !self.params.return_raw {
|
let return_expr = if !self.params.return_raw {
|
||||||
quote_spanned! { return_span=>
|
quote_spanned! { return_span=>
|
||||||
|
@ -67,12 +67,12 @@ pub(crate) fn generate_body(
|
|||||||
&format!("{}_token", function.name().to_string()),
|
&format!("{}_token", function.name().to_string()),
|
||||||
function.name().span(),
|
function.name().span(),
|
||||||
);
|
);
|
||||||
let reg_name = function
|
let reg_names = function
|
||||||
.params()
|
.params()
|
||||||
.name
|
.name
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| function.name().to_string());
|
.unwrap_or_else(|| vec![function.name().to_string()]);
|
||||||
let fn_literal = syn::LitStr::new(®_name, proc_macro2::Span::call_site());
|
|
||||||
let fn_input_types: Vec<syn::Expr> = function
|
let fn_input_types: Vec<syn::Expr> = function
|
||||||
.arg_list()
|
.arg_list()
|
||||||
.map(|fnarg| match fnarg {
|
.map(|fnarg| match fnarg {
|
||||||
@ -110,6 +110,9 @@ pub(crate) fn generate_body(
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
for reg_name in reg_names {
|
||||||
|
let fn_literal = syn::LitStr::new(®_name, proc_macro2::Span::call_site());
|
||||||
|
|
||||||
set_fn_stmts.push(
|
set_fn_stmts.push(
|
||||||
syn::parse2::<syn::Stmt>(quote! {
|
syn::parse2::<syn::Stmt>(quote! {
|
||||||
m.set_fn(#fn_literal, FnAccess::Public, &[#(#fn_input_types),*],
|
m.set_fn(#fn_literal, FnAccess::Public, &[#(#fn_input_types),*],
|
||||||
@ -117,6 +120,7 @@ pub(crate) fn generate_body(
|
|||||||
})
|
})
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
gen_fn_tokens.push(quote! {
|
gen_fn_tokens.push(quote! {
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
@ -155,11 +159,14 @@ pub(crate) fn check_rename_collisions(fns: &Vec<ExportedFn>) -> Result<(), syn::
|
|||||||
let mut renames = HashMap::<String, proc_macro2::Span>::new();
|
let mut renames = HashMap::<String, proc_macro2::Span>::new();
|
||||||
let mut names = HashMap::<String, proc_macro2::Span>::new();
|
let mut names = HashMap::<String, proc_macro2::Span>::new();
|
||||||
for itemfn in fns.iter() {
|
for itemfn in fns.iter() {
|
||||||
if let Some(ref name) = itemfn.params().name {
|
if let Some(ref names) = itemfn.params().name {
|
||||||
|
for name in names {
|
||||||
let current_span = itemfn.params().span.as_ref().unwrap();
|
let current_span = itemfn.params().span.as_ref().unwrap();
|
||||||
let key = itemfn.arg_list().fold(name.clone(), |mut argstr, fnarg| {
|
let key = itemfn.arg_list().fold(name.clone(), |mut argstr, fnarg| {
|
||||||
let type_string: String = match fnarg {
|
let type_string: String = match fnarg {
|
||||||
syn::FnArg::Receiver(_) => unimplemented!("receiver rhai_fns not implemented"),
|
syn::FnArg::Receiver(_) => {
|
||||||
|
unimplemented!("receiver rhai_fns not implemented")
|
||||||
|
}
|
||||||
syn::FnArg::Typed(syn::PatType { ref ty, .. }) => {
|
syn::FnArg::Typed(syn::PatType { ref ty, .. }) => {
|
||||||
ty.as_ref().to_token_stream().to_string()
|
ty.as_ref().to_token_stream().to_string()
|
||||||
}
|
}
|
||||||
@ -179,6 +186,7 @@ pub(crate) fn check_rename_collisions(fns: &Vec<ExportedFn>) -> Result<(), syn::
|
|||||||
));
|
));
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let ident = itemfn.name();
|
let ident = itemfn.name();
|
||||||
if let Some(other_span) = names.insert(ident.to_string(), ident.span()) {
|
if let Some(other_span) = names.insert(ident.to_string(), ident.span()) {
|
||||||
|
@ -222,6 +222,73 @@ fn duplicate_fn_rename_test() -> Result<(), Box<EvalAltResult>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod multiple_fn_rename {
|
||||||
|
use rhai::plugin::*;
|
||||||
|
#[export_module]
|
||||||
|
pub mod my_adds {
|
||||||
|
use rhai::{FLOAT, INT};
|
||||||
|
|
||||||
|
pub fn get_mystic_number() -> FLOAT {
|
||||||
|
42.0
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "add", name = "+", name = "add_together")]
|
||||||
|
pub fn add_float(f1: FLOAT, f2: FLOAT) -> FLOAT {
|
||||||
|
f1 + f2 * 2.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rhai_fn(name = "add", name = "+", name = "add_together")]
|
||||||
|
pub fn add_int(i1: INT, i2: INT) -> INT {
|
||||||
|
i1 + i2 * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rhai_fn(name = "prop", get = "prop")]
|
||||||
|
pub fn get_prop(x: FLOAT) -> FLOAT {
|
||||||
|
x * 2.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rhai_fn(name = "idx", index_get)]
|
||||||
|
pub fn index(x: FLOAT, i: INT) -> FLOAT {
|
||||||
|
x + (i as FLOAT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn multiple_fn_rename_test() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
let m = rhai::exported_module!(crate::multiple_fn_rename::my_adds);
|
||||||
|
engine.load_package(m);
|
||||||
|
|
||||||
|
let output_array = engine.eval::<Array>(
|
||||||
|
r#"
|
||||||
|
let fx = get_mystic_number();
|
||||||
|
let fy1 = add(fx, 1.0);
|
||||||
|
let fy2 = add_together(fx, 1.0);
|
||||||
|
let fy3 = fx + 1.0;
|
||||||
|
let p1 = fx.prop;
|
||||||
|
let p2 = prop(fx);
|
||||||
|
let idx1 = fx[1];
|
||||||
|
let idx2 = idx(fx, 1);
|
||||||
|
let ix = 42;
|
||||||
|
let iy1 = add(ix, 1);
|
||||||
|
let iy2 = add_together(ix, 1);
|
||||||
|
let iy3 = ix + 1;
|
||||||
|
[fy1, fy2, fy3, iy1, iy2, iy3, p1, p2, idx1, idx2]
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
assert_eq!(&output_array[0].as_float().unwrap(), &44.0);
|
||||||
|
assert_eq!(&output_array[1].as_float().unwrap(), &44.0);
|
||||||
|
assert_eq!(&output_array[2].as_float().unwrap(), &44.0);
|
||||||
|
assert_eq!(&output_array[3].as_int().unwrap(), &44);
|
||||||
|
assert_eq!(&output_array[4].as_int().unwrap(), &44);
|
||||||
|
assert_eq!(&output_array[5].as_int().unwrap(), &44);
|
||||||
|
assert_eq!(&output_array[6].as_float().unwrap(), &84.0);
|
||||||
|
assert_eq!(&output_array[7].as_float().unwrap(), &84.0);
|
||||||
|
assert_eq!(&output_array[8].as_float().unwrap(), &43.0);
|
||||||
|
assert_eq!(&output_array[9].as_float().unwrap(), &43.0);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
mod export_by_prefix {
|
mod export_by_prefix {
|
||||||
use rhai::plugin::*;
|
use rhai::plugin::*;
|
||||||
#[export_module(export_prefix = "foo_")]
|
#[export_module(export_prefix = "foo_")]
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
use rhai::plugin::*;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Point {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[export_module]
|
||||||
|
pub mod test_module {
|
||||||
|
pub use super::Point;
|
||||||
|
#[rhai_fn(name = "foo", get = "bar")]
|
||||||
|
pub fn test_fn(input: Point) -> bool {
|
||||||
|
input.x > input.y
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rhai_fn(get = "bar")]
|
||||||
|
pub fn foo(input: Point) -> bool {
|
||||||
|
input.x < input.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let n = Point { x: 0.0, y: 10.0 };
|
||||||
|
if test_module::test_fn(n) {
|
||||||
|
println!("yes");
|
||||||
|
} else {
|
||||||
|
println!("no");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
error: duplicate Rhai signature for 'get$bar'
|
||||||
|
--> $DIR/rhai_fn_rename_collision_oneattr_multiple.rs:17:15
|
||||||
|
|
|
||||||
|
17 | #[rhai_fn(get = "bar")]
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: duplicated function renamed 'get$bar'
|
||||||
|
--> $DIR/rhai_fn_rename_collision_oneattr_multiple.rs:12:15
|
||||||
|
|
|
||||||
|
12 | #[rhai_fn(name = "foo", get = "bar")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
|
||||||
|
--> $DIR/rhai_fn_rename_collision_oneattr_multiple.rs:25:8
|
||||||
|
|
|
||||||
|
25 | if test_module::test_fn(n) {
|
||||||
|
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
|
25
codegen/ui_tests/rhai_fn_rename_collision_with_itself.rs
Normal file
25
codegen/ui_tests/rhai_fn_rename_collision_with_itself.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
use rhai::plugin::*;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Point {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[export_module]
|
||||||
|
pub mod test_module {
|
||||||
|
pub use super::Point;
|
||||||
|
#[rhai_fn(name = "foo", name = "bar", name = "foo")]
|
||||||
|
pub fn test_fn(input: Point) -> bool {
|
||||||
|
input.x > input.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let n = Point { x: 0.0, y: 10.0 };
|
||||||
|
if test_module::test_fn(n) {
|
||||||
|
println!("yes");
|
||||||
|
} else {
|
||||||
|
println!("no");
|
||||||
|
}
|
||||||
|
}
|
17
codegen/ui_tests/rhai_fn_rename_collision_with_itself.stderr
Normal file
17
codegen/ui_tests/rhai_fn_rename_collision_with_itself.stderr
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
error: duplicate Rhai signature for 'foo'
|
||||||
|
--> $DIR/rhai_fn_rename_collision_with_itself.rs:12:15
|
||||||
|
|
|
||||||
|
12 | #[rhai_fn(name = "foo", name = "bar", name = "foo")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: duplicated function renamed 'foo'
|
||||||
|
--> $DIR/rhai_fn_rename_collision_with_itself.rs:12:15
|
||||||
|
|
|
||||||
|
12 | #[rhai_fn(name = "foo", name = "bar", name = "foo")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
|
||||||
|
--> $DIR/rhai_fn_rename_collision_with_itself.rs:20:8
|
||||||
|
|
|
||||||
|
20 | if test_module::test_fn(n) {
|
||||||
|
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
|
@ -21,7 +21,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rhai_fn(name = "test")]
|
#[rhai_fn(name = "test", name = "hi")]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn len(array: &mut Array, mul: INT) -> INT {
|
pub fn len(array: &mut Array, mul: INT) -> INT {
|
||||||
(array.len() as INT) * mul
|
(array.len() as INT) * mul
|
||||||
@ -74,6 +74,8 @@ fn test_plugins_package() -> Result<(), Box<EvalAltResult>> {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
assert_eq!(engine.eval::<INT>("let a = [1, 2, 3]; a.foo")?, 1);
|
assert_eq!(engine.eval::<INT>("let a = [1, 2, 3]; a.foo")?, 1);
|
||||||
|
|
||||||
|
assert_eq!(engine.eval::<INT>("let a = [1, 2, 3]; test(a, 2)")?, 6);
|
||||||
|
assert_eq!(engine.eval::<INT>("let a = [1, 2, 3]; hi(a, 2)")?, 6);
|
||||||
assert_eq!(engine.eval::<INT>("let a = [1, 2, 3]; test(a, 2)")?, 6);
|
assert_eq!(engine.eval::<INT>("let a = [1, 2, 3]; test(a, 2)")?, 6);
|
||||||
assert_eq!(engine.eval::<INT>("2 + 2")?, 5);
|
assert_eq!(engine.eval::<INT>("2 + 2")?, 5);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
Loading…
Reference in New Issue
Block a user