@@ -12,9 +12,8 @@ mod syn_ext;
1212mod zval;
1313
1414use proc_macro:: TokenStream ;
15- use syn:: {
16- parse_macro_input, DeriveInput , ItemConst , ItemFn , ItemForeignMod , ItemImpl , ItemStruct ,
17- } ;
15+ use proc_macro2:: TokenStream as TokenStream2 ;
16+ use syn:: { DeriveInput , ItemConst , ItemFn , ItemForeignMod , ItemImpl , ItemStruct } ;
1817
1918extern crate proc_macro;
2019
@@ -203,14 +202,17 @@ extern crate proc_macro;
203202// END DOCS FROM classes.md
204203#[ proc_macro_attribute]
205204pub fn php_class ( args : TokenStream , input : TokenStream ) -> TokenStream {
206- let input = parse_macro_input ! ( input as ItemStruct ) ;
205+ php_class_internal ( args. into ( ) , input. into ( ) ) . into ( )
206+ }
207+
208+ #[ allow( clippy:: needless_pass_by_value) ]
209+ fn php_class_internal ( args : TokenStream2 , input : TokenStream2 ) -> TokenStream2 {
210+ let input = parse_macro_input2 ! ( input as ItemStruct ) ;
207211 if !args. is_empty ( ) {
208- return err ! ( input => "`#[php_class(<args>)]` args are no longer supported. Please use `#[php(<args>)]` instead." ) . to_compile_error ( ) . into ( ) ;
212+ return err ! ( input => "`#[php_class(<args>)]` args are no longer supported. Please use `#[php(<args>)]` instead." ) . to_compile_error ( ) ;
209213 }
210214
211- class:: parser ( input)
212- . unwrap_or_else ( |e| e. to_compile_error ( ) )
213- . into ( )
215+ class:: parser ( input) . unwrap_or_else ( |e| e. to_compile_error ( ) )
214216}
215217
216218// BEGIN DOCS FROM function.md
@@ -371,14 +373,17 @@ pub fn php_class(args: TokenStream, input: TokenStream) -> TokenStream {
371373// END DOCS FROM function.md
372374#[ proc_macro_attribute]
373375pub fn php_function ( args : TokenStream , input : TokenStream ) -> TokenStream {
374- let input = parse_macro_input ! ( input as ItemFn ) ;
376+ php_function_internal ( args. into ( ) , input. into ( ) ) . into ( )
377+ }
378+
379+ #[ allow( clippy:: needless_pass_by_value) ]
380+ fn php_function_internal ( args : TokenStream2 , input : TokenStream2 ) -> TokenStream2 {
381+ let input = parse_macro_input2 ! ( input as ItemFn ) ;
375382 if !args. is_empty ( ) {
376- return err ! ( input => "`#[php_function(<args>)]` args are no longer supported. Please use `#[php(<args>)]` instead." ) . to_compile_error ( ) . into ( ) ;
383+ return err ! ( input => "`#[php_function(<args>)]` args are no longer supported. Please use `#[php(<args>)]` instead." ) . to_compile_error ( ) ;
377384 }
378385
379- function:: parser ( input)
380- . unwrap_or_else ( |e| e. to_compile_error ( ) )
381- . into ( )
386+ function:: parser ( input) . unwrap_or_else ( |e| e. to_compile_error ( ) )
382387}
383388
384389// BEGIN DOCS FROM constant.md
@@ -436,14 +441,17 @@ pub fn php_function(args: TokenStream, input: TokenStream) -> TokenStream {
436441// END DOCS FROM constant.md
437442#[ proc_macro_attribute]
438443pub fn php_const ( args : TokenStream , input : TokenStream ) -> TokenStream {
439- let input = parse_macro_input ! ( input as ItemConst ) ;
444+ php_const_internal ( args. into ( ) , input. into ( ) ) . into ( )
445+ }
446+
447+ #[ allow( clippy:: needless_pass_by_value) ]
448+ fn php_const_internal ( args : TokenStream2 , input : TokenStream2 ) -> TokenStream2 {
449+ let input = parse_macro_input2 ! ( input as ItemConst ) ;
440450 if !args. is_empty ( ) {
441- return err ! ( input => "`#[php_const(<args>)]` args are no longer supported. Please use `#[php(<args>)]` instead." ) . to_compile_error ( ) . into ( ) ;
451+ return err ! ( input => "`#[php_const(<args>)]` args are no longer supported. Please use `#[php(<args>)]` instead." ) . to_compile_error ( ) ;
442452 }
443453
444- constant:: parser ( input)
445- . unwrap_or_else ( |e| e. to_compile_error ( ) )
446- . into ( )
454+ constant:: parser ( input) . unwrap_or_else ( |e| e. to_compile_error ( ) )
447455}
448456
449457// BEGIN DOCS FROM module.md
@@ -516,14 +524,17 @@ pub fn php_const(args: TokenStream, input: TokenStream) -> TokenStream {
516524// END DOCS FROM module.md
517525#[ proc_macro_attribute]
518526pub fn php_module ( args : TokenStream , input : TokenStream ) -> TokenStream {
519- let input = parse_macro_input ! ( input as ItemFn ) ;
527+ php_module_internal ( args. into ( ) , input. into ( ) ) . into ( )
528+ }
529+
530+ #[ allow( clippy:: needless_pass_by_value) ]
531+ fn php_module_internal ( args : TokenStream2 , input : TokenStream2 ) -> TokenStream2 {
532+ let input = parse_macro_input2 ! ( input as ItemFn ) ;
520533 if !args. is_empty ( ) {
521- return err ! ( input => "`#[php_module(<args>)]` args are no longer supported. Please use `#[php(<args>)]` instead." ) . to_compile_error ( ) . into ( ) ;
534+ return err ! ( input => "`#[php_module(<args>)]` args are no longer supported. Please use `#[php(<args>)]` instead." ) . to_compile_error ( ) ;
522535 }
523536
524- module:: parser ( input)
525- . unwrap_or_else ( |e| e. to_compile_error ( ) )
526- . into ( )
537+ module:: parser ( input) . unwrap_or_else ( |e| e. to_compile_error ( ) )
527538}
528539
529540// BEGIN DOCS FROM impl.md
@@ -713,14 +724,17 @@ pub fn php_module(args: TokenStream, input: TokenStream) -> TokenStream {
713724// END DOCS FROM impl.md
714725#[ proc_macro_attribute]
715726pub fn php_impl ( args : TokenStream , input : TokenStream ) -> TokenStream {
716- let input = parse_macro_input ! ( input as ItemImpl ) ;
727+ php_impl_internal ( args. into ( ) , input. into ( ) ) . into ( )
728+ }
729+
730+ #[ allow( clippy:: needless_pass_by_value) ]
731+ fn php_impl_internal ( args : TokenStream2 , input : TokenStream2 ) -> TokenStream2 {
732+ let input = parse_macro_input2 ! ( input as ItemImpl ) ;
717733 if !args. is_empty ( ) {
718- return err ! ( input => "`#[php_impl(<args>)]` args are no longer supported. Please use `#[php(<args>)]` instead." ) . to_compile_error ( ) . into ( ) ;
734+ return err ! ( input => "`#[php_impl(<args>)]` args are no longer supported. Please use `#[php(<args>)]` instead." ) . to_compile_error ( ) ;
719735 }
720736
721- impl_:: parser ( input)
722- . unwrap_or_else ( |e| e. to_compile_error ( ) )
723- . into ( )
737+ impl_:: parser ( input) . unwrap_or_else ( |e| e. to_compile_error ( ) )
724738}
725739
726740// BEGIN DOCS FROM extern.md
@@ -789,12 +803,15 @@ pub fn php_impl(args: TokenStream, input: TokenStream) -> TokenStream {
789803/// [`Zval`]: crate::types::Zval
790804// END DOCS FROM extern.md
791805#[ proc_macro_attribute]
792- pub fn php_extern ( _: TokenStream , input : TokenStream ) -> TokenStream {
793- let input = parse_macro_input ! ( input as ItemForeignMod ) ;
806+ pub fn php_extern ( args : TokenStream , input : TokenStream ) -> TokenStream {
807+ php_extern_internal ( args. into ( ) , input. into ( ) ) . into ( )
808+ }
809+
810+ #[ allow( clippy:: needless_pass_by_value) ]
811+ fn php_extern_internal ( _: TokenStream2 , input : TokenStream2 ) -> TokenStream2 {
812+ let input = parse_macro_input2 ! ( input as ItemForeignMod ) ;
794813
795- extern_:: parser ( input)
796- . unwrap_or_else ( |e| e. to_compile_error ( ) )
797- . into ( )
814+ extern_:: parser ( input) . unwrap_or_else ( |e| e. to_compile_error ( ) )
798815}
799816
800817// BEGIN DOCS FROM zval_convert.md
@@ -953,11 +970,13 @@ pub fn php_extern(_: TokenStream, input: TokenStream) -> TokenStream {
953970// END DOCS FROM zval_convert.md
954971#[ proc_macro_derive( ZvalConvert ) ]
955972pub fn zval_convert_derive ( input : TokenStream ) -> TokenStream {
956- let input = parse_macro_input ! ( input as DeriveInput ) ;
973+ zval_convert_derive_internal ( input. into ( ) ) . into ( )
974+ }
957975
958- zval:: parser ( input)
959- . unwrap_or_else ( |e| e. to_compile_error ( ) )
960- . into ( )
976+ fn zval_convert_derive_internal ( input : TokenStream2 ) -> TokenStream2 {
977+ let input = parse_macro_input2 ! ( input as DeriveInput ) ;
978+
979+ zval:: parser ( input) . unwrap_or_else ( |e| e. to_compile_error ( ) )
961980}
962981
963982/// Defines an `extern` function with the Zend fastcall convention based on
@@ -992,35 +1011,61 @@ pub fn zval_convert_derive(input: TokenStream) -> TokenStream {
9921011/// Rust and the `abi_vectorcall` feature enabled.
9931012#[ proc_macro]
9941013pub fn zend_fastcall ( input : TokenStream ) -> TokenStream {
995- let input = parse_macro_input ! ( input as ItemFn ) ;
1014+ zend_fastcall_internal ( input. into ( ) ) . into ( )
1015+ }
9961016
997- fastcall:: parser ( input) . into ( )
1017+ fn zend_fastcall_internal ( input : TokenStream2 ) -> TokenStream2 {
1018+ let input = parse_macro_input2 ! ( input as ItemFn ) ;
1019+
1020+ fastcall:: parser ( input)
9981021}
9991022
10001023/// Wraps a function to be used in the [`Module::function`] method.
10011024#[ proc_macro]
10021025pub fn wrap_function ( input : TokenStream ) -> TokenStream {
1003- let input = parse_macro_input ! ( input as syn:: Path ) ;
1026+ wrap_function_internal ( input. into ( ) ) . into ( )
1027+ }
1028+
1029+ fn wrap_function_internal ( input : TokenStream2 ) -> TokenStream2 {
1030+ let input = parse_macro_input2 ! ( input as syn:: Path ) ;
10041031
10051032 match function:: wrap ( & input) {
10061033 Ok ( parsed) => parsed,
10071034 Err ( e) => e. to_compile_error ( ) ,
10081035 }
1009- . into ( )
10101036}
10111037
10121038/// Wraps a constant to be used in the [`ModuleBuilder::constant`] method.
10131039#[ proc_macro]
10141040pub fn wrap_constant ( input : TokenStream ) -> TokenStream {
1015- let input = parse_macro_input ! ( input as syn:: Path ) ;
1041+ wrap_constant_internal ( input. into ( ) ) . into ( )
1042+ }
1043+
1044+ fn wrap_constant_internal ( input : TokenStream2 ) -> TokenStream2 {
1045+ let input = parse_macro_input2 ! ( input as syn:: Path ) ;
10161046
10171047 match constant:: wrap ( & input) {
10181048 Ok ( parsed) => parsed,
10191049 Err ( e) => e. to_compile_error ( ) ,
10201050 }
1021- . into ( )
10221051}
10231052
1053+ macro_rules! parse_macro_input2 {
1054+ ( $tokenstream: ident as $ty: ty) => {
1055+ match syn:: parse2:: <$ty>( $tokenstream) {
1056+ Ok ( data) => data,
1057+ Err ( err) => {
1058+ return proc_macro2:: TokenStream :: from( err. to_compile_error( ) ) ;
1059+ }
1060+ }
1061+ } ;
1062+ ( $tokenstream: ident) => {
1063+ $crate:: parse_macro_input!( $tokenstream as _)
1064+ } ;
1065+ }
1066+
1067+ pub ( crate ) use parse_macro_input2;
1068+
10241069macro_rules! err {
10251070 ( $span: expr => $( $msg: tt) * ) => {
10261071 :: syn:: Error :: new( :: syn:: spanned:: Spanned :: span( & $span) , format!( $( $msg) * ) )
@@ -1061,3 +1106,62 @@ pub(crate) mod prelude {
10611106 pub ( crate ) use crate :: { bail, err} ;
10621107 pub ( crate ) type Result < T > = std:: result:: Result < T , syn:: Error > ;
10631108}
1109+
1110+ #[ cfg( test) ]
1111+ mod tests {
1112+ use super :: * ;
1113+ use std:: path:: PathBuf ;
1114+
1115+ type AttributeFn =
1116+ fn ( proc_macro2:: TokenStream , proc_macro2:: TokenStream ) -> proc_macro2:: TokenStream ;
1117+ type FunctionLikeFn = fn ( proc_macro2:: TokenStream ) -> proc_macro2:: TokenStream ;
1118+
1119+ #[ test]
1120+ pub fn test_expand ( ) {
1121+ macrotest:: expand ( "tests/expand/*.rs" ) ;
1122+ for entry in glob:: glob ( "tests/expand/*.rs" ) . expect ( "Failed to read expand tests glob" ) {
1123+ let entry = entry. expect ( "Failed to read expand test file" ) ;
1124+ runtime_expand_attr ( & entry) ;
1125+ runtime_expand_func ( & entry) ;
1126+ runtime_expand_derive ( & entry) ;
1127+ }
1128+ }
1129+
1130+ fn runtime_expand_attr ( path : & PathBuf ) {
1131+ let file = std:: fs:: File :: open ( path) . expect ( "Failed to open expand test file" ) ;
1132+ runtime_macros:: emulate_attributelike_macro_expansion (
1133+ file,
1134+ & [
1135+ ( "php_class" , php_class_internal as AttributeFn ) ,
1136+ ( "php_const" , php_const_internal as AttributeFn ) ,
1137+ ( "php_extern" , php_extern_internal as AttributeFn ) ,
1138+ ( "php_function" , php_function_internal as AttributeFn ) ,
1139+ ( "php_impl" , php_impl_internal as AttributeFn ) ,
1140+ ( "php_module" , php_module_internal as AttributeFn ) ,
1141+ ] ,
1142+ )
1143+ . expect ( "Failed to expand attribute macros in test file" ) ;
1144+ }
1145+
1146+ fn runtime_expand_func ( path : & PathBuf ) {
1147+ let file = std:: fs:: File :: open ( path) . expect ( "Failed to open expand test file" ) ;
1148+ runtime_macros:: emulate_functionlike_macro_expansion (
1149+ file,
1150+ & [
1151+ ( "zend_fastcall" , zend_fastcall_internal as FunctionLikeFn ) ,
1152+ ( "wrap_function" , wrap_function_internal as FunctionLikeFn ) ,
1153+ ( "wrap_constant" , wrap_constant_internal as FunctionLikeFn ) ,
1154+ ] ,
1155+ )
1156+ . expect ( "Failed to expand function-like macros in test file" ) ;
1157+ }
1158+
1159+ fn runtime_expand_derive ( path : & PathBuf ) {
1160+ let file = std:: fs:: File :: open ( path) . expect ( "Failed to open expand test file" ) ;
1161+ runtime_macros:: emulate_derive_macro_expansion (
1162+ file,
1163+ & [ ( "ZvalConvert" , zval_convert_derive_internal) ] ,
1164+ )
1165+ . expect ( "Failed to expand derive macros in test file" ) ;
1166+ }
1167+ }
0 commit comments