@@ -10,7 +10,7 @@ use proc_macro2::{Ident, Span, TokenStream, TokenTree};
10
10
use quote:: ToTokens ;
11
11
use syn:: parse:: { Parse , ParseStream , Result as SynResult } ;
12
12
use syn:: spanned:: Spanned ;
13
- use syn:: { Lit , MacroDelimiter } ;
13
+ use syn:: { ItemFn , Lit , MacroDelimiter , ReturnType } ;
14
14
15
15
thread_local ! ( static ATTRS : AttributeParseState = Default :: default ( ) ) ;
16
16
@@ -81,6 +81,7 @@ macro_rules! attrgen {
81
81
( typescript_custom_section, TypescriptCustomSection ( Span ) ) ,
82
82
( skip_typescript, SkipTypescript ( Span ) ) ,
83
83
( skip_jsdoc, SkipJsDoc ( Span ) ) ,
84
+ ( main, Main ( Span ) ) ,
84
85
( start, Start ( Span ) ) ,
85
86
( skip, Skip ( Span ) ) ,
86
87
( typescript_type, TypeScriptType ( Span , String , Span ) ) ,
@@ -929,6 +930,13 @@ impl<'a> MacroParse<(Option<BindgenAttrs>, &'a mut TokenStream)> for syn::Item {
929
930
) -> Result < ( ) , Diagnostic > {
930
931
match self {
931
932
syn:: Item :: Fn ( mut f) => {
933
+ let opts = opts. unwrap_or_default ( ) ;
934
+
935
+ if opts. main ( ) . is_some ( ) {
936
+ opts. check_used ( ) ;
937
+ return main ( f, tokens) ;
938
+ }
939
+
932
940
let no_mangle = f
933
941
. attrs
934
942
. iter ( )
@@ -946,7 +954,6 @@ impl<'a> MacroParse<(Option<BindgenAttrs>, &'a mut TokenStream)> for syn::Item {
946
954
// `dead_code` warning. So, add `#[allow(dead_code)]` before it to avoid that.
947
955
tokens. extend ( quote:: quote! { #[ allow( dead_code) ] } ) ;
948
956
f. to_tokens ( tokens) ;
949
- let opts = opts. unwrap_or_default ( ) ;
950
957
if opts. start ( ) . is_some ( ) {
951
958
if f. sig . generics . params . len ( ) > 0 {
952
959
bail_span ! ( & f. sig. generics, "the start function cannot have generics" , ) ;
@@ -1693,6 +1700,59 @@ pub fn link_to(opts: BindgenAttrs) -> Result<ast::LinkToModule, Diagnostic> {
1693
1700
Ok ( ast:: LinkToModule ( program) )
1694
1701
}
1695
1702
1703
+ fn main ( mut f : ItemFn , tokens : & mut TokenStream ) -> Result < ( ) , Diagnostic > {
1704
+ if f. sig . ident != "main" {
1705
+ bail_span ! ( & f. sig. ident, "the main function has to be called main" ) ;
1706
+ }
1707
+ if let Some ( constness) = f. sig . constness {
1708
+ bail_span ! ( & constness, "the main function cannot be const" ) ;
1709
+ }
1710
+ if !f. sig . generics . params . is_empty ( ) {
1711
+ bail_span ! ( & f. sig. generics, "the main function cannot have generics" ) ;
1712
+ }
1713
+ if !f. sig . inputs . is_empty ( ) {
1714
+ bail_span ! ( & f. sig. inputs, "the main function cannot have arguments" ) ;
1715
+ }
1716
+
1717
+ let r#return = f. sig . output ;
1718
+ f. sig . output = ReturnType :: Default ;
1719
+ let body = f. block ;
1720
+
1721
+ if f. sig . asyncness . take ( ) . is_some ( ) {
1722
+ f. block = Box :: new (
1723
+ syn:: parse2 ( quote:: quote! {
1724
+ {
1725
+ async fn __wasm_bindgen_generated_main( ) #r#return #body
1726
+ wasm_bindgen_futures:: spawn_local(
1727
+ async move {
1728
+ use wasm_bindgen:: __rt:: Main ;
1729
+ let __ret = __wasm_bindgen_generated_main( ) ;
1730
+ ( & mut & mut & mut wasm_bindgen:: __rt:: MainWrapper ( Some ( __ret. await ) ) ) . __wasm_bindgen_main( )
1731
+ } ,
1732
+ )
1733
+ }
1734
+ } )
1735
+ . unwrap ( ) ,
1736
+ ) ;
1737
+ } else {
1738
+ f. block = Box :: new (
1739
+ syn:: parse2 ( quote:: quote! {
1740
+ {
1741
+ fn __wasm_bindgen_generated_main( ) #r#return #body
1742
+ use wasm_bindgen:: __rt:: Main ;
1743
+ let __ret = __wasm_bindgen_generated_main( ) ;
1744
+ ( & mut & mut & mut wasm_bindgen:: __rt:: MainWrapper ( Some ( __ret) ) ) . __wasm_bindgen_main( )
1745
+ }
1746
+ } )
1747
+ . unwrap ( ) ,
1748
+ ) ;
1749
+ }
1750
+
1751
+ f. to_tokens ( tokens) ;
1752
+
1753
+ Ok ( ( ) )
1754
+ }
1755
+
1696
1756
#[ cfg( test) ]
1697
1757
mod tests {
1698
1758
#[ test]
0 commit comments