1#![warn(missing_docs)]
3
4extern crate proc_macro;
5
6mod quote_m2;
7mod roles;
8mod syntax;
9mod tokens;
10
11use proc_macro::TokenStream;
12use std::collections::BTreeSet;
13
14use proc_macro2::{TokenStream as TokenStream2, TokenTree};
15use quote::{ToTokens, format_ident, quote};
16use syn::{Data, DeriveInput, Error, Fields, Member, Result, Type, parse_macro_input, parse_quote};
17
18fn base_crate() -> TokenStream2 {
19 quote!(::m2_syn)
20}
21
22#[proc_macro]
24pub fn syntax(input: TokenStream) -> TokenStream {
25 let expansion = match syntax::generate(input.into()) {
26 Ok(expansion) => expansion,
27 Err(error) => return error.into_compile_error().into(),
28 };
29 expansion.into()
30}
31
32#[proc_macro]
38pub fn token(input: TokenStream) -> TokenStream {
39 let base = base_crate();
40 match tokens::token_type_name(&input.into()) {
41 Ok(name) => quote!(#base::#name).into(),
42 Err(error) => error.into_compile_error().into(),
43 }
44}
45#[proc_macro]
51pub fn quote_m2(input: TokenStream) -> TokenStream {
52 quote_m2::expand(input)
53}
54
55#[proc_macro]
57pub fn parse_quote_m2(input: TokenStream) -> TokenStream {
58 let input = TokenStream2::from(input);
59 let base = base_crate();
60 quote!({
61 let tokens = #base::quote_m2!(#input);
62 #base::parse2(tokens).expect("parse_quote_m2! input should parse")
63 })
64 .into()
65}
66
67#[proc_macro_derive(Spanned)]
69pub fn derive_spanned(input: TokenStream) -> TokenStream {
70 let input = parse_macro_input!(input as DeriveInput);
71 match expand_spanned(&input) {
72 Ok(expansion) => expansion.into(),
73 Err(error) => error.to_compile_error().into(),
74 }
75}
76
77fn expand_spanned_members(
78 members: impl IntoIterator<Item = (Member, TokenStream2)>,
79) -> TokenStream2 {
80 let members = members.into_iter().collect::<Vec<_>>();
81 let base = base_crate();
82 let span = quote! {#base::Spanned::span};
83 if let Some((_, value)) = members
84 .iter()
85 .find(|(member, _)| matches!(member, Member::Named(ident) if ident == "span"))
86 {
87 quote!(#span(#value))
88 } else {
89 let values = members.iter().map(|(_, value)| value);
90 quote! {
91 #base::Span::join_all(
92 [#(#base::Spanned::span(#values)),*]
93 )
94 }
95 }
96}
97
98fn expand_spanned(input: &DeriveInput) -> Result<TokenStream2> {
99 let name = &input.ident;
100 let base = base_crate();
101 let span_ty = quote! {#base::Span};
102 let mut generics = input.generics.clone();
103 let type_parameters = input
104 .generics
105 .type_params()
106 .map(|parameter| parameter.ident.to_string())
107 .collect::<BTreeSet<_>>();
108 for ty in spanned_field_types(input)
109 .into_iter()
110 .filter(|ty| type_mentions_parameter(ty, &type_parameters))
111 {
112 generics
113 .make_where_clause()
114 .predicates
115 .push(parse_quote!(#ty: #base::Spanned));
116 }
117 let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
118 let body = match &input.data {
119 Data::Struct(data) => {
120 let members = data.fields.members().map(|member| {
121 let value = quote!(&self.#member);
122 (member, value)
123 });
124 expand_spanned_members(members)
125 }
126 Data::Enum(data) => {
127 let arms = data
128 .variants
129 .iter()
130 .map(|variant| {
131 let variant_name = &variant.ident;
132 let members = variant.fields.members().collect::<Vec<_>>();
133 let bindings = members
134 .iter()
135 .enumerate()
136 .map(|(index, _)| format_ident!("__m2_syn_field_{index}"))
137 .collect::<Vec<_>>();
138 let values = bindings.iter().map(|binding| quote!(#binding));
139 let span = expand_spanned_members(members.iter().cloned().zip(values));
140
141 match &variant.fields {
142 Fields::Named(_) => {
143 let fields = members
144 .iter()
145 .zip(&bindings)
146 .map(|(member, binding)| quote!(#member: #binding));
147 quote! {
148 Self::#variant_name { #(#fields),* } => #span
149 }
150 }
151 Fields::Unnamed(_) => quote! {
152 Self::#variant_name(#(#bindings),*) => #span
153 },
154 Fields::Unit => quote! {
155 Self::#variant_name => #span
156 },
157 }
158 })
159 .collect::<Vec<_>>();
160 let empty_fallback = data
161 .variants
162 .is_empty()
163 .then(|| quote!(_ => #span_ty::detached()));
164 quote! {
165 match self {
166 #(#arms,)*
167 #empty_fallback
168 }
169 }
170 }
171 Data::Union(_) => {
172 return Err(Error::new_spanned(
173 name,
174 "Spanned cannot be derived for unions",
175 ));
176 }
177 };
178
179 Ok(quote! {
180 impl #impl_generics
181 #base::Spanned for #name #type_generics #where_clause
182 {
183 fn span(&self) -> #span_ty {
184 #body
185 }
186 }
187 })
188}
189
190fn type_mentions_parameter(ty: &impl ToTokens, parameters: &BTreeSet<String>) -> bool {
191 fn stream_mentions_parameter(stream: TokenStream2, parameters: &BTreeSet<String>) -> bool {
192 stream.into_iter().any(|token| match token {
193 TokenTree::Ident(ident) => parameters.contains(&ident.to_string()),
194 TokenTree::Group(group) => stream_mentions_parameter(group.stream(), parameters),
195 _ => false,
196 })
197 }
198 stream_mentions_parameter(ty.to_token_stream(), parameters)
199}
200
201fn spanned_field_types(input: &DeriveInput) -> Vec<&Type> {
202 fn selected(fields: &Fields) -> Vec<&Type> {
203 fields
204 .iter()
205 .find(|field| field.ident.as_ref().is_some_and(|ident| ident == "span"))
206 .map_or_else(
207 || fields.iter().map(|field| &field.ty).collect(),
208 |field| vec![&field.ty],
209 )
210 }
211
212 match &input.data {
213 Data::Struct(data) => selected(&data.fields),
214 Data::Enum(data) => data
215 .variants
216 .iter()
217 .flat_map(|variant| selected(&variant.fields))
218 .collect(),
219 Data::Union(_) => Vec::new(),
220 }
221}