diff --git a/codegen/src/function.rs b/codegen/src/function.rs index b96180d2..3b0edee8 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -17,24 +17,43 @@ use syn::{parse::Parse, parse::ParseStream, parse::Parser, spanned::Spanned}; use crate::attrs::{ExportInfo, ExportScope, ExportedParams}; +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Index { + Get, + Set, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Property { + Get(syn::Ident), + Set(syn::Ident), +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum FnSpecialAccess { + None, + Index(Index), + Property(Property), +} + +impl Default for FnSpecialAccess { + fn default() -> FnSpecialAccess { + FnSpecialAccess::None + } +} + #[derive(Debug, Default)] pub(crate) struct ExportedFnParams { pub name: Option>, pub return_raw: bool, pub skip: bool, pub span: Option, + pub special: FnSpecialAccess, } pub const FN_IDX_GET: &str = "index$get$"; pub const FN_IDX_SET: &str = "index$set$"; -pub fn make_getter(id: &str) -> String { - format!("get${}", id) -} -pub fn make_setter(id: &str) -> String { - format!("set${}", id) -} - impl Parse for ExportedFnParams { fn parse(args: ParseStream) -> syn::Result { if args.is_empty() { @@ -63,6 +82,7 @@ impl ExportedParams for ExportedFnParams { let mut name = Vec::new(); let mut return_raw = false; let mut skip = false; + let mut special = FnSpecialAccess::None; for attr in attrs { let crate::attrs::AttrItem { key, value, span: item_span } = attr; match (key.to_string().as_ref(), value) { @@ -98,10 +118,37 @@ impl ExportedParams for ExportedFnParams { ("name", Some(s)) => { name.push(s.value()) }, - ("get", Some(s)) => name.push(make_getter(&s.value())), - ("set", Some(s)) => name.push(make_setter(&s.value())), - ("index_get", None) => name.push(FN_IDX_GET.to_string()), - ("index_set", None) => name.push(FN_IDX_SET.to_string()), + ("set", Some(s)) => special = match special { + FnSpecialAccess::None => + FnSpecialAccess::Property(Property::Set(syn::Ident::new(&s.value(), + s.span()))), + _ => { + return Err(syn::Error::new(item_span.span(), "conflicting setter")) + } + }, + ("get", Some(s)) => special = match special { + FnSpecialAccess::None => + FnSpecialAccess::Property(Property::Get(syn::Ident::new(&s.value(), + s.span()))), + _ => { + return Err(syn::Error::new(item_span.span(), "conflicting getter")) + } + }, + ("index_get", None) => special = match special { + FnSpecialAccess::None => + FnSpecialAccess::Index(Index::Get), + _ => { + return Err(syn::Error::new(item_span.span(), "conflicting index_get")) + } + }, + + ("index_set", None) => special = match special { + FnSpecialAccess::None => + FnSpecialAccess::Index(Index::Set), + _ => { + return Err(syn::Error::new(item_span.span(), "conflicting index_set")) + } + }, ("return_raw", None) => return_raw = true, ("index_get", Some(s)) | ("index_set", Some(s)) | ("return_raw", Some(s)) => { return Err(syn::Error::new(s.span(), "extraneous value")) @@ -121,6 +168,7 @@ impl ExportedParams for ExportedFnParams { name: if name.is_empty() { None } else { Some(name) }, return_raw, skip, + special, span: Some(span), ..Default::default() }) @@ -278,6 +326,32 @@ impl ExportedFn { &self.signature.ident } + pub(crate) fn exported_names(&self) -> Vec { + let mut literals = self.params.name.as_ref() + .map(|v| v.iter() + .map(|s| syn::LitStr::new(s, proc_macro2::Span::call_site())).collect()) + .unwrap_or_else(|| Vec::new()); + + match self.params.special { + FnSpecialAccess::None => {}, + FnSpecialAccess::Property(Property::Get(ref g)) => + literals.push(syn::LitStr::new(&format!("get${}", g.to_string()), g.span())), + FnSpecialAccess::Property(Property::Set(ref s)) => + literals.push(syn::LitStr::new(&format!("set${}", s.to_string()), s.span())), + FnSpecialAccess::Index(Index::Get) => + literals.push(syn::LitStr::new(FN_IDX_GET, proc_macro2::Span::call_site())), + FnSpecialAccess::Index(Index::Set) => + literals.push(syn::LitStr::new(FN_IDX_SET, proc_macro2::Span::call_site())), + } + + if literals.is_empty() { + literals.push(syn::LitStr::new(&self.signature.ident.to_string(), + self.signature.ident.span())); + } + + literals + } + pub(crate) fn exported_name<'n>(&'n self) -> Cow<'n, str> { if let Some(ref name) = self.params.name { Cow::Borrowed(name.last().unwrap().as_str()) diff --git a/codegen/src/rhai_module.rs b/codegen/src/rhai_module.rs index 57ec78a8..d318f351 100644 --- a/codegen/src/rhai_module.rs +++ b/codegen/src/rhai_module.rs @@ -67,11 +67,7 @@ pub(crate) fn generate_body( &format!("{}_token", function.name().to_string()), function.name().span(), ); - let reg_names = function - .params() - .name - .clone() - .unwrap_or_else(|| vec![function.name().to_string()]); + let reg_names = function.exported_names(); let fn_input_types: Vec = function .arg_list() @@ -110,9 +106,7 @@ pub(crate) fn generate_body( }) .collect(); - for reg_name in reg_names { - let fn_literal = syn::LitStr::new(®_name, proc_macro2::Span::call_site()); - + for fn_literal in reg_names { set_fn_stmts.push( syn::parse2::(quote! { m.set_fn(#fn_literal, FnAccess::Public, &[#(#fn_input_types),*], diff --git a/codegen/ui_tests/rhai_fn_rename_collision_oneattr_multiple.stderr b/codegen/ui_tests/rhai_fn_rename_collision_oneattr_multiple.stderr index 2f2f6623..77375279 100644 --- a/codegen/ui_tests/rhai_fn_rename_collision_oneattr_multiple.stderr +++ b/codegen/ui_tests/rhai_fn_rename_collision_oneattr_multiple.stderr @@ -1,15 +1,15 @@ -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' +error: duplicate Rhai signature for 'foo' --> $DIR/rhai_fn_rename_collision_oneattr_multiple.rs:12:15 | 12 | #[rhai_fn(name = "foo", get = "bar")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ +error: duplicated function 'foo' + --> $DIR/rhai_fn_rename_collision_oneattr_multiple.rs:18:12 + | +18 | pub fn foo(input: Point) -> bool { + | ^^^ + error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_rename_collision_oneattr_multiple.rs:25:8 | diff --git a/codegen/ui_tests/rhai_fn_rename_dollar_sign.stderr b/codegen/ui_tests/rhai_fn_rename_dollar_sign.stderr index 96f4c4de..3438bdfc 100644 --- a/codegen/ui_tests/rhai_fn_rename_dollar_sign.stderr +++ b/codegen/ui_tests/rhai_fn_rename_dollar_sign.stderr @@ -4,8 +4,8 @@ error: Rhai function names may not contain dollar sign 12 | #[rhai_fn(name = "big$caching")] | ^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_rename_dollar_sign.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_rename_to_index_getter.stderr b/codegen/ui_tests/rhai_fn_rename_to_index_getter.stderr index 287283f9..64c11d92 100644 --- a/codegen/ui_tests/rhai_fn_rename_to_index_getter.stderr +++ b/codegen/ui_tests/rhai_fn_rename_to_index_getter.stderr @@ -4,8 +4,8 @@ error: use attribute 'index_get' instead 12 | #[rhai_fn(name = "index$get$")] | ^^^^^^^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_rename_to_index_getter.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_rename_to_index_setter.stderr b/codegen/ui_tests/rhai_fn_rename_to_index_setter.stderr index 712f2c59..0d9c9f3d 100644 --- a/codegen/ui_tests/rhai_fn_rename_to_index_setter.stderr +++ b/codegen/ui_tests/rhai_fn_rename_to_index_setter.stderr @@ -4,8 +4,8 @@ error: use attribute 'index_set' instead 12 | #[rhai_fn(name = "index$set$")] | ^^^^^^^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_rename_to_index_setter.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_rename_to_prop_getter.stderr b/codegen/ui_tests/rhai_fn_rename_to_prop_getter.stderr index d9d9b3e8..cee9c66b 100644 --- a/codegen/ui_tests/rhai_fn_rename_to_prop_getter.stderr +++ b/codegen/ui_tests/rhai_fn_rename_to_prop_getter.stderr @@ -4,8 +4,8 @@ error: use attribute 'getter = "foo"' instead 12 | #[rhai_fn(name = "get$foo")] | ^^^^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_rename_to_prop_getter.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module` diff --git a/codegen/ui_tests/rhai_fn_rename_to_prop_setter.stderr b/codegen/ui_tests/rhai_fn_rename_to_prop_setter.stderr index a1dfbebd..9544ce93 100644 --- a/codegen/ui_tests/rhai_fn_rename_to_prop_setter.stderr +++ b/codegen/ui_tests/rhai_fn_rename_to_prop_setter.stderr @@ -4,8 +4,8 @@ error: use attribute 'getter = "foo"' instead 12 | #[rhai_fn(name = "get$foo")] | ^^^^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type or module `test_module` +error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> $DIR/rhai_fn_rename_to_prop_setter.rs:23:8 | 23 | if test_module::test_fn(n) { - | ^^^^^^^^^^^ use of undeclared type or module `test_module` + | ^^^^^^^^^^^ use of undeclared crate or module `test_module`