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 name: Option<String>,
|
||||
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 {
|
||||
@ -68,6 +77,7 @@ impl Parse for ExportedFnParams {
|
||||
|
||||
let mut name = None;
|
||||
let mut return_raw = false;
|
||||
let mut skip = false;
|
||||
for (ident, value) in attrs.drain() {
|
||||
match (ident.to_string().as_ref(), value) {
|
||||
("name", Some(s)) => name = Some(s.value()),
|
||||
@ -76,6 +86,10 @@ impl Parse for ExportedFnParams {
|
||||
("return_raw", Some(s)) => {
|
||||
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, _) => {
|
||||
return Err(syn::Error::new(
|
||||
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,
|
||||
is_public: bool,
|
||||
mut_receiver: bool,
|
||||
params: ExportedFnParams,
|
||||
pub params: ExportedFnParams,
|
||||
}
|
||||
|
||||
impl Parse for ExportedFn {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::{parse::Parse, parse::ParseStream};
|
||||
|
||||
use crate::function::ExportedFn;
|
||||
use crate::function::{ExportedFn, ExportedFnParams};
|
||||
use crate::rhai_module::ExportedConst;
|
||||
|
||||
#[cfg(no_std)]
|
||||
@ -12,6 +12,22 @@ use std::vec as new_vec;
|
||||
#[cfg(no_std)]
|
||||
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)]
|
||||
pub(crate) struct Module {
|
||||
mod_all: Option<syn::ItemMod>,
|
||||
@ -21,25 +37,27 @@ pub(crate) struct Module {
|
||||
|
||||
impl Parse for Module {
|
||||
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 consts: Vec<_>;
|
||||
if let Some((_, ref content)) = mod_all.content {
|
||||
if let Some((_, ref mut content)) = mod_all.content {
|
||||
fns = content
|
||||
.iter()
|
||||
.iter_mut()
|
||||
.filter_map(|item| match item {
|
||||
syn::Item::Fn(f) => {
|
||||
if let syn::Visibility::Public(_) = f.vis {
|
||||
Some(f)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
syn::Item::Fn(f) => Some(f),
|
||||
_ => 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())
|
||||
.map(|f| vec.push(f))
|
||||
.map(|mut f| {
|
||||
f.params = params;
|
||||
f
|
||||
})
|
||||
.map(|f| if !f.params.skip { vec.push(f) })
|
||||
.map(|_| vec)
|
||||
})?;
|
||||
consts = content
|
||||
@ -217,6 +235,22 @@ mod module_tests {
|
||||
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]
|
||||
fn one_private_constant_module() {
|
||||
let input_tokens: TokenStream = quote! {
|
||||
@ -552,6 +586,36 @@ mod generate_tests {
|
||||
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]
|
||||
fn one_private_constant_module() {
|
||||
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