Add rhai_fn nested attribute and skip fn parameter
This commit is contained in:
parent
db9d8b81cf
commit
bcf14025a7
@ -17,6 +17,15 @@ use syn::{parse::Parse, parse::ParseStream, parse::Parser, spanned::Spanned};
|
|||||||
pub(crate) struct ExportedFnParams {
|
pub(crate) struct ExportedFnParams {
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub return_raw: bool,
|
pub return_raw: bool,
|
||||||
|
pub skip: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExportedFnParams {
|
||||||
|
pub fn skip() -> ExportedFnParams {
|
||||||
|
let mut skip = ExportedFnParams::default();
|
||||||
|
skip.skip = true;
|
||||||
|
skip
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for ExportedFnParams {
|
impl Parse for ExportedFnParams {
|
||||||
@ -68,6 +77,7 @@ impl Parse for ExportedFnParams {
|
|||||||
|
|
||||||
let mut name = None;
|
let mut name = None;
|
||||||
let mut return_raw = false;
|
let mut return_raw = false;
|
||||||
|
let mut skip = false;
|
||||||
for (ident, value) in attrs.drain() {
|
for (ident, value) in attrs.drain() {
|
||||||
match (ident.to_string().as_ref(), value) {
|
match (ident.to_string().as_ref(), value) {
|
||||||
("name", Some(s)) => name = Some(s.value()),
|
("name", Some(s)) => name = Some(s.value()),
|
||||||
@ -76,6 +86,10 @@ impl Parse for ExportedFnParams {
|
|||||||
("return_raw", Some(s)) => {
|
("return_raw", Some(s)) => {
|
||||||
return Err(syn::Error::new(s.span(), "extraneous value"))
|
return Err(syn::Error::new(s.span(), "extraneous value"))
|
||||||
}
|
}
|
||||||
|
("skip", None) => skip = true,
|
||||||
|
("skip", Some(s)) => {
|
||||||
|
return Err(syn::Error::new(s.span(), "extraneous value"))
|
||||||
|
}
|
||||||
(attr, _) => {
|
(attr, _) => {
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
ident.span(),
|
ident.span(),
|
||||||
@ -85,7 +99,7 @@ impl Parse for ExportedFnParams {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ExportedFnParams { name, return_raw })
|
Ok(ExportedFnParams { name, return_raw, skip, ..Default::default() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +109,7 @@ pub(crate) struct ExportedFn {
|
|||||||
signature: syn::Signature,
|
signature: syn::Signature,
|
||||||
is_public: bool,
|
is_public: bool,
|
||||||
mut_receiver: bool,
|
mut_receiver: bool,
|
||||||
params: ExportedFnParams,
|
pub params: ExportedFnParams,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for ExportedFn {
|
impl Parse for ExportedFn {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use quote::{quote, ToTokens};
|
use quote::{quote, ToTokens};
|
||||||
use syn::{parse::Parse, parse::ParseStream};
|
use syn::{parse::Parse, parse::ParseStream};
|
||||||
|
|
||||||
use crate::function::ExportedFn;
|
use crate::function::{ExportedFn, ExportedFnParams};
|
||||||
use crate::rhai_module::ExportedConst;
|
use crate::rhai_module::ExportedConst;
|
||||||
|
|
||||||
#[cfg(no_std)]
|
#[cfg(no_std)]
|
||||||
@ -12,6 +12,22 @@ use std::vec as new_vec;
|
|||||||
#[cfg(no_std)]
|
#[cfg(no_std)]
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
||||||
|
fn inner_fn_attributes(f: &mut syn::ItemFn) -> syn::Result<ExportedFnParams> {
|
||||||
|
if let Some(rhai_fn_idx) = f.attrs.iter().position(|a| {
|
||||||
|
a.path
|
||||||
|
.get_ident()
|
||||||
|
.map(|i| i.to_string() == "rhai_fn")
|
||||||
|
.unwrap_or(false)
|
||||||
|
}) {
|
||||||
|
let rhai_fn_attr = f.attrs.remove(rhai_fn_idx);
|
||||||
|
rhai_fn_attr.parse_args()
|
||||||
|
} else if let syn::Visibility::Public(_) = f.vis {
|
||||||
|
Ok(ExportedFnParams::default())
|
||||||
|
} else {
|
||||||
|
Ok(ExportedFnParams::skip())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Module {
|
pub(crate) struct Module {
|
||||||
mod_all: Option<syn::ItemMod>,
|
mod_all: Option<syn::ItemMod>,
|
||||||
@ -21,25 +37,27 @@ pub(crate) struct Module {
|
|||||||
|
|
||||||
impl Parse for Module {
|
impl Parse for Module {
|
||||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
let mod_all: syn::ItemMod = input.parse()?;
|
let mut mod_all: syn::ItemMod = input.parse()?;
|
||||||
let fns: Vec<_>;
|
let fns: Vec<_>;
|
||||||
let consts: Vec<_>;
|
let consts: Vec<_>;
|
||||||
if let Some((_, ref content)) = mod_all.content {
|
if let Some((_, ref mut content)) = mod_all.content {
|
||||||
fns = content
|
fns = content
|
||||||
.iter()
|
.iter_mut()
|
||||||
.filter_map(|item| match item {
|
.filter_map(|item| match item {
|
||||||
syn::Item::Fn(f) => {
|
syn::Item::Fn(f) => Some(f),
|
||||||
if let syn::Visibility::Public(_) = f.vis {
|
|
||||||
Some(f)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.try_fold(Vec::new(), |mut vec, itemfn| {
|
.try_fold(Vec::new(), |mut vec, mut itemfn| {
|
||||||
|
let params = match inner_fn_attributes(&mut itemfn) {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
};
|
||||||
syn::parse2::<ExportedFn>(itemfn.to_token_stream())
|
syn::parse2::<ExportedFn>(itemfn.to_token_stream())
|
||||||
.map(|f| vec.push(f))
|
.map(|mut f| {
|
||||||
|
f.params = params;
|
||||||
|
f
|
||||||
|
})
|
||||||
|
.map(|f| if !f.params.skip { vec.push(f) })
|
||||||
.map(|_| vec)
|
.map(|_| vec)
|
||||||
})?;
|
})?;
|
||||||
consts = content
|
consts = content
|
||||||
@ -217,6 +235,22 @@ mod module_tests {
|
|||||||
assert!(item_mod.consts.is_empty());
|
assert!(item_mod.consts.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn one_skipped_fn_module() {
|
||||||
|
let input_tokens: TokenStream = quote! {
|
||||||
|
pub mod one_fn {
|
||||||
|
#[rhai_fn(skip)]
|
||||||
|
pub fn get_mystic_number() -> INT {
|
||||||
|
42
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let item_mod = syn::parse2::<Module>(input_tokens).unwrap();
|
||||||
|
assert!(item_mod.fns.is_empty());
|
||||||
|
assert!(item_mod.consts.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn one_private_constant_module() {
|
fn one_private_constant_module() {
|
||||||
let input_tokens: TokenStream = quote! {
|
let input_tokens: TokenStream = quote! {
|
||||||
@ -552,6 +586,36 @@ mod generate_tests {
|
|||||||
assert_streams_eq(item_mod.generate(), expected_tokens);
|
assert_streams_eq(item_mod.generate(), expected_tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn one_skipped_fn_module() {
|
||||||
|
let input_tokens: TokenStream = quote! {
|
||||||
|
pub mod one_fn {
|
||||||
|
#[rhai_fn(skip)]
|
||||||
|
pub fn get_mystic_number() -> INT {
|
||||||
|
42
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected_tokens = quote! {
|
||||||
|
pub mod one_fn {
|
||||||
|
pub fn get_mystic_number() -> INT {
|
||||||
|
42
|
||||||
|
}
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use super::*;
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
pub fn rhai_module_generate() -> Module {
|
||||||
|
let mut m = Module::new();
|
||||||
|
m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let item_mod = syn::parse2::<Module>(input_tokens).unwrap();
|
||||||
|
assert_streams_eq(item_mod.generate(), expected_tokens);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn one_private_constant_module() {
|
fn one_private_constant_module() {
|
||||||
let input_tokens: TokenStream = quote! {
|
let input_tokens: TokenStream = quote! {
|
||||||
|
36
codegen/tests/test_nested.rs
Normal file
36
codegen/tests/test_nested.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use rhai::module_resolvers::*;
|
||||||
|
use rhai::{Engine, EvalAltResult, RegisterFn, FLOAT, INT};
|
||||||
|
|
||||||
|
pub mod one_fn_module_nested_attr {
|
||||||
|
use rhai::plugin::*;
|
||||||
|
|
||||||
|
#[export_module]
|
||||||
|
pub mod advanced_math {
|
||||||
|
use rhai::plugin::*;
|
||||||
|
use rhai::FLOAT;
|
||||||
|
|
||||||
|
#[rhai_fn(return_raw)]
|
||||||
|
pub fn get_mystic_number() -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
|
Ok(Dynamic::from(42.0 as FLOAT))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn one_fn_module_nested_attr_test() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
let m = rhai::exported_module!(crate::one_fn_module_nested_attr::advanced_math);
|
||||||
|
let mut r = StaticModuleResolver::new();
|
||||||
|
r.insert("Math::Advanced".to_string(), m);
|
||||||
|
engine.set_module_resolver(Some(r));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<FLOAT>(
|
||||||
|
r#"import "Math::Advanced" as math;
|
||||||
|
let m = math::get_mystic_number();
|
||||||
|
m"#
|
||||||
|
)?,
|
||||||
|
42.0
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
27
codegen/ui_tests/rhai_fn_bad_attr.rs
Normal file
27
codegen/ui_tests/rhai_fn_bad_attr.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use rhai::plugin::*;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Point {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[export_module]
|
||||||
|
pub mod test_module {
|
||||||
|
#[rhai_fn(unknown = "thing")]
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
11
codegen/ui_tests/rhai_fn_bad_attr.stderr
Normal file
11
codegen/ui_tests/rhai_fn_bad_attr.stderr
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
error: unknown attribute 'unknown'
|
||||||
|
--> $DIR/rhai_fn_bad_attr.rs:11:11
|
||||||
|
|
|
||||||
|
11 | #[rhai_fn(unknown = "thing")]
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
|
||||||
|
--> $DIR/rhai_fn_bad_attr.rs:22:8
|
||||||
|
|
|
||||||
|
22 | if test_module::test_fn(n) {
|
||||||
|
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
|
27
codegen/ui_tests/rhai_fn_bad_value.rs
Normal file
27
codegen/ui_tests/rhai_fn_bad_value.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use rhai::plugin::*;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Point {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[export_module]
|
||||||
|
pub mod test_module {
|
||||||
|
#[rhai_fn(name = true)]
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
11
codegen/ui_tests/rhai_fn_bad_value.stderr
Normal file
11
codegen/ui_tests/rhai_fn_bad_value.stderr
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
error: expecting string literal
|
||||||
|
--> $DIR/rhai_fn_bad_value.rs:11:18
|
||||||
|
|
|
||||||
|
11 | #[rhai_fn(name = true)]
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
|
||||||
|
--> $DIR/rhai_fn_bad_value.rs:22:8
|
||||||
|
|
|
||||||
|
22 | if test_module::test_fn(n) {
|
||||||
|
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
|
27
codegen/ui_tests/rhai_fn_extra_value.rs
Normal file
27
codegen/ui_tests/rhai_fn_extra_value.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use rhai::plugin::*;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Point {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[export_module]
|
||||||
|
pub mod test_module {
|
||||||
|
#[rhai_fn(return_raw = "yes")]
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
11
codegen/ui_tests/rhai_fn_extra_value.stderr
Normal file
11
codegen/ui_tests/rhai_fn_extra_value.stderr
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
error: extraneous value
|
||||||
|
--> $DIR/rhai_fn_extra_value.rs:11:24
|
||||||
|
|
|
||||||
|
11 | #[rhai_fn(return_raw = "yes")]
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
|
||||||
|
--> $DIR/rhai_fn_extra_value.rs:22:8
|
||||||
|
|
|
||||||
|
22 | if test_module::test_fn(n) {
|
||||||
|
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
|
27
codegen/ui_tests/rhai_fn_junk_arg.rs
Normal file
27
codegen/ui_tests/rhai_fn_junk_arg.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use rhai::plugin::*;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Point {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[export_module]
|
||||||
|
pub mod test_module {
|
||||||
|
#[rhai_fn("wheeeee")]
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
11
codegen/ui_tests/rhai_fn_junk_arg.stderr
Normal file
11
codegen/ui_tests/rhai_fn_junk_arg.stderr
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
error: expecting identifier
|
||||||
|
--> $DIR/rhai_fn_junk_arg.rs:11:11
|
||||||
|
|
|
||||||
|
11 | #[rhai_fn("wheeeee")]
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
|
||||||
|
--> $DIR/rhai_fn_junk_arg.rs:22:8
|
||||||
|
|
|
||||||
|
22 | if test_module::test_fn(n) {
|
||||||
|
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
|
27
codegen/ui_tests/rhai_fn_missing_value.rs
Normal file
27
codegen/ui_tests/rhai_fn_missing_value.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use rhai::plugin::*;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Point {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[export_module]
|
||||||
|
pub mod test_module {
|
||||||
|
#[rhai_fn(name)]
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
11
codegen/ui_tests/rhai_fn_missing_value.stderr
Normal file
11
codegen/ui_tests/rhai_fn_missing_value.stderr
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
error: requires value
|
||||||
|
--> $DIR/rhai_fn_missing_value.rs:11:11
|
||||||
|
|
|
||||||
|
11 | #[rhai_fn(name)]
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
|
||||||
|
--> $DIR/rhai_fn_missing_value.rs:22:8
|
||||||
|
|
|
||||||
|
22 | if test_module::test_fn(n) {
|
||||||
|
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
|
27
codegen/ui_tests/rhai_fn_path_attr.rs
Normal file
27
codegen/ui_tests/rhai_fn_path_attr.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use rhai::plugin::*;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Point {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[export_module]
|
||||||
|
pub mod test_module {
|
||||||
|
#[rhai_fn(rhai::name = "thing")]
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
11
codegen/ui_tests/rhai_fn_path_attr.stderr
Normal file
11
codegen/ui_tests/rhai_fn_path_attr.stderr
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
error: expecting attribute name
|
||||||
|
--> $DIR/rhai_fn_path_attr.rs:11:11
|
||||||
|
|
|
||||||
|
11 | #[rhai_fn(rhai::name = "thing")]
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
|
||||||
|
--> $DIR/rhai_fn_path_attr.rs:22:8
|
||||||
|
|
|
||||||
|
22 | if test_module::test_fn(n) {
|
||||||
|
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
|
Loading…
Reference in New Issue
Block a user