wasm_bindgen_macro_support/
lib.rs
1#![doc(html_root_url = "https://docs.rs/wasm-bindgen-macro-support/0.2")]
5
6extern crate proc_macro2;
7extern crate quote;
8#[macro_use]
9extern crate syn;
10#[macro_use]
11extern crate wasm_bindgen_backend as backend;
12extern crate wasm_bindgen_shared as shared;
13
14pub use crate::parser::BindgenAttrs;
15use crate::parser::{ConvertToAst, MacroParse};
16use backend::{Diagnostic, TryToTokens};
17use proc_macro2::TokenStream;
18use quote::quote;
19use quote::ToTokens;
20use quote::TokenStreamExt;
21use syn::parse::{Parse, ParseStream, Result as SynResult};
22
23mod parser;
24
25pub fn expand(attr: TokenStream, input: TokenStream) -> Result<TokenStream, Diagnostic> {
27 parser::reset_attrs_used();
28 let item = syn::parse2::<syn::Item>(input)?;
31 if let syn::Item::Struct(s) = item {
32 let opts: BindgenAttrs = syn::parse2(attr.clone())?;
33 let wasm_bindgen = opts
34 .wasm_bindgen()
35 .cloned()
36 .unwrap_or_else(|| syn::parse_quote! { wasm_bindgen });
37
38 let item = quote! {
39 #[derive(#wasm_bindgen::__rt::BindgenedStruct)]
40 #[wasm_bindgen(#attr)]
41 #s
42 };
43 return Ok(item);
44 }
45
46 let opts = syn::parse2(attr)?;
47 let mut tokens = proc_macro2::TokenStream::new();
48 let mut program = backend::ast::Program::default();
49 item.macro_parse(&mut program, (Some(opts), &mut tokens))?;
50 program.try_to_tokens(&mut tokens)?;
51
52 parser::check_unused_attrs(&mut tokens);
56
57 Ok(tokens)
58}
59
60pub fn expand_link_to(input: TokenStream) -> Result<TokenStream, Diagnostic> {
62 parser::reset_attrs_used();
63 let opts = syn::parse2(input)?;
64
65 let mut tokens = proc_macro2::TokenStream::new();
66 let link = parser::link_to(opts)?;
67 link.try_to_tokens(&mut tokens)?;
68
69 Ok(tokens)
70}
71
72pub fn expand_class_marker(
74 attr: TokenStream,
75 input: TokenStream,
76) -> Result<TokenStream, Diagnostic> {
77 parser::reset_attrs_used();
78 let mut item = syn::parse2::<syn::ImplItemFn>(input)?;
79 let opts: ClassMarker = syn::parse2(attr)?;
80
81 let mut program = backend::ast::Program::default();
82 item.macro_parse(&mut program, &opts)?;
83
84 let mut tokens = proc_macro2::TokenStream::new();
96 tokens.append_all(
97 item.attrs
98 .iter()
99 .filter(|attr| matches!(attr.style, syn::AttrStyle::Outer)),
100 );
101 item.vis.to_tokens(&mut tokens);
102 item.sig.to_tokens(&mut tokens);
103 let mut err = None;
104 item.block.brace_token.surround(&mut tokens, |tokens| {
105 if let Err(e) = program.try_to_tokens(tokens) {
106 err = Some(e);
107 }
108 parser::check_unused_attrs(tokens); tokens.append_all(
110 item.attrs
111 .iter()
112 .filter(|attr| matches!(attr.style, syn::AttrStyle::Inner(_))),
113 );
114 tokens.append_all(&item.block.stmts);
115 });
116
117 if let Some(err) = err {
118 return Err(err);
119 }
120
121 Ok(tokens)
122}
123
124struct ClassMarker {
125 class: syn::Ident,
126 js_class: String,
127 wasm_bindgen: syn::Path,
128 wasm_bindgen_futures: syn::Path,
129}
130
131impl Parse for ClassMarker {
132 fn parse(input: ParseStream) -> SynResult<Self> {
133 let class = input.parse::<syn::Ident>()?;
134 input.parse::<Token![=]>()?;
135 let mut js_class = input.parse::<syn::LitStr>()?.value();
136 js_class = js_class
137 .strip_prefix("r#")
138 .map(String::from)
139 .unwrap_or(js_class);
140
141 let mut wasm_bindgen = None;
142 let mut wasm_bindgen_futures = None;
143
144 loop {
145 if input.parse::<Option<Token![,]>>()?.is_some() {
146 let ident = input.parse::<syn::Ident>()?;
147
148 if ident == "wasm_bindgen" {
149 if wasm_bindgen.is_some() {
150 return Err(syn::Error::new(
151 ident.span(),
152 "found duplicate `wasm_bindgen`",
153 ));
154 }
155
156 input.parse::<Token![=]>()?;
157 wasm_bindgen = Some(input.parse::<syn::Path>()?);
158 } else if ident == "wasm_bindgen_futures" {
159 if wasm_bindgen_futures.is_some() {
160 return Err(syn::Error::new(
161 ident.span(),
162 "found duplicate `wasm_bindgen_futures`",
163 ));
164 }
165
166 input.parse::<Token![=]>()?;
167 wasm_bindgen_futures = Some(input.parse::<syn::Path>()?);
168 } else {
169 return Err(syn::Error::new(
170 ident.span(),
171 "expected `wasm_bindgen` or `wasm_bindgen_futures`",
172 ));
173 }
174 } else {
175 break;
176 }
177 }
178
179 Ok(ClassMarker {
180 class,
181 js_class,
182 wasm_bindgen: wasm_bindgen.unwrap_or_else(|| syn::parse_quote! { wasm_bindgen }),
183 wasm_bindgen_futures: wasm_bindgen_futures
184 .unwrap_or_else(|| syn::parse_quote! { wasm_bindgen_futures }),
185 })
186 }
187}
188
189pub fn expand_struct_marker(item: TokenStream) -> Result<TokenStream, Diagnostic> {
190 parser::reset_attrs_used();
191
192 let mut s: syn::ItemStruct = syn::parse2(item)?;
193
194 let mut program = backend::ast::Program::default();
195 program.structs.push((&mut s).convert(&program)?);
196
197 let mut tokens = proc_macro2::TokenStream::new();
198 program.try_to_tokens(&mut tokens)?;
199
200 parser::check_unused_attrs(&mut tokens);
201
202 Ok(tokens)
203}