1use proc_macro::TokenStream;
2use quote::{quote, ToTokens};
3use syn::{
4 parse_macro_input, spanned::Spanned, Attribute, Data, DataEnum, DataStruct, DeriveInput, Error,
5 Field, Fields, Generics, Ident, Index, Meta, MetaList,
6};
7
8#[proc_macro_derive(Parsable, attributes(whitespace, value))]
9pub fn parsable_fn(item: TokenStream) -> TokenStream {
10 let item = parse_macro_input!(item as DeriveInput);
11 match &item.data {
12 Data::Struct(value) => derive_struct(&item.ident, value, &item.generics),
13 Data::Enum(value) => derive_enum(&item.ident, value, &item.generics),
14 Data::Union(_) => TokenStream::from(
15 Error::new(item.span(), "Can not derive Parse from a union type.").to_compile_error(),
16 ),
17 }
18}
19
20fn derive_struct(ident: &Ident, value: &DataStruct, generics: &Generics) -> TokenStream {
21 let fields = value.fields.iter().collect::<Vec<_>>();
22
23 let definitions = derive_fields(fields.clone());
24 let parse_result = match &value.fields {
25 Fields::Named(fields) => {
26 let fields = fields.named.iter().map(|field| &field.ident);
27 let inner_fields = fields
28 .clone()
29 .enumerate()
30 .map(|(i, field)| inner_ident(field, i));
31 quote! {
32 ::std::result::Result::Ok(Self {
33 #(#fields: #inner_fields),*
34 })
35 }
36 }
37 Fields::Unnamed(fields) => {
38 let inner_fields = fields
39 .unnamed
40 .iter()
41 .enumerate()
42 .map(|(i, _)| inner_ident(&None, i));
43 quote! {
44 ::std::result::Result::Ok(Self(#(#inner_fields),*))
45 }
46 }
47 Fields::Unit => {
48 return TokenStream::from(
49 Error::new(
50 ident.span(),
51 "Can not derive trait Parse for a unit struct.",
52 )
53 .to_compile_error(),
54 )
55 }
56 };
57
58 let first_ident = get_ident(&fields.first().unwrap().ident, 0);
59 let last_ident = get_ident(&fields.last().unwrap().ident, fields.len() - 1);
60 let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
61 quote! {
62 impl #impl_generics Parse for #ident #type_generics #where_clause {
63 fn parse(value: &mut parsing::charstream::CharStream) -> ::std::result::Result<Self, parsing::ParseError> {
64 #(#definitions)*
65 #parse_result
66 }
67
68 fn span(&self) -> parsing::charstream::Span {
69 parsing::charstream::Span::new(self.#first_ident.span().start, self.#last_ident.span().end)
70 }
71 }
72 }.into()
73}
74
75fn derive_enum(ident: &Ident, value: &DataEnum, generics: &Generics) -> TokenStream {
76 let variants = value.variants.iter().map(|variant| {
77 let ident = Ident::new(
78 &format!("__parse_{}", variant.ident.to_string().to_lowercase()),
79 variant.span(),
80 );
81 (&variant.ident, ident, &variant.fields, &variant.attrs)
82 });
83 let variant_functions = match variants
84 .clone()
85 .map(|(field_ident, func_ident, fields, attrs)| {
86 derive_variant_function(field_ident, func_ident, fields, attrs)
87 })
88 .collect::<Result<Vec<_>, _>>()
89 {
90 Ok(value) => value,
91 Err(error) => return error,
92 };
93
94 let parse_variants = variants.clone().map(|(_, func_ident, _, _)| {
95 quote! {
96 let mut __value = value.clone();
97 match Self::#func_ident(&mut __value) {
98 ::std::result::Result::Ok(inner) => {
99 let __position = __value.pos();
100 if __position > position {
101 position = __value.pos();
102 }
103 options.push(inner);
104 }
105 ::std::result::Result::Err(err) => match error {
106 Some(__err) if err.pos() > __err.pos() =>
107 error = ::std::option::Option::Some(err),
108 Some(_) => {}
109 None => error = ::std::option::Option::Some(err),
110 }
111 }
112 }
113 });
114
115 let span_variants = variants.map(|(variant_ident, _, fields, _)| {
116 let fields = fields.iter().collect::<Vec<_>>();
117 let definitions = fields
118 .iter()
119 .enumerate()
120 .map(|(i, field)| match &field.ident {
121 Some(ident) => {
122 let inner = inner_ident(&field.ident, i);
123 quote! {
124 #ident: #inner
125 }
126 }
127 None => {
128 let ident = inner_ident(&field.ident, i);
129 quote! {#ident}
130 }
131 });
132
133 if fields.is_empty() {
134 quote! {
135 Self::#variant_ident => parsing::charstream::Span::default(),
136 }
137 } else {
138 let first = inner_ident(&fields.first().unwrap().ident, 0);
139 let last = inner_ident(&fields.last().unwrap().ident, fields.len() - 1);
140
141 quote! {
142 Self::#variant_ident(#(#definitions),*) =>
143 parsing::charstream::Span::new(#first.span().start, #last.span().end),
144 }
145 }
146 });
147
148 let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
149
150 quote! {
151 impl #impl_generics #ident #type_generics #where_clause {
152 #(#variant_functions)*
153 }
154
155 impl #impl_generics Parse for #ident #type_generics #where_clause {
156 fn parse(value: &mut parsing::charstream::CharStream) -> ::std::result::Result<Self, parsing::ParseError> {
157 let mut options = Vec::new();
158 let mut error: Option<parsing::ParseError> = None;
159 let mut position = value.pos();
160 #(#parse_variants)*
161 options.sort_by(|a, b| b.span().partial_cmp(&a.span()).unwrap());
162 match options.first() {
163 Some(option) => {
164 value.goto(position.clone())?;
165 Ok(option.clone())
166 }
167 None => Err(error.unwrap()),
168 }
169 }
170
171 fn span(&self) -> parsing::charstream::Span {
172 match self {
173 #(#span_variants)*
174 }
175 }
176 }
177 }.into()
178}
179
180fn derive_variant_function(
181 field_ident: &Ident,
182 func_ident: Ident,
183 fields: &Fields,
184 _attrs: &[Attribute],
185) -> Result<quote::__private::TokenStream, TokenStream> {
186 let definitions = derive_fields(fields.iter().collect());
187 let parse_result = match fields {
188 Fields::Named(fields) => {
189 let fields = fields.named.iter().map(|field| &field.ident);
190 let inner_fields = fields
191 .clone()
192 .enumerate()
193 .map(|(i, field)| inner_ident(field, i));
194 quote! {
195 ::std::result::Result::Ok(Self::#field_ident {
196 #(#fields: #inner_fields),*
197 })
198 }
199 }
200 Fields::Unnamed(fields) => {
201 let inner_fields = fields
202 .unnamed
203 .iter()
204 .enumerate()
205 .map(|(i, _)| inner_ident(&None, i));
206 quote! {
207 ::std::result::Result::Ok(Self::#field_ident(#(#inner_fields),*))
208 }
209 }
210 Fields::Unit => quote! {
211 ::std::result::Result::Ok(Self::#field_ident)
212 }
213 };
214 Ok(quote! {
215 fn #func_ident(value: &mut parsing::charstream::CharStream) -> ::std::result::Result<Self, parsing::ParseError> {
216 #(#definitions)*
217 #parse_result
218 }
219 })
220}
221
222fn derive_fields(fields: Vec<&Field>) -> Vec<quote::__private::TokenStream> {
223 let fields = fields
224 .iter()
225 .enumerate()
226 .map(|(i, field)| (inner_ident(&field.ident, i), &field.ty, &field.attrs));
227 fields.map(|(ident, ty, attrs)| {
228 let whitespace_attr = get_attr(attrs, "whitespace");
229 let value_attr = get_attr(attrs, "value");
230
231 let value = match whitespace_attr {
232 Some(attr) => {
233 let whitespace = attr.nested;
234 quote! {
235 {
236 let mut __whitespace_value = value.clone();
237 __whitespace_value.set_whitespace(parsing::charstream::WhitespaceType::#whitespace);
238
239 let inner = <#ty>::parse(&mut __whitespace_value);
240 value.goto(__whitespace_value.pos())?;
241 inner
242 }
243 }
244 }
245 None => quote! {
246 <#ty>::parse(value)
247 }
248 };
249 let value = match value_attr {
250 Some(attr) => {
251 let mut values = attr.nested.iter().map(|meta| quote! {
252 ::std::result::Result::Ok(inner) if inner == #meta => inner
253 }).collect::<Vec<_>>();
254
255 let expected = attr.nested.iter().map(|meta| quote! {
256 #meta
257 }).collect::<Vec<_>>();
258 values.push(quote! {
259 ::std::result::Result::Ok(inner) => return ::std::result::Result::Err(parsing::ParseError::new(&format!("Value was not one of the expected values. expected one of: {}", stringify!([#(#expected),*])), value.pos()))
260 });
261 values.push(quote! {
262 ::std::result::Result::Err(error) => return ::std::result::Result::Err(error)
263 });
264 quote! {
265 match #value {
266 #(#values),*
267 }
268 }
269 }
270 None => quote! {
271 #value?
272 }
273 };
274 quote! {
275 let #ident = #value;
276 }
277 }).collect::<Vec<_>>()
278}
279
280fn get_attr(attrs: &[Attribute], value: &str) -> Option<MetaList> {
281 attrs.iter().find_map(|attr| match attr.path.get_ident() {
282 Some(ident) if ident == value => match attr.parse_meta() {
283 Ok(Meta::List(list)) => Some(list),
284 _ => None,
285 },
286 _ => None,
287 })
288}
289
290fn inner_ident(ident: &Option<Ident>, index: usize) -> Ident {
291 let ident = get_ident(ident, index);
292 Ident::new(&format!("__inner_{}", ident), ident.span())
293}
294
295fn get_ident(ident: &Option<Ident>, index: usize) -> quote::__private::TokenStream {
296 match ident {
297 Some(ident) => <Ident as ToTokens>::to_token_stream(ident),
298 None => <Index as ToTokens>::to_token_stream(&Index::from(index)),
299 }
300}