1use crate::{syn_utils::*, to_tokens_attribute::*};
2use proc_macro2::{Span, TokenStream};
3use quote::{format_ident, quote, quote_spanned};
4use std::unreachable;
5use syn::{
6 parenthesized,
7 parse::{Parse, ParseStream},
8 parse2, parse_quote,
9 punctuated::Punctuated,
10 spanned::Spanned,
11 Data, DataEnum, DataStruct, DeriveInput, Fields, Ident, Result, Token,
12};
13
14pub fn derive_parse(input: DeriveInput) -> Result<TokenStream> {
15 let mut dump = false;
16 for attr in &input.attrs {
17 if attr.path.is_ident("parse") {
18 let attr: ParseAttribute = parse2(attr.tokens.clone())?;
19 dump = dump || attr.dump.is_some();
20 }
21 }
22
23 let ts = match &input.data {
24 Data::Struct(data) => code_from_struct(data)?,
25 Data::Enum(data) => code_from_enum(&input.ident, data)?,
26 Data::Union(_) => {
27 bail!(Span::call_site(), "Not supported for union.")
28 }
29 };
30 let ts = quote! {
31 fn parse(input: ::syn::parse::ParseStream<'_>) -> ::syn::Result<Self> {
32 #ts
33 }
34 };
35 let ts = impl_trait_result(&input, &parse_quote!(::syn::parse::Parse), &[], ts, dump)?;
36 Ok(ts)
37}
38
39fn code_from_struct(data: &DataStruct) -> Result<TokenStream> {
40 code_from_fields(quote!(Self), &data.fields, None)
41}
42fn code_from_enum(self_ident: &Ident, data: &DataEnum) -> Result<TokenStream> {
43 let mut ts = TokenStream::new();
44 ts.extend(quote!(
45 use syn::ext::*;
46 ));
47 let mut input_is_forked = false;
48 let mut input_is_moved = false;
49 for index in 0..data.variants.len() {
50 let variant = &data.variants[index];
51 let variant_ident = &variant.ident;
52 let is_last = index == data.variants.len() - 1;
53 let fn_ident = format_ident!("_parse_{}", &variant.ident);
54 let mut peeks = Vec::new();
55 let fn_expr = code_from_fields(
56 quote!(#self_ident::#variant_ident),
57 &variant.fields,
58 Some(&mut peeks),
59 )?;
60 let fn_def = quote! {
61 #[allow(non_snake_case)]
62 fn #fn_ident(input: ::syn::parse::ParseStream<'_>) -> ::syn::Result<#self_ident> {
63 #fn_expr
64 }
65 };
66 let code = if peeks.is_empty() {
67 if is_last && !input_is_forked {
68 input_is_moved = true;
69 quote! {
70 #fn_ident(input)
71 }
72 } else {
73 input_is_forked = true;
74 quote! {
75 let fork = input.fork();
76 if let Ok(value) = #fn_ident(&fork) {
77 ::syn::parse::discouraged::Speculative::advance_to(input, &fork);
78 return Ok(value);
79 }
80 }
81 }
82 } else {
83 let mut preds = Vec::new();
84 for (index, peek) in peeks.into_iter().enumerate() {
85 preds.push(to_predicate(index, &peek)?);
86 }
87 quote! {
88 if #(#preds )&&* {
89 return #fn_ident(&input);
90 }
91 }
92 };
93 ts.extend(quote! {
94 #fn_def
95 #code
96 });
97 }
98 if !input_is_moved {
99 ts.extend(quote! {
100 Err(input.error("parse failed."))
101 });
102 }
103 Ok(ts)
104}
105fn to_predicate(index: usize, peek: &PeekItem) -> Result<TokenStream> {
106 let peek_ident: Ident = match index {
107 0 => parse_quote!(peek),
108 1 => parse_quote!(peek2),
109 2 => parse_quote!(peek3),
110 _ => bail!(peek.span, "more than three `#[parse(peek)]` was specified."),
111 };
112 let peek_arg = &peek.arg;
113 Ok(quote!(input.#peek_ident(#peek_arg)))
114}
115
116struct Scope {
117 input: Ident,
118 close: Option<char>,
119}
120struct PeekItem {
121 span: Span,
122 arg: TokenStream,
123}
124fn to_parse_bracket(c: char) -> Ident {
125 match c {
126 '(' => parse_quote!(parenthesized),
127 '[' => parse_quote!(bracketed),
128 '{' => parse_quote!(braced),
129 _ => unreachable!(),
130 }
131}
132fn code_from_fields(
133 self_path: TokenStream,
134 fields: &Fields,
135 mut peeks: Option<&mut Vec<PeekItem>>,
136) -> Result<TokenStream> {
137 let mut scopes = vec![Scope {
138 input: parse_quote!(input),
139 close: None,
140 }];
141 let mut ts = TokenStream::new();
142 let mut inits = Vec::new();
143 let mut non_peek_field = None;
144 for (index, field) in fields.iter().enumerate() {
145 let ty = &field.ty;
146 let var_ident = to_var_ident(index, &field.ident);
147 let mut use_parse = true;
148 let mut peek = None;
149 let mut is_any = false;
150 let mut is_terminated = false;
151 let mut is_root = scopes.len() == 1;
152 for attr in &field.attrs {
153 if attr.path.is_ident("to_tokens") {
154 let attr: ToTokensAttribute = parse2(attr.tokens.clone())?;
155 for token in attr.token {
156 for c in token.value().chars() {
157 match c {
158 '(' | '[' | '{' => {
159 use_parse = false;
160 let parse_bracket = if is_macro_delimiter(&field.ty) {
161 quote!(::structmeta::helpers_parse_macro_delimiter)
162 } else {
163 let parse_bracket = to_parse_bracket(c);
164 quote!(::syn::#parse_bracket)
165 };
166 let input_old = &scopes.last().unwrap().input;
167 let input = format_ident!("input_{}", index);
168 let ty = &field.ty;
169 let code = quote_spanned!(field.span()=>
170 let #input;
171 let #var_ident = #parse_bracket!(#input in #input_old);
172 let #var_ident : #ty = #var_ident;
173 let #input = &#input;
174 );
175 ts.extend(code);
179 scopes.push(Scope {
180 close: Some(to_close(c)),
181 input,
182 });
183 }
184 ')' | ']' | '}' => {
185 if scopes.last().unwrap().close != Some(c) {
186 bail!(token.span(), "mismatched closing delimiter `{}`.", c);
187 }
188 scopes.pop();
189 if scopes.len() == 1 {
190 is_root = true;
191 }
192 }
193 _ => {
194 bail!(
195 token.span(),
196 "expected '(', ')', '[', ']', '{{' or '}}', found `{}`.",
197 c
198 );
199 }
200 }
201 }
202 }
203 }
204 if attr.path.is_ident("parse") {
205 let attr: ParseAttribute = parse2(attr.tokens.clone())?;
206 peek = peek.or(attr.peek);
207 is_any = is_any || attr.any.is_some();
208 is_terminated = is_terminated || attr.terminated.is_some();
209 }
210 }
211 if let Some(peeks) = &mut peeks {
212 if let Some(peek) = peek {
213 let span = peek.span();
214 if !is_root {
215 bail!(span, "`#[parse(peek)]` cannot be specified with a field enclosed by `[]`, `()` or `{}`.");
216 }
217 if let Some(non_peek_field) = &non_peek_field {
218 bail!(
219 span,
220 "you need to peek all previous tokens. consider specifying `#[parse(peek)]` for field `{}`.",
221 non_peek_field
222 );
223 }
224 let arg = if is_any {
225 quote!(#ty::peek_any)
226 } else {
227 quote!(#ty)
228 };
229 peeks.push(PeekItem { span, arg });
230 }
231 }
232 if is_root && peek.is_none() && non_peek_field.is_none() {
233 non_peek_field = Some(to_display(index, &field.ident));
234 }
235 if use_parse {
236 let input = &scopes.last().unwrap().input;
237 let expr = match (is_terminated, is_any) {
238 (false, false) => quote!(::syn::parse::Parse::parse(#input)),
239 (false, true) => quote!(<#ty>::parse_any(#input)),
240 (true, false) => {
241 quote!(<#ty>::parse_terminated(#input))
242 }
243 (true, true) => {
244 quote!(<#ty>::parse_terminated_with(#input, ::syn::ext::IdentExt::parse_any))
245 }
246 };
247 let code = quote_spanned!(field.span()=>let #var_ident = #expr?;);
248 ts.extend(code);
249 }
250 if let Some(field_ident) = &field.ident {
251 inits.push(quote!(#field_ident : #var_ident));
252 } else {
253 inits.push(quote!(#var_ident));
254 }
255 }
256 let init = match &fields {
257 Fields::Named(_) => quote!({#(#inits,)*}),
258 Fields::Unnamed(_) => quote!((#(#inits,)*)),
259 Fields::Unit => quote!(),
260 };
261 Ok(quote! {
262 use syn::ext::*;
263 #ts
264 Ok(#self_path #init)
265 })
266}
267
268fn to_var_ident(index: usize, ident: &Option<Ident>) -> Ident {
269 if let Some(ident) = ident {
270 format_ident!("_{}", ident)
271 } else {
272 format_ident!("_{}", index)
273 }
274}
275fn to_display(index: usize, ident: &Option<Ident>) -> String {
276 if let Some(ident) = ident {
277 format!("{ident}")
278 } else {
279 format!("{index}")
280 }
281}
282
283struct ParseAttribute {
284 any: Option<kw::any>,
285 peek: Option<kw::peek>,
286 terminated: Option<kw::terminated>,
287 dump: Option<kw::dump>,
288}
289impl Parse for ParseAttribute {
290 fn parse(input: ParseStream) -> Result<Self> {
291 let content;
292 parenthesized!(content in input);
293 let mut any = None;
294 let mut peek = None;
295 let mut terminated = None;
296 let mut dump = None;
297 let args: Punctuated<ParseAttributeArg, Token![,]> =
298 content.parse_terminated(ParseAttributeArg::parse)?;
299 for arg in args.into_iter() {
300 match arg {
301 ParseAttributeArg::Any(kw_any) => any = any.or(Some(kw_any)),
302 ParseAttributeArg::Peek(kw_peek) => peek = peek.or(Some(kw_peek)),
303 ParseAttributeArg::Terminated(kw_terminated) => {
304 terminated = terminated.or(Some(kw_terminated))
305 }
306 ParseAttributeArg::Dump(kw_dump) => dump = dump.or(Some(kw_dump)),
307 }
308 }
309 Ok(Self {
310 any,
311 peek,
312 terminated,
313 dump,
314 })
315 }
316}
317mod kw {
318 use syn::custom_keyword;
319 custom_keyword!(any);
320 custom_keyword!(peek);
321 custom_keyword!(terminated);
322 custom_keyword!(dump);
323}
324
325enum ParseAttributeArg {
326 Any(kw::any),
327 Peek(kw::peek),
328 Terminated(kw::terminated),
329 Dump(kw::dump),
330}
331impl Parse for ParseAttributeArg {
332 fn parse(input: ParseStream) -> Result<Self> {
333 if input.peek(kw::any) {
334 Ok(Self::Any(input.parse()?))
335 } else if input.peek(kw::peek) {
336 Ok(Self::Peek(input.parse()?))
337 } else if input.peek(kw::terminated) {
338 Ok(Self::Terminated(input.parse()?))
339 } else if input.peek(kw::dump) {
340 Ok(Self::Dump(input.parse()?))
341 } else {
342 Err(input.error("expected `any`, `peek`, `terminated` or `dump`."))
343 }
344 }
345}