1#![deny(clippy::all)]
2#![recursion_limit = "1024"]
3
4extern crate proc_macro;
5
6use quote::quote;
7use swc_macros_common::prelude::*;
8use syn::{visit_mut::VisitMut, *};
9
10mod ast_node_macro;
11mod enum_deserialize;
12mod spanned;
13
14#[proc_macro_derive(Spanned, attributes(span))]
17pub fn derive_spanned(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
18 let input = parse::<DeriveInput>(input).expect("failed to parse input as DeriveInput");
19
20 let item = self::spanned::derive(input);
21
22 print("derive(Spanned)", item.into_token_stream())
23}
24
25#[proc_macro_derive(DeserializeEnum, attributes(tag))]
27pub fn derive_deserialize_enum(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
28 let input = parse::<DeriveInput>(input).expect("failed to parse input as DeriveInput");
29
30 let item = enum_deserialize::expand(input);
31
32 print("derive(DeserializeEnum)", item.into_token_stream())
33}
34
35#[proc_macro_attribute]
76pub fn ast_serde(
77 args: proc_macro::TokenStream,
78 input: proc_macro::TokenStream,
79) -> proc_macro::TokenStream {
80 let input: DeriveInput = parse(input).expect("failed to parse input as a DeriveInput");
81
82 let mut item = TokenStream::new();
84 match input.data {
85 Data::Enum(..) => {
86 if !args.is_empty() {
87 panic!("#[ast_serde] on enum does not accept any argument")
88 }
89
90 item.extend(quote!(
91 #[derive(::serde::Serialize, ::swc_common::DeserializeEnum)]
92 #[serde(untagged)]
93 #input
94 ));
95 }
96 _ => {
97 let args: Option<ast_node_macro::Args> = if args.is_empty() {
98 None
99 } else {
100 Some(parse(args).expect("failed to parse args of #[ast_serde]"))
101 };
102
103 let serde_tag = match input.data {
104 Data::Struct(DataStruct {
105 fields: Fields::Named(..),
106 ..
107 }) => {
108 if args.is_some() {
109 Some(quote!(#[serde(tag = "type")]))
110 } else {
111 None
112 }
113 }
114 _ => None,
115 };
116
117 let serde_rename = args.as_ref().map(|args| {
118 let name = &args.ty;
119 quote!(#[serde(rename = #name)])
120 });
121
122 item.extend(quote!(
123 #[derive(::serde::Serialize, ::serde::Deserialize)]
124 #serde_tag
125 #[serde(rename_all = "camelCase")]
126 #serde_rename
127 #input
128 ));
129 }
130 };
131
132 print("ast_serde", item)
133}
134
135struct AddAttr;
136
137impl VisitMut for AddAttr {
138 fn visit_field_mut(&mut self, f: &mut Field) {
139 f.attrs
140 .push(parse_quote!(#[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))]));
141 }
142}
143
144#[proc_macro_attribute]
149pub fn ast_node(
150 args: proc_macro::TokenStream,
151 input: proc_macro::TokenStream,
152) -> proc_macro::TokenStream {
153 let mut input: DeriveInput = parse(input).expect("failed to parse input as a DeriveInput");
154
155 AddAttr.visit_data_mut(&mut input.data);
156
157 let mut item = TokenStream::new();
159 match input.data {
160 Data::Enum(..) => {
161 use syn::parse::Parser;
162
163 let attrs = <syn::punctuated::Punctuated<syn::Ident, syn::Token![,]>>::parse_terminated
164 .parse(args)
165 .expect("failed to parse #[ast_node]");
166
167 let mut has_no_clone = false;
168 let mut has_no_unknown = false;
169 for attr in &attrs {
170 if attr == "no_clone" {
171 has_no_clone = true;
172 } else if attr == "no_unknown" {
173 has_no_unknown = true;
174 } else {
175 panic!("unknown attribute: {attr:?}")
176 }
177 }
178
179 let clone = if !has_no_clone {
180 Some(quote!(#[derive(Clone)]))
181 } else {
182 None
183 };
184 let non_exhaustive = if !has_no_unknown {
185 Some(quote!(#[cfg_attr(swc_ast_unknown, non_exhaustive)]))
186 } else {
187 None
188 };
189
190 item.extend(quote!(
191 #[allow(clippy::derive_partial_eq_without_eq)]
192 #[cfg_attr(
193 feature = "serde-impl",
194 derive(
195 ::serde::Serialize,
196 )
197 )]
198 #[derive(
199 ::swc_common::FromVariant,
200 ::swc_common::Spanned,
201 Debug,
202 PartialEq,
203 ::swc_common::DeserializeEnum,
204 )]
205 #clone
206 #non_exhaustive
207 #[cfg_attr(
208 feature = "rkyv-impl",
209 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
210 )]
211 #[cfg_attr(
212 feature = "rkyv-impl",
213 rkyv(deserialize_bounds(__D::Error: rkyv::rancor::Source))
214 )]
215 #[cfg_attr(feature = "rkyv-impl", repr(u32))]
216 #[cfg_attr(
217 feature = "rkyv-impl",
218 rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator,
219 __S::Error: rkyv::rancor::Source))
220 )]
221 #[cfg_attr(
222 feature = "rkyv-impl",
223 rkyv(bytecheck(bounds(
224 __C: rkyv::validation::ArchiveContext,
225 __C::Error: rkyv::rancor::Source
226 )))
227 )]
228 #[cfg_attr(
229 feature = "serde-impl",
230 serde(untagged)
231 )]
232 #input
233 ));
234 }
235 _ => {
236 let args: Option<ast_node_macro::Args> = if args.is_empty() {
237 None
238 } else {
239 Some(parse(args).expect("failed to parse args of #[ast_node]"))
240 };
241
242 let serde_tag = match input.data {
243 Data::Struct(DataStruct {
244 fields: Fields::Named(..),
245 ..
246 }) => {
247 if args.is_some() {
248 Some(quote!(#[cfg_attr(
249 feature = "serde-impl",
250 serde(tag = "type")
251 )]))
252 } else {
253 None
254 }
255 }
256 _ => None,
257 };
258
259 let serde_rename = args.as_ref().map(|args| {
260 let name = &args.ty;
261
262 quote!(#[cfg_attr(
263 feature = "serde-impl",
264 serde(rename = #name)
265 )])
266 });
267
268 let ast_node_impl = args
269 .as_ref()
270 .map(|args| ast_node_macro::expand_struct(args.clone(), input.clone()));
271
272 item.extend(quote!(
273 #[allow(clippy::derive_partial_eq_without_eq)]
274 #[derive(::swc_common::Spanned, Clone, Debug, PartialEq)]
275 #[cfg_attr(
276 feature = "serde-impl",
277 derive(::serde::Serialize, ::serde::Deserialize)
278 )]
279 #[cfg_attr(
280 feature = "rkyv-impl",
281 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
282 )]
283 #[cfg_attr(
284 feature = "rkyv-impl",
285 rkyv(deserialize_bounds(__D::Error: rkyv::rancor::Source))
286 )]
287 #[cfg_attr(
288 feature = "rkyv-impl",
289 rkyv(bytecheck(bounds(
290 __C: rkyv::validation::ArchiveContext,
291 __C::Error: rkyv::rancor::Source
292 )))
293 )]
294 #[cfg_attr(feature = "rkyv-impl", repr(C))]
295 #[cfg_attr(
296 feature = "rkyv-impl",
297 rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator,
298 __S::Error: rkyv::rancor::Source))
299 )]
300 #serde_tag
301 #[cfg_attr(
302 feature = "serde-impl",
303 serde(rename_all = "camelCase")
304 )]
305 #serde_rename
306 #input
307 ));
308
309 if let Some(items) = ast_node_impl {
310 for item_impl in items {
311 item.extend(item_impl.into_token_stream());
312 }
313 }
314 }
315 };
316
317 print("ast_node", item)
318}