From 23b5bc4bd9c2a9333073938d529bd556bc0b2808 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 18 Sep 2020 12:31:41 +0800 Subject: [PATCH 01/10] Prevent errors when using alternative error printout style. --- codegen/src/test/function.rs | 4 +++- codegen/src/test/module.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/codegen/src/test/function.rs b/codegen/src/test/function.rs index a4a54959..31797438 100644 --- a/codegen/src/test/function.rs +++ b/codegen/src/test/function.rs @@ -245,7 +245,6 @@ mod generate_tests { false } }); - eprintln!("actual != expected, diverge at char {}", counter); /* let (actual_diff, expected_diff) = { let mut actual_diff = String::new(); @@ -256,6 +255,9 @@ mod generate_tests { } (actual_diff, expected_diff) }; + */ + eprintln!("actual != expected, diverge at char {}", counter); + /* eprintln!(" actual: {}", actual_diff); eprintln!("expected: {}", expected_diff); assert!(false); diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index b560e94b..4d71f296 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -226,7 +226,6 @@ mod generate_tests { false } }); - eprintln!("actual != expected, diverge at char {}", counter); /* let (actual_diff, expected_diff) = { let mut actual_diff = String::new(); @@ -237,6 +236,9 @@ mod generate_tests { } (actual_diff, expected_diff) }; + */ + eprintln!("actual != expected, diverge at char {}", counter); + /* eprintln!(" actual: {}", actual_diff); eprintln!("expected: {}", expected_diff); assert!(false); From fe718fea39e4c45c0858946671aa8b88f11ddfa2 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 18 Sep 2020 13:59:38 +0800 Subject: [PATCH 02/10] Remove Position parameter from plugin call function. --- codegen/src/function.rs | 214 +++++++++++++++++++++-------------- codegen/src/test/function.rs | 12 +- codegen/src/test/module.rs | 38 +++---- src/fn_call.rs | 4 +- src/plugin.rs | 5 +- 5 files changed, 157 insertions(+), 116 deletions(-) diff --git a/codegen/src/function.rs b/codegen/src/function.rs index 75812dbd..aa059013 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -84,71 +84,91 @@ impl ExportedParams for ExportedFnParams { let mut skip = false; let mut special = FnSpecialAccess::None; for attr in attrs { - let crate::attrs::AttrItem { key, value, span: item_span } = attr; + let crate::attrs::AttrItem { + key, + value, + span: item_span, + } = attr; match (key.to_string().as_ref(), value) { ("get", None) | ("set", None) | ("name", None) => { return Err(syn::Error::new(key.span(), "requires value")) - }, + } ("name", Some(s)) if &s.value() == FN_IDX_GET => { - return Err(syn::Error::new(item_span, - "use attribute 'index_get' instead")) - }, + return Err(syn::Error::new( + item_span, + "use attribute 'index_get' instead", + )) + } ("name", Some(s)) if &s.value() == FN_IDX_SET => { - return Err(syn::Error::new(item_span, - "use attribute 'index_set' instead")) - }, + return Err(syn::Error::new( + item_span, + "use attribute 'index_set' instead", + )) + } ("name", Some(s)) if s.value().starts_with("get$") => { - return Err(syn::Error::new(item_span, - format!("use attribute 'getter = \"{}\"' instead", - &s.value()["get$".len()..]))) - }, + return Err(syn::Error::new( + item_span, + format!( + "use attribute 'getter = \"{}\"' instead", + &s.value()["get$".len()..] + ), + )) + } ("name", Some(s)) if s.value().starts_with("set$") => { - return Err(syn::Error::new(item_span, - format!("use attribute 'setter = \"{}\"' instead", - &s.value()["set$".len()..]))) - }, + return Err(syn::Error::new( + item_span, + format!( + "use attribute 'setter = \"{}\"' instead", + &s.value()["set$".len()..] + ), + )) + } ("name", Some(s)) if s.value().contains('$') => { - return Err(syn::Error::new(s.span(), - "Rhai function names may not contain dollar sign")) - }, + return Err(syn::Error::new( + s.span(), + "Rhai function names may not contain dollar sign", + )) + } ("name", Some(s)) if s.value().contains('.') => { - return Err(syn::Error::new(s.span(), - "Rhai function names may not contain dot")) - }, - ("name", Some(s)) => { - name.push(s.value()) - }, - ("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")) + return Err(syn::Error::new( + s.span(), + "Rhai function names may not contain dot", + )) + } + ("name", Some(s)) => name.push(s.value()), + ("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")) + } + ("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_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")) + ("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")) @@ -327,26 +347,40 @@ impl ExportedFn { } 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()) + 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())), + 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.push(syn::LitStr::new( + &self.signature.ident.to_string(), + self.signature.ident.span(), + )); } literals @@ -394,53 +428,61 @@ impl ExportedFn { match params.special { // 2a. Property getters must take only the subject as an argument. - FnSpecialAccess::Property(Property::Get(_)) if self.arg_count() != 1 => + FnSpecialAccess::Property(Property::Get(_)) if self.arg_count() != 1 => { return Err(syn::Error::new( self.signature.span(), "property getter requires exactly 1 argument", - )), + )) + } // 2b. Property getters must return a value. - FnSpecialAccess::Property(Property::Get(_)) if self.return_type().is_none() => + FnSpecialAccess::Property(Property::Get(_)) if self.return_type().is_none() => { return Err(syn::Error::new( self.signature.span(), - "property getter must return a value" - )), + "property getter must return a value", + )) + } // 3a. Property setters must take the subject and a new value as arguments. - FnSpecialAccess::Property(Property::Set(_)) if self.arg_count() != 2 => + FnSpecialAccess::Property(Property::Set(_)) if self.arg_count() != 2 => { return Err(syn::Error::new( self.signature.span(), "property setter requires exactly 2 arguments", - )), + )) + } // 3b. Property setters must return nothing. - FnSpecialAccess::Property(Property::Set(_)) if self.return_type().is_some() => + FnSpecialAccess::Property(Property::Set(_)) if self.return_type().is_some() => { return Err(syn::Error::new( self.signature.span(), - "property setter must return no value" - )), + "property setter must return no value", + )) + } // 4a. Index getters must take the subject and the accessed "index" as arguments. - FnSpecialAccess::Index(Index::Get) if self.arg_count() != 2 => + FnSpecialAccess::Index(Index::Get) if self.arg_count() != 2 => { return Err(syn::Error::new( self.signature.span(), "index getter requires exactly 2 arguments", - )), + )) + } // 4b. Index getters must return a value. - FnSpecialAccess::Index(Index::Get) if self.return_type().is_none() => + FnSpecialAccess::Index(Index::Get) if self.return_type().is_none() => { return Err(syn::Error::new( self.signature.span(), - "index getter must return a value" - )), + "index getter must return a value", + )) + } // 5a. Index setters must take the subject, "index", and new value as arguments. - FnSpecialAccess::Index(Index::Set) if self.arg_count() != 3 => + FnSpecialAccess::Index(Index::Set) if self.arg_count() != 3 => { return Err(syn::Error::new( self.signature.span(), "index setter requires exactly 3 arguments", - )), + )) + } // 5b. Index setters must return nothing. - FnSpecialAccess::Index(Index::Set) if self.return_type().is_some() => + FnSpecialAccess::Index(Index::Set) if self.return_type().is_some() => { return Err(syn::Error::new( self.signature.span(), - "index setter must return no value" - )), + "index setter must return no value", + )) + } _ => {} } @@ -685,7 +727,7 @@ impl ExportedFn { quote! { impl PluginFunction for #type_name { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), #arg_count, "wrong arg count: {} != {}", diff --git a/codegen/src/test/function.rs b/codegen/src/test/function.rs index 31797438..61c1f942 100644 --- a/codegen/src/test/function.rs +++ b/codegen/src/test/function.rs @@ -279,7 +279,7 @@ mod generate_tests { struct Token(); impl PluginFunction for Token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 0usize, "wrong arg count: {} != {}", args.len(), 0usize); @@ -323,7 +323,7 @@ mod generate_tests { struct Token(); impl PluginFunction for Token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -364,7 +364,7 @@ mod generate_tests { let expected_tokens = quote! { impl PluginFunction for MyType { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -398,7 +398,7 @@ mod generate_tests { struct Token(); impl PluginFunction for Token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -445,7 +445,7 @@ mod generate_tests { struct Token(); impl PluginFunction for Token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -493,7 +493,7 @@ mod generate_tests { struct Token(); impl PluginFunction for Token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index 4d71f296..59e58ce7 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -307,7 +307,7 @@ mod generate_tests { struct get_mystic_number_token(); impl PluginFunction for get_mystic_number_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 0usize, "wrong arg count: {} != {}", args.len(), 0usize); @@ -369,7 +369,7 @@ mod generate_tests { struct add_one_to_token(); impl PluginFunction for add_one_to_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -446,7 +446,7 @@ mod generate_tests { struct add_one_to_token(); impl PluginFunction for add_one_to_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -474,7 +474,7 @@ mod generate_tests { struct add_n_to_token(); impl PluginFunction for add_n_to_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -540,7 +540,7 @@ mod generate_tests { struct add_together_token(); impl PluginFunction for add_together_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -613,7 +613,7 @@ mod generate_tests { struct add_together_token(); impl PluginFunction for add_together_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -855,7 +855,7 @@ mod generate_tests { struct get_mystic_number_token(); impl PluginFunction for get_mystic_number_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 0usize, "wrong arg count: {} != {}", args.len(), 0usize); @@ -948,7 +948,7 @@ mod generate_tests { struct print_out_to_token(); impl PluginFunction for print_out_to_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -1012,7 +1012,7 @@ mod generate_tests { struct increment_token(); impl PluginFunction for increment_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -1079,7 +1079,7 @@ mod generate_tests { struct increment_token(); impl PluginFunction for increment_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -1166,7 +1166,7 @@ mod generate_tests { struct increment_token(); impl PluginFunction for increment_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -1251,7 +1251,7 @@ mod generate_tests { struct int_foo_token(); impl PluginFunction for int_foo_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -1317,7 +1317,7 @@ mod generate_tests { struct int_foo_token(); impl PluginFunction for int_foo_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -1383,7 +1383,7 @@ mod generate_tests { struct int_foo_token(); impl PluginFunction for int_foo_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -1454,7 +1454,7 @@ mod generate_tests { struct int_foo_token(); impl PluginFunction for int_foo_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -1521,7 +1521,7 @@ mod generate_tests { struct get_by_index_token(); impl PluginFunction for get_by_index_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -1593,7 +1593,7 @@ mod generate_tests { struct get_by_index_token(); impl PluginFunction for get_by_index_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -1662,7 +1662,7 @@ mod generate_tests { struct set_by_index_token(); impl PluginFunction for set_by_index_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 3usize, "wrong arg count: {} != {}", args.len(), 3usize); @@ -1738,7 +1738,7 @@ mod generate_tests { struct set_by_index_token(); impl PluginFunction for set_by_index_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 3usize, "wrong arg count: {} != {}", args.len(), 3usize); diff --git a/src/fn_call.rs b/src/fn_call.rs index 3728d4e8..c40d352f 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -232,7 +232,7 @@ impl Engine { // Run external function let result = if func.is_plugin_fn() { - func.get_plugin_fn().call(args, Position::none()) + func.get_plugin_fn().call(args) } else { func.get_native_fn()(self, lib, args) }; @@ -1099,7 +1099,7 @@ impl Engine { self.call_script_fn(scope, mods, state, lib, &mut None, name, func, args, level) } - Some(f) if f.is_plugin_fn() => f.get_plugin_fn().call(args.as_mut(), Position::none()), + Some(f) if f.is_plugin_fn() => f.get_plugin_fn().call(args.as_mut()), Some(f) if f.is_native() => { if !f.is_method() { // Clone first argument diff --git a/src/plugin.rs b/src/plugin.rs index ef4a6590..e6e4e956 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -3,7 +3,7 @@ pub use crate::{ fn_native::CallableFunction, stdlib::any::TypeId, stdlib::boxed::Box, stdlib::format, stdlib::mem, stdlib::string::ToString, stdlib::vec as new_vec, stdlib::vec::Vec, Dynamic, - Engine, EvalAltResult, FnAccess, ImmutableString, Module, Position, RegisterResultFn, + Engine, EvalAltResult, FnAccess, ImmutableString, Module, RegisterResultFn, }; #[cfg(not(features = "no_module"))] @@ -34,8 +34,7 @@ pub trait PluginFunction { fn is_method_call(&self) -> bool; fn is_varadic(&self) -> bool; - fn call(&self, args: &mut [&mut Dynamic], pos: Position) - -> Result>; + fn call(&self, args: &mut [&mut Dynamic]) -> Result>; fn clone_boxed(&self) -> Box; From f5d132d1f4a613aa7b0c481c9dc8cceaf4a1c32d Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 18 Sep 2020 14:12:57 +0800 Subject: [PATCH 03/10] Fix doc test. --- src/fn_register.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_register.rs b/src/fn_register.rs index 28d33198..12aedad2 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -46,7 +46,7 @@ pub trait RegisterPlugin { /// fn is_method_call(&self) -> bool { false } /// fn is_varadic(&self) -> bool { false } /// - /// fn call(&self, args: &mut[&mut Dynamic], pos: Position) -> Result> { + /// fn call(&self, args: &mut[&mut Dynamic]) -> Result> { /// let x1: NUMBER = std::mem::take(args[0]).clone().cast::(); /// let y1: NUMBER = std::mem::take(args[1]).clone().cast::(); /// let x2: NUMBER = std::mem::take(args[2]).clone().cast::(); From 20a453b3cc480b8cbeae7ff5f51c2dd0f163c397 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 19 Sep 2020 18:18:40 +0800 Subject: [PATCH 04/10] Enable String parameters. --- codegen/src/function.rs | 23 ++++++++--- codegen/src/rhai_module.rs | 6 +++ codegen/src/test/function.rs | 12 ++---- codegen/src/test/module.rs | 76 ++++++++++++++++++++++++++++++++---- tests/plugins.rs | 5 +++ 5 files changed, 100 insertions(+), 22 deletions(-) diff --git a/codegen/src/function.rs b/codegen/src/function.rs index aa059013..82e76214 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -638,11 +638,13 @@ impl ExportedFn { // Handle the rest of the arguments, which all are passed by value. // // The only exception is strings, which need to be downcast to ImmutableString to enable a - // zero-copy conversion to &str by reference. + // zero-copy conversion to &str by reference, or a cloned String. let str_type_path = syn::parse2::(quote! { str }).unwrap(); + let string_type_path = syn::parse2::(quote! { String }).unwrap(); for (i, arg) in self.arg_list().enumerate().skip(skip_first_arg as usize) { let var = syn::Ident::new(&format!("arg{}", i), proc_macro2::Span::call_site()); - let is_str_ref; + let is_string; + let is_ref; match arg { syn::FnArg::Typed(pattern) => { let arg_type: &syn::Type = pattern.ty.as_ref(); @@ -653,15 +655,24 @@ impl ExportedFn { .. }) => match elem.as_ref() { &syn::Type::Path(ref p) if p.path == str_type_path => { - is_str_ref = true; + is_string = true; + is_ref = true; quote_spanned!(arg_type.span()=> mem::take(args[#i]) .clone().cast::()) } _ => panic!("internal error: why wasn't this found earlier!?"), }, + &syn::Type::Path(ref p) if p.path == string_type_path => { + is_string = true; + is_ref = false; + quote_spanned!(arg_type.span()=> + mem::take(args[#i]) + .clone().cast::<#arg_type>()) + } _ => { - is_str_ref = false; + is_string = false; + is_ref = false; quote_spanned!(arg_type.span()=> mem::take(args[#i]).clone().cast::<#arg_type>()) } @@ -673,7 +684,7 @@ impl ExportedFn { }) .unwrap(), ); - if !is_str_ref { + if !is_string { input_type_exprs.push( syn::parse2::(quote_spanned!( arg_type.span()=> TypeId::of::<#arg_type>() @@ -691,7 +702,7 @@ impl ExportedFn { } syn::FnArg::Receiver(_) => panic!("internal error: how did this happen!?"), } - if !is_str_ref { + if !is_ref { unpack_exprs.push(syn::parse2::(quote! { #var }).unwrap()); } else { unpack_exprs.push(syn::parse2::(quote! { &#var }).unwrap()); diff --git a/codegen/src/rhai_module.rs b/codegen/src/rhai_module.rs index 1859ba42..c25c9484 100644 --- a/codegen/src/rhai_module.rs +++ b/codegen/src/rhai_module.rs @@ -19,6 +19,7 @@ pub(crate) fn generate_body( let mut add_mod_blocks: Vec = Vec::new(); let mut set_flattened_mod_blocks: Vec = Vec::new(); let str_type_path = syn::parse2::(quote! { str }).unwrap(); + let string_type_path = syn::parse2::(quote! { String }).unwrap(); for (const_name, _, _) in consts { let const_literal = syn::LitStr::new(&const_name, proc_macro2::Span::call_site()); @@ -97,6 +98,11 @@ pub(crate) fn generate_body( } _ => panic!("internal error: non-string shared reference!?"), }, + syn::Type::Path(ref p) if p.path == string_type_path => { + syn::parse2::(quote! { + ImmutableString }) + .unwrap() + } syn::Type::Reference(syn::TypeReference { mutability: Some(_), ref elem, diff --git a/codegen/src/test/function.rs b/codegen/src/test/function.rs index 61c1f942..b6d8e894 100644 --- a/codegen/src/test/function.rs +++ b/codegen/src/test/function.rs @@ -245,8 +245,7 @@ mod generate_tests { false } }); - /* - let (actual_diff, expected_diff) = { + let (_actual_diff, _expected_diff) = { let mut actual_diff = String::new(); let mut expected_diff = String::new(); for (a, e) in _iter.take(50) { @@ -255,13 +254,10 @@ mod generate_tests { } (actual_diff, expected_diff) }; - */ eprintln!("actual != expected, diverge at char {}", counter); - /* - eprintln!(" actual: {}", actual_diff); - eprintln!("expected: {}", expected_diff); - assert!(false); - */ + // eprintln!(" actual: {}", _actual_diff); + // eprintln!("expected: {}", _expected_diff); + // assert!(false); } assert_eq!(actual, expected); } diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index 59e58ce7..a2ab7eab 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -226,8 +226,7 @@ mod generate_tests { false } }); - /* - let (actual_diff, expected_diff) = { + let (_actual_diff, _expected_diff) = { let mut actual_diff = String::new(); let mut expected_diff = String::new(); for (a, e) in _iter.take(50) { @@ -236,13 +235,10 @@ mod generate_tests { } (actual_diff, expected_diff) }; - */ eprintln!("actual != expected, diverge at char {}", counter); - /* - eprintln!(" actual: {}", actual_diff); - eprintln!("expected: {}", expected_diff); - assert!(false); - */ + // eprintln!(" actual: {}", _actual_diff); + // eprintln!("expected: {}", _expected_diff); + // assert!(false); } assert_eq!(actual, expected); } @@ -978,6 +974,70 @@ mod generate_tests { assert_streams_eq(item_mod.generate(), expected_tokens); } + #[test] + fn one_string_arg_fn_module() { + let input_tokens: TokenStream = quote! { + pub mod str_fn { + pub fn print_out_to(x: String) { + x + 1 + } + } + }; + + let expected_tokens = quote! { + pub mod str_fn { + pub fn print_out_to(x: String) { + x + 1 + } + #[allow(unused_imports)] + use super::*; + + pub fn rhai_module_generate() -> Module { + let mut m = Module::new(); + rhai_generate_into_module(&mut m, false); + m + } + #[allow(unused_mut)] + pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { + m.set_fn("print_out_to", FnAccess::Public, + &[core::any::TypeId::of::()], + CallableFunction::from_plugin(print_out_to_token())); + if flatten {} else {} + } + #[allow(non_camel_case_types)] + struct print_out_to_token(); + impl PluginFunction for print_out_to_token { + fn call(&self, + args: &mut [&mut Dynamic] + ) -> Result> { + debug_assert_eq!(args.len(), 1usize, + "wrong arg count: {} != {}", args.len(), 1usize); + let arg0 = mem::take(args[0usize]).clone().cast::(); + Ok(Dynamic::from(print_out_to(arg0))) + } + + fn is_method_call(&self) -> bool { false } + fn is_varadic(&self) -> bool { false } + fn clone_boxed(&self) -> Box { + Box::new(print_out_to_token()) + } + fn input_types(&self) -> Box<[TypeId]> { + new_vec![TypeId::of::()].into_boxed_slice() + } + } + pub fn print_out_to_token_callable() -> CallableFunction { + CallableFunction::from_plugin(print_out_to_token()) + } + pub fn print_out_to_token_input_types() -> Box<[TypeId]> { + print_out_to_token().input_types() + } + } + }; + + let item_mod = syn::parse2::(input_tokens).unwrap(); + assert_streams_eq(item_mod.generate(), expected_tokens); + } + #[test] fn one_mut_ref_fn_module() { let input_tokens: TokenStream = quote! { diff --git a/tests/plugins.rs b/tests/plugins.rs index 2bee84e4..ce403dd6 100644 --- a/tests/plugins.rs +++ b/tests/plugins.rs @@ -24,6 +24,10 @@ mod test { } } + pub fn hash(_text: String) -> INT { + 42 + } + #[rhai_fn(name = "test", name = "hi")] #[inline(always)] pub fn len(array: &mut Array, mul: INT) -> INT { @@ -77,6 +81,7 @@ fn test_plugins_package() -> Result<(), Box> { #[cfg(not(feature = "no_object"))] assert_eq!(engine.eval::("let a = [1, 2, 3]; a.foo")?, 1); + assert_eq!(engine.eval::(r#"hash("hello")"#)?, 42); assert_eq!(engine.eval::("let a = [1, 2, 3]; test(a, 2)")?, 6); assert_eq!(engine.eval::("let a = [1, 2, 3]; hi(a, 2)")?, 6); assert_eq!(engine.eval::("let a = [1, 2, 3]; test(a, 2)")?, 6); From 7c3498a4e18061a9dd3e2a1cc2dcfa6abef59f82 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 18 Sep 2020 12:31:41 +0800 Subject: [PATCH 05/10] Prevent errors when using alternative error printout style. --- codegen/src/test/function.rs | 4 +++- codegen/src/test/module.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/codegen/src/test/function.rs b/codegen/src/test/function.rs index a4a54959..31797438 100644 --- a/codegen/src/test/function.rs +++ b/codegen/src/test/function.rs @@ -245,7 +245,6 @@ mod generate_tests { false } }); - eprintln!("actual != expected, diverge at char {}", counter); /* let (actual_diff, expected_diff) = { let mut actual_diff = String::new(); @@ -256,6 +255,9 @@ mod generate_tests { } (actual_diff, expected_diff) }; + */ + eprintln!("actual != expected, diverge at char {}", counter); + /* eprintln!(" actual: {}", actual_diff); eprintln!("expected: {}", expected_diff); assert!(false); diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index b560e94b..4d71f296 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -226,7 +226,6 @@ mod generate_tests { false } }); - eprintln!("actual != expected, diverge at char {}", counter); /* let (actual_diff, expected_diff) = { let mut actual_diff = String::new(); @@ -237,6 +236,9 @@ mod generate_tests { } (actual_diff, expected_diff) }; + */ + eprintln!("actual != expected, diverge at char {}", counter); + /* eprintln!(" actual: {}", actual_diff); eprintln!("expected: {}", expected_diff); assert!(false); From cfe28c92829ec1c17c61769333cf1098283002d6 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 18 Sep 2020 13:59:38 +0800 Subject: [PATCH 06/10] Remove Position parameter from plugin call function. --- codegen/src/function.rs | 214 +++++++++++++++++++++-------------- codegen/src/test/function.rs | 12 +- codegen/src/test/module.rs | 38 +++---- src/fn_call.rs | 4 +- src/plugin.rs | 5 +- 5 files changed, 157 insertions(+), 116 deletions(-) diff --git a/codegen/src/function.rs b/codegen/src/function.rs index 75812dbd..aa059013 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -84,71 +84,91 @@ impl ExportedParams for ExportedFnParams { let mut skip = false; let mut special = FnSpecialAccess::None; for attr in attrs { - let crate::attrs::AttrItem { key, value, span: item_span } = attr; + let crate::attrs::AttrItem { + key, + value, + span: item_span, + } = attr; match (key.to_string().as_ref(), value) { ("get", None) | ("set", None) | ("name", None) => { return Err(syn::Error::new(key.span(), "requires value")) - }, + } ("name", Some(s)) if &s.value() == FN_IDX_GET => { - return Err(syn::Error::new(item_span, - "use attribute 'index_get' instead")) - }, + return Err(syn::Error::new( + item_span, + "use attribute 'index_get' instead", + )) + } ("name", Some(s)) if &s.value() == FN_IDX_SET => { - return Err(syn::Error::new(item_span, - "use attribute 'index_set' instead")) - }, + return Err(syn::Error::new( + item_span, + "use attribute 'index_set' instead", + )) + } ("name", Some(s)) if s.value().starts_with("get$") => { - return Err(syn::Error::new(item_span, - format!("use attribute 'getter = \"{}\"' instead", - &s.value()["get$".len()..]))) - }, + return Err(syn::Error::new( + item_span, + format!( + "use attribute 'getter = \"{}\"' instead", + &s.value()["get$".len()..] + ), + )) + } ("name", Some(s)) if s.value().starts_with("set$") => { - return Err(syn::Error::new(item_span, - format!("use attribute 'setter = \"{}\"' instead", - &s.value()["set$".len()..]))) - }, + return Err(syn::Error::new( + item_span, + format!( + "use attribute 'setter = \"{}\"' instead", + &s.value()["set$".len()..] + ), + )) + } ("name", Some(s)) if s.value().contains('$') => { - return Err(syn::Error::new(s.span(), - "Rhai function names may not contain dollar sign")) - }, + return Err(syn::Error::new( + s.span(), + "Rhai function names may not contain dollar sign", + )) + } ("name", Some(s)) if s.value().contains('.') => { - return Err(syn::Error::new(s.span(), - "Rhai function names may not contain dot")) - }, - ("name", Some(s)) => { - name.push(s.value()) - }, - ("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")) + return Err(syn::Error::new( + s.span(), + "Rhai function names may not contain dot", + )) + } + ("name", Some(s)) => name.push(s.value()), + ("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")) + } + ("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_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")) + ("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")) @@ -327,26 +347,40 @@ impl ExportedFn { } 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()) + 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())), + 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.push(syn::LitStr::new( + &self.signature.ident.to_string(), + self.signature.ident.span(), + )); } literals @@ -394,53 +428,61 @@ impl ExportedFn { match params.special { // 2a. Property getters must take only the subject as an argument. - FnSpecialAccess::Property(Property::Get(_)) if self.arg_count() != 1 => + FnSpecialAccess::Property(Property::Get(_)) if self.arg_count() != 1 => { return Err(syn::Error::new( self.signature.span(), "property getter requires exactly 1 argument", - )), + )) + } // 2b. Property getters must return a value. - FnSpecialAccess::Property(Property::Get(_)) if self.return_type().is_none() => + FnSpecialAccess::Property(Property::Get(_)) if self.return_type().is_none() => { return Err(syn::Error::new( self.signature.span(), - "property getter must return a value" - )), + "property getter must return a value", + )) + } // 3a. Property setters must take the subject and a new value as arguments. - FnSpecialAccess::Property(Property::Set(_)) if self.arg_count() != 2 => + FnSpecialAccess::Property(Property::Set(_)) if self.arg_count() != 2 => { return Err(syn::Error::new( self.signature.span(), "property setter requires exactly 2 arguments", - )), + )) + } // 3b. Property setters must return nothing. - FnSpecialAccess::Property(Property::Set(_)) if self.return_type().is_some() => + FnSpecialAccess::Property(Property::Set(_)) if self.return_type().is_some() => { return Err(syn::Error::new( self.signature.span(), - "property setter must return no value" - )), + "property setter must return no value", + )) + } // 4a. Index getters must take the subject and the accessed "index" as arguments. - FnSpecialAccess::Index(Index::Get) if self.arg_count() != 2 => + FnSpecialAccess::Index(Index::Get) if self.arg_count() != 2 => { return Err(syn::Error::new( self.signature.span(), "index getter requires exactly 2 arguments", - )), + )) + } // 4b. Index getters must return a value. - FnSpecialAccess::Index(Index::Get) if self.return_type().is_none() => + FnSpecialAccess::Index(Index::Get) if self.return_type().is_none() => { return Err(syn::Error::new( self.signature.span(), - "index getter must return a value" - )), + "index getter must return a value", + )) + } // 5a. Index setters must take the subject, "index", and new value as arguments. - FnSpecialAccess::Index(Index::Set) if self.arg_count() != 3 => + FnSpecialAccess::Index(Index::Set) if self.arg_count() != 3 => { return Err(syn::Error::new( self.signature.span(), "index setter requires exactly 3 arguments", - )), + )) + } // 5b. Index setters must return nothing. - FnSpecialAccess::Index(Index::Set) if self.return_type().is_some() => + FnSpecialAccess::Index(Index::Set) if self.return_type().is_some() => { return Err(syn::Error::new( self.signature.span(), - "index setter must return no value" - )), + "index setter must return no value", + )) + } _ => {} } @@ -685,7 +727,7 @@ impl ExportedFn { quote! { impl PluginFunction for #type_name { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), #arg_count, "wrong arg count: {} != {}", diff --git a/codegen/src/test/function.rs b/codegen/src/test/function.rs index 31797438..61c1f942 100644 --- a/codegen/src/test/function.rs +++ b/codegen/src/test/function.rs @@ -279,7 +279,7 @@ mod generate_tests { struct Token(); impl PluginFunction for Token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 0usize, "wrong arg count: {} != {}", args.len(), 0usize); @@ -323,7 +323,7 @@ mod generate_tests { struct Token(); impl PluginFunction for Token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -364,7 +364,7 @@ mod generate_tests { let expected_tokens = quote! { impl PluginFunction for MyType { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -398,7 +398,7 @@ mod generate_tests { struct Token(); impl PluginFunction for Token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -445,7 +445,7 @@ mod generate_tests { struct Token(); impl PluginFunction for Token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -493,7 +493,7 @@ mod generate_tests { struct Token(); impl PluginFunction for Token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index 4d71f296..59e58ce7 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -307,7 +307,7 @@ mod generate_tests { struct get_mystic_number_token(); impl PluginFunction for get_mystic_number_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 0usize, "wrong arg count: {} != {}", args.len(), 0usize); @@ -369,7 +369,7 @@ mod generate_tests { struct add_one_to_token(); impl PluginFunction for add_one_to_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -446,7 +446,7 @@ mod generate_tests { struct add_one_to_token(); impl PluginFunction for add_one_to_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -474,7 +474,7 @@ mod generate_tests { struct add_n_to_token(); impl PluginFunction for add_n_to_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -540,7 +540,7 @@ mod generate_tests { struct add_together_token(); impl PluginFunction for add_together_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -613,7 +613,7 @@ mod generate_tests { struct add_together_token(); impl PluginFunction for add_together_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -855,7 +855,7 @@ mod generate_tests { struct get_mystic_number_token(); impl PluginFunction for get_mystic_number_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 0usize, "wrong arg count: {} != {}", args.len(), 0usize); @@ -948,7 +948,7 @@ mod generate_tests { struct print_out_to_token(); impl PluginFunction for print_out_to_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -1012,7 +1012,7 @@ mod generate_tests { struct increment_token(); impl PluginFunction for increment_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -1079,7 +1079,7 @@ mod generate_tests { struct increment_token(); impl PluginFunction for increment_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -1166,7 +1166,7 @@ mod generate_tests { struct increment_token(); impl PluginFunction for increment_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -1251,7 +1251,7 @@ mod generate_tests { struct int_foo_token(); impl PluginFunction for int_foo_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -1317,7 +1317,7 @@ mod generate_tests { struct int_foo_token(); impl PluginFunction for int_foo_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); @@ -1383,7 +1383,7 @@ mod generate_tests { struct int_foo_token(); impl PluginFunction for int_foo_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -1454,7 +1454,7 @@ mod generate_tests { struct int_foo_token(); impl PluginFunction for int_foo_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -1521,7 +1521,7 @@ mod generate_tests { struct get_by_index_token(); impl PluginFunction for get_by_index_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -1593,7 +1593,7 @@ mod generate_tests { struct get_by_index_token(); impl PluginFunction for get_by_index_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); @@ -1662,7 +1662,7 @@ mod generate_tests { struct set_by_index_token(); impl PluginFunction for set_by_index_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 3usize, "wrong arg count: {} != {}", args.len(), 3usize); @@ -1738,7 +1738,7 @@ mod generate_tests { struct set_by_index_token(); impl PluginFunction for set_by_index_token { fn call(&self, - args: &mut [&mut Dynamic], pos: Position + args: &mut [&mut Dynamic] ) -> Result> { debug_assert_eq!(args.len(), 3usize, "wrong arg count: {} != {}", args.len(), 3usize); diff --git a/src/fn_call.rs b/src/fn_call.rs index 3728d4e8..c40d352f 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -232,7 +232,7 @@ impl Engine { // Run external function let result = if func.is_plugin_fn() { - func.get_plugin_fn().call(args, Position::none()) + func.get_plugin_fn().call(args) } else { func.get_native_fn()(self, lib, args) }; @@ -1099,7 +1099,7 @@ impl Engine { self.call_script_fn(scope, mods, state, lib, &mut None, name, func, args, level) } - Some(f) if f.is_plugin_fn() => f.get_plugin_fn().call(args.as_mut(), Position::none()), + Some(f) if f.is_plugin_fn() => f.get_plugin_fn().call(args.as_mut()), Some(f) if f.is_native() => { if !f.is_method() { // Clone first argument diff --git a/src/plugin.rs b/src/plugin.rs index ef4a6590..e6e4e956 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -3,7 +3,7 @@ pub use crate::{ fn_native::CallableFunction, stdlib::any::TypeId, stdlib::boxed::Box, stdlib::format, stdlib::mem, stdlib::string::ToString, stdlib::vec as new_vec, stdlib::vec::Vec, Dynamic, - Engine, EvalAltResult, FnAccess, ImmutableString, Module, Position, RegisterResultFn, + Engine, EvalAltResult, FnAccess, ImmutableString, Module, RegisterResultFn, }; #[cfg(not(features = "no_module"))] @@ -34,8 +34,7 @@ pub trait PluginFunction { fn is_method_call(&self) -> bool; fn is_varadic(&self) -> bool; - fn call(&self, args: &mut [&mut Dynamic], pos: Position) - -> Result>; + fn call(&self, args: &mut [&mut Dynamic]) -> Result>; fn clone_boxed(&self) -> Box; From 5a7a0f11ae504a371bb0dbd72b3f7b0205396881 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 18 Sep 2020 14:12:57 +0800 Subject: [PATCH 07/10] Fix doc test. --- src/fn_register.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_register.rs b/src/fn_register.rs index 28d33198..12aedad2 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -46,7 +46,7 @@ pub trait RegisterPlugin { /// fn is_method_call(&self) -> bool { false } /// fn is_varadic(&self) -> bool { false } /// - /// fn call(&self, args: &mut[&mut Dynamic], pos: Position) -> Result> { + /// fn call(&self, args: &mut[&mut Dynamic]) -> Result> { /// let x1: NUMBER = std::mem::take(args[0]).clone().cast::(); /// let y1: NUMBER = std::mem::take(args[1]).clone().cast::(); /// let x2: NUMBER = std::mem::take(args[2]).clone().cast::(); From bf245a798b57b9776eacffba8926b55f248391af Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 19 Sep 2020 18:18:40 +0800 Subject: [PATCH 08/10] Enable String parameters. --- codegen/src/function.rs | 23 ++++++++--- codegen/src/rhai_module.rs | 6 +++ codegen/src/test/function.rs | 12 ++---- codegen/src/test/module.rs | 76 ++++++++++++++++++++++++++++++++---- tests/plugins.rs | 5 +++ 5 files changed, 100 insertions(+), 22 deletions(-) diff --git a/codegen/src/function.rs b/codegen/src/function.rs index aa059013..82e76214 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -638,11 +638,13 @@ impl ExportedFn { // Handle the rest of the arguments, which all are passed by value. // // The only exception is strings, which need to be downcast to ImmutableString to enable a - // zero-copy conversion to &str by reference. + // zero-copy conversion to &str by reference, or a cloned String. let str_type_path = syn::parse2::(quote! { str }).unwrap(); + let string_type_path = syn::parse2::(quote! { String }).unwrap(); for (i, arg) in self.arg_list().enumerate().skip(skip_first_arg as usize) { let var = syn::Ident::new(&format!("arg{}", i), proc_macro2::Span::call_site()); - let is_str_ref; + let is_string; + let is_ref; match arg { syn::FnArg::Typed(pattern) => { let arg_type: &syn::Type = pattern.ty.as_ref(); @@ -653,15 +655,24 @@ impl ExportedFn { .. }) => match elem.as_ref() { &syn::Type::Path(ref p) if p.path == str_type_path => { - is_str_ref = true; + is_string = true; + is_ref = true; quote_spanned!(arg_type.span()=> mem::take(args[#i]) .clone().cast::()) } _ => panic!("internal error: why wasn't this found earlier!?"), }, + &syn::Type::Path(ref p) if p.path == string_type_path => { + is_string = true; + is_ref = false; + quote_spanned!(arg_type.span()=> + mem::take(args[#i]) + .clone().cast::<#arg_type>()) + } _ => { - is_str_ref = false; + is_string = false; + is_ref = false; quote_spanned!(arg_type.span()=> mem::take(args[#i]).clone().cast::<#arg_type>()) } @@ -673,7 +684,7 @@ impl ExportedFn { }) .unwrap(), ); - if !is_str_ref { + if !is_string { input_type_exprs.push( syn::parse2::(quote_spanned!( arg_type.span()=> TypeId::of::<#arg_type>() @@ -691,7 +702,7 @@ impl ExportedFn { } syn::FnArg::Receiver(_) => panic!("internal error: how did this happen!?"), } - if !is_str_ref { + if !is_ref { unpack_exprs.push(syn::parse2::(quote! { #var }).unwrap()); } else { unpack_exprs.push(syn::parse2::(quote! { &#var }).unwrap()); diff --git a/codegen/src/rhai_module.rs b/codegen/src/rhai_module.rs index 1859ba42..c25c9484 100644 --- a/codegen/src/rhai_module.rs +++ b/codegen/src/rhai_module.rs @@ -19,6 +19,7 @@ pub(crate) fn generate_body( let mut add_mod_blocks: Vec = Vec::new(); let mut set_flattened_mod_blocks: Vec = Vec::new(); let str_type_path = syn::parse2::(quote! { str }).unwrap(); + let string_type_path = syn::parse2::(quote! { String }).unwrap(); for (const_name, _, _) in consts { let const_literal = syn::LitStr::new(&const_name, proc_macro2::Span::call_site()); @@ -97,6 +98,11 @@ pub(crate) fn generate_body( } _ => panic!("internal error: non-string shared reference!?"), }, + syn::Type::Path(ref p) if p.path == string_type_path => { + syn::parse2::(quote! { + ImmutableString }) + .unwrap() + } syn::Type::Reference(syn::TypeReference { mutability: Some(_), ref elem, diff --git a/codegen/src/test/function.rs b/codegen/src/test/function.rs index 61c1f942..b6d8e894 100644 --- a/codegen/src/test/function.rs +++ b/codegen/src/test/function.rs @@ -245,8 +245,7 @@ mod generate_tests { false } }); - /* - let (actual_diff, expected_diff) = { + let (_actual_diff, _expected_diff) = { let mut actual_diff = String::new(); let mut expected_diff = String::new(); for (a, e) in _iter.take(50) { @@ -255,13 +254,10 @@ mod generate_tests { } (actual_diff, expected_diff) }; - */ eprintln!("actual != expected, diverge at char {}", counter); - /* - eprintln!(" actual: {}", actual_diff); - eprintln!("expected: {}", expected_diff); - assert!(false); - */ + // eprintln!(" actual: {}", _actual_diff); + // eprintln!("expected: {}", _expected_diff); + // assert!(false); } assert_eq!(actual, expected); } diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index 59e58ce7..a2ab7eab 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -226,8 +226,7 @@ mod generate_tests { false } }); - /* - let (actual_diff, expected_diff) = { + let (_actual_diff, _expected_diff) = { let mut actual_diff = String::new(); let mut expected_diff = String::new(); for (a, e) in _iter.take(50) { @@ -236,13 +235,10 @@ mod generate_tests { } (actual_diff, expected_diff) }; - */ eprintln!("actual != expected, diverge at char {}", counter); - /* - eprintln!(" actual: {}", actual_diff); - eprintln!("expected: {}", expected_diff); - assert!(false); - */ + // eprintln!(" actual: {}", _actual_diff); + // eprintln!("expected: {}", _expected_diff); + // assert!(false); } assert_eq!(actual, expected); } @@ -978,6 +974,70 @@ mod generate_tests { assert_streams_eq(item_mod.generate(), expected_tokens); } + #[test] + fn one_string_arg_fn_module() { + let input_tokens: TokenStream = quote! { + pub mod str_fn { + pub fn print_out_to(x: String) { + x + 1 + } + } + }; + + let expected_tokens = quote! { + pub mod str_fn { + pub fn print_out_to(x: String) { + x + 1 + } + #[allow(unused_imports)] + use super::*; + + pub fn rhai_module_generate() -> Module { + let mut m = Module::new(); + rhai_generate_into_module(&mut m, false); + m + } + #[allow(unused_mut)] + pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { + m.set_fn("print_out_to", FnAccess::Public, + &[core::any::TypeId::of::()], + CallableFunction::from_plugin(print_out_to_token())); + if flatten {} else {} + } + #[allow(non_camel_case_types)] + struct print_out_to_token(); + impl PluginFunction for print_out_to_token { + fn call(&self, + args: &mut [&mut Dynamic] + ) -> Result> { + debug_assert_eq!(args.len(), 1usize, + "wrong arg count: {} != {}", args.len(), 1usize); + let arg0 = mem::take(args[0usize]).clone().cast::(); + Ok(Dynamic::from(print_out_to(arg0))) + } + + fn is_method_call(&self) -> bool { false } + fn is_varadic(&self) -> bool { false } + fn clone_boxed(&self) -> Box { + Box::new(print_out_to_token()) + } + fn input_types(&self) -> Box<[TypeId]> { + new_vec![TypeId::of::()].into_boxed_slice() + } + } + pub fn print_out_to_token_callable() -> CallableFunction { + CallableFunction::from_plugin(print_out_to_token()) + } + pub fn print_out_to_token_input_types() -> Box<[TypeId]> { + print_out_to_token().input_types() + } + } + }; + + let item_mod = syn::parse2::(input_tokens).unwrap(); + assert_streams_eq(item_mod.generate(), expected_tokens); + } + #[test] fn one_mut_ref_fn_module() { let input_tokens: TokenStream = quote! { diff --git a/tests/plugins.rs b/tests/plugins.rs index 2bee84e4..ce403dd6 100644 --- a/tests/plugins.rs +++ b/tests/plugins.rs @@ -24,6 +24,10 @@ mod test { } } + pub fn hash(_text: String) -> INT { + 42 + } + #[rhai_fn(name = "test", name = "hi")] #[inline(always)] pub fn len(array: &mut Array, mul: INT) -> INT { @@ -77,6 +81,7 @@ fn test_plugins_package() -> Result<(), Box> { #[cfg(not(feature = "no_object"))] assert_eq!(engine.eval::("let a = [1, 2, 3]; a.foo")?, 1); + assert_eq!(engine.eval::(r#"hash("hello")"#)?, 42); assert_eq!(engine.eval::("let a = [1, 2, 3]; test(a, 2)")?, 6); assert_eq!(engine.eval::("let a = [1, 2, 3]; hi(a, 2)")?, 6); assert_eq!(engine.eval::("let a = [1, 2, 3]; test(a, 2)")?, 6); From 2ba875a17728648de8155a603b1e16215e800850 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 20 Sep 2020 14:23:14 +0800 Subject: [PATCH 09/10] Use take_string for &str and String parameters. --- codegen/src/function.rs | 6 ++---- codegen/src/test/function.rs | 2 +- codegen/src/test/module.rs | 4 ++-- src/any.rs | 4 +++- tests/plugins.rs | 4 ++++ 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/codegen/src/function.rs b/codegen/src/function.rs index 82e76214..2fca6d96 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -658,8 +658,7 @@ impl ExportedFn { is_string = true; is_ref = true; quote_spanned!(arg_type.span()=> - mem::take(args[#i]) - .clone().cast::()) + mem::take(args[#i]).take_immutable_string().unwrap()) } _ => panic!("internal error: why wasn't this found earlier!?"), }, @@ -667,8 +666,7 @@ impl ExportedFn { is_string = true; is_ref = false; quote_spanned!(arg_type.span()=> - mem::take(args[#i]) - .clone().cast::<#arg_type>()) + mem::take(args[#i]).take_string().unwrap()) } _ => { is_string = false; diff --git a/codegen/src/test/function.rs b/codegen/src/test/function.rs index b6d8e894..f22f1fe2 100644 --- a/codegen/src/test/function.rs +++ b/codegen/src/test/function.rs @@ -493,7 +493,7 @@ mod generate_tests { ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); - let arg0 = mem::take(args[0usize]).clone().cast::(); + let arg0 = mem::take(args[0usize]).take_immutable_string().unwrap(); Ok(Dynamic::from(special_print(&arg0))) } diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index a2ab7eab..80a93f28 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -948,7 +948,7 @@ mod generate_tests { ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); - let arg0 = mem::take(args[0usize]).clone().cast::(); + let arg0 = mem::take(args[0usize]).take_immutable_string().unwrap(); Ok(Dynamic::from(print_out_to(&arg0))) } @@ -1012,7 +1012,7 @@ mod generate_tests { ) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); - let arg0 = mem::take(args[0usize]).clone().cast::(); + let arg0 = mem::take(args[0usize]).take_string().unwrap(); Ok(Dynamic::from(print_out_to(arg0))) } diff --git a/src/any.rs b/src/any.rs index 7b1fa184..a1e532aa 100644 --- a/src/any.rs +++ b/src/any.rs @@ -1136,6 +1136,7 @@ impl Dynamic { } /// Convert the `Dynamic` into `String` and return it. + /// If there are other references to the same string, a cloned copy is returned. /// Returns the name of the actual type if the cast fails. #[inline(always)] pub fn take_string(self) -> Result { @@ -1145,7 +1146,8 @@ impl Dynamic { /// Convert the `Dynamic` into `ImmutableString` and return it. /// Returns the name of the actual type if the cast fails. - pub(crate) fn take_immutable_string(self) -> Result { + #[inline] + pub fn take_immutable_string(self) -> Result { match self.0 { Union::Str(s) => Ok(s), Union::FnPtr(f) => Ok(f.take_data().0), diff --git a/tests/plugins.rs b/tests/plugins.rs index ce403dd6..909ad51b 100644 --- a/tests/plugins.rs +++ b/tests/plugins.rs @@ -27,6 +27,9 @@ mod test { pub fn hash(_text: String) -> INT { 42 } + pub fn hash2(_text: &str) -> INT { + 42 + } #[rhai_fn(name = "test", name = "hi")] #[inline(always)] @@ -82,6 +85,7 @@ fn test_plugins_package() -> Result<(), Box> { assert_eq!(engine.eval::("let a = [1, 2, 3]; a.foo")?, 1); assert_eq!(engine.eval::(r#"hash("hello")"#)?, 42); + assert_eq!(engine.eval::(r#"hash2("hello")"#)?, 42); assert_eq!(engine.eval::("let a = [1, 2, 3]; test(a, 2)")?, 6); assert_eq!(engine.eval::("let a = [1, 2, 3]; hi(a, 2)")?, 6); assert_eq!(engine.eval::("let a = [1, 2, 3]; test(a, 2)")?, 6); From 3a98567139185f27d80d32b7e2c92907f81c4664 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 20 Sep 2020 14:29:10 +0800 Subject: [PATCH 10/10] Use take_string. --- codegen/src/function.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/codegen/src/function.rs b/codegen/src/function.rs index 2c0cf525..2fca6d96 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -666,8 +666,7 @@ impl ExportedFn { is_string = true; is_ref = false; quote_spanned!(arg_type.span()=> - mem::take(args[#i]) - .clone().cast::<#arg_type>()) + mem::take(args[#i]).take_string().unwrap()) } _ => { is_string = false;