1use darling::{ast::Data, util::SpannedValue, FromDeriveInput, FromField, FromVariant};
2use proc_macro2::{Ident, Span, TokenStream};
3use quote::{format_ident, quote, quote_spanned};
4use regex_syntax::ast as regex_ast;
5use std::{convert::Infallible, mem::replace};
6use syn::{
7 parse::{Parse, ParseStream},
8 parse_macro_input, parse_quote, parse_quote_spanned,
9 punctuated::Punctuated,
10 spanned::Spanned,
11 DeriveInput, GenericParam, Index, ItemFn, Token,
12};
13
14#[proc_macro]
15pub fn generate_inpt_impls(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
16 ('B'..='G')
18 .map(|last| {
19 let names = 'A'..=last;
20 let idents: Vec<Ident> = names.clone().map(|i| format_ident!("{}", i)).collect();
21 let idents = &idents;
22 let is_last = (0..idents.len()).map(|i| i + 1 == idents.len());
23 quote! {
24 impl<'s, #(#idents: ::inpt::Inpt<'s>),*> ::inpt::Inpt<'s> for (#(#idents),*) {
25 fn step(text: &'s str, end: bool, trimmed: ::inpt::CharClass, guard: &mut ::inpt::RecursionGuard) -> ::inpt::InptStep<'s, Self> {
26 use ::inpt::ResultExt as _;
27
28 let mut rest = text;
29 let mut this = || Ok((#(
30 {
31 rest = #idents::default_trim(trimmed).trim(rest, #is_last && end);
32 let step = #idents::step(rest, #is_last && end, trimmed, guard);
33 rest = step.rest;
34 step.data?
35 },
36 )*));
37 ::inpt::InptStep {
38 data: this().within(text).expected::<Self>(),
39 rest,
40 }
41 }
42 }
43 }
44 })
45 .collect::<TokenStream>()
46 .into()
47}
48
49#[proc_macro]
50pub fn char_class(args: proc_macro::TokenStream) -> proc_macro::TokenStream {
51 let source = parse_macro_input!(args as syn::LitStr);
52 match parse_char_class(&SpannedValue::new(source.value(), source.span())) {
53 Ok(out) => out.into(),
54 Err(err) => err.into_compile_error().into(),
55 }
56}
57
58fn parse_char_class(source: &SpannedValue<String>) -> syn::Result<TokenStream> {
59 use regex_syntax::hir::{Class, HirKind};
60
61 if source.is_empty() {
62 return Ok(quote! { ::inpt::CharClass(&[]) });
63 }
64
65 let regex = format!("[{}]", **source);
66 let hir = match regex_syntax::Parser::new().parse(®ex) {
67 Ok(hir) => hir,
68 Err(err) => return Err(syn::Error::new(source.span(), err.to_string())),
69 };
70 let class = match hir.kind() {
71 HirKind::Class(Class::Unicode(class)) => class,
72 _ => panic!("did not parse as hir class"),
73 };
74 let tuples: TokenStream = class
75 .iter()
76 .map(|range| {
77 let start = range.start();
78 let end = range.end();
79 quote! { (#start, #end), }
80 })
81 .collect();
82 Ok(quote! { ::inpt::CharClass(&[#tuples]) })
83}
84
85struct ImplInptAs {
86 _impl: Token![impl],
87 generics: syn::Generics,
88 ty: syn::Type,
89 _as: Token![as],
90 wrapper: syn::Type,
91 _arrow: Token![=>],
92 x: syn::Expr,
93}
94
95impl Parse for ImplInptAs {
96 fn parse(input: ParseStream) -> syn::Result<Self> {
97 let _impl = input.parse()?;
98 let mut generics: syn::Generics = input.parse()?;
99 let ty = input.parse()?;
100 let _as = input.parse()?;
101 let wrapper = input.parse()?;
102 generics.where_clause = input.parse()?;
103 let _arrow = input.parse()?;
104 let x = input.parse()?;
105 Ok(ImplInptAs {
106 _impl,
107 generics,
108 ty,
109 _as,
110 wrapper,
111 _arrow,
112 x,
113 })
114 }
115}
116
117struct ImplInptAsArgs {
118 impls: Punctuated<ImplInptAs, Token![,]>,
119}
120
121impl Parse for ImplInptAsArgs {
122 fn parse(input: ParseStream) -> syn::Result<Self> {
123 Ok(ImplInptAsArgs {
124 impls: Punctuated::parse_terminated(input)?,
125 })
126 }
127}
128
129#[proc_macro]
130pub fn impl_inpt_as(args: proc_macro::TokenStream) -> proc_macro::TokenStream {
131 let ImplInptAsArgs { impls } = parse_macro_input!(args as ImplInptAsArgs);
132 impls
133 .into_iter()
134 .map(|impl_as| {
135 let ImplInptAs {
136 mut generics,
137 ty,
138 wrapper,
139 x,
140 ..
141 } = impl_as;
142 let lt = generics.lifetimes().next().cloned();
143 let lt = match lt {
144 Some(lt) => lt,
145 None => {
146 let lt: syn::LifetimeDef = parse_quote! { 's };
147 generics
148 .params
149 .insert(0, GenericParam::Lifetime(lt.clone()));
150 lt
151 }
152 };
153 let lt = <
154 let (impl_generics, _, where_clause) = generics.split_for_impl();
155 quote! {
156 impl #impl_generics ::inpt::Inpt<#lt> for #ty #where_clause {
157 fn step(text: &#lt str, end: bool, trimmed: ::inpt::CharClass, guard: &mut ::inpt::RecursionGuard) -> ::inpt::InptStep<#lt, Self> {
158 use ::inpt::ResultExt as _;
159 let mut step = <#wrapper as ::inpt::Inpt<#lt>>::step(text, end, trimmed, guard).map(#x);
160 step.data = step.data.replace_expected::<#wrapper, Self>();
161 step
162 }
163
164 fn default_trim(inherited: ::inpt::CharClass) -> ::inpt::CharClass {
165 <#wrapper as ::inpt::Inpt<#lt>>::default_trim(inherited)
166 }
167 }
168 }
169 })
170 .collect::<TokenStream>()
171 .into()
172}
173
174#[derive(FromField)]
175#[darling(attributes(inpt))]
176struct InputField {
177 ty: syn::Type,
178 ident: Option<syn::Ident>,
179 #[darling(default)]
180 from_iter: SpannedValue<Option<SpannedValue<String>>>,
181 #[darling(default)]
182 from_str: SpannedValue<Option<bool>>,
183 #[darling(default)]
184 skip: Option<bool>,
185 #[darling(default)]
186 after: Option<bool>,
187 #[darling(default)]
188 before: Option<bool>,
189 #[darling(default)]
190 trim: Option<SpannedValue<String>>,
191 #[darling(default)]
192 split: Option<SpannedValue<String>>,
193 #[darling(skip)]
194 index: usize,
195}
196
197impl InputField {
198 fn skip(&self) -> bool {
199 self.skip.unwrap_or(false)
200 }
201
202 fn from_str(&self) -> bool {
203 self.from_str.unwrap_or(false)
204 }
205
206 fn after(&self) -> bool {
207 !self.skip() && self.after.unwrap_or(false)
208 }
209
210 fn before(&self) -> bool {
211 !self.skip() && self.before.unwrap_or(false)
212 }
213
214 fn capture(&self) -> bool {
215 !(self.skip() || self.after() || self.before())
216 }
217}
218
219#[derive(FromVariant)]
220#[darling(attributes(inpt))]
221struct InputVariant {
222 ident: syn::Ident,
223 fields: darling::ast::Fields<SpannedValue<InputField>>,
224 #[darling(default)]
225 regex: Option<SpannedValue<String>>,
226}
227
228#[derive(FromDeriveInput)]
229#[darling(attributes(inpt))]
230struct InputOpts {
231 ident: syn::Ident,
232 generics: syn::Generics,
233 data: Data<InputVariant, SpannedValue<InputField>>,
234 #[darling(default)]
235 regex: Option<SpannedValue<String>>,
236 #[darling(default)]
237 bounds: Option<syn::LitStr>,
238 #[darling(default)]
239 trim: Option<SpannedValue<String>>,
240 #[darling(default)]
241 from: Option<syn::LitStr>,
242 #[darling(default)]
243 try_from: Option<syn::LitStr>,
244}
245
246fn from_str_field(ty: &syn::Type, input: Ident) -> TokenStream {
247 quote! {
248 match <#ty as ::std::str::FromStr>::from_str(#input) {
249 Ok(val) => Ok(val),
250 Err(e) => Err(::inpt::InptError::expected_from_str::<#ty>(#input))
251 .message_inside(e.to_string())
252 }
253 }
254}
255
256fn parse_type(ty: &SpannedValue<String>) -> syn::Result<syn::Type> {
257 match syn::parse_str::<syn::Type>(ty) {
258 Ok(ty) => Ok(ty),
259 Err(e) => {
260 let mut err = syn::Error::new(ty.span(), "could not parse type");
261 err.combine(e);
262 Err(err)
263 }
264 }
265}
266
267fn from_iter_field(
268 ty: &syn::Type,
269 item: &syn::Type,
270 item_span: Span,
271 input: Ident,
272 trimmed: Ident,
273) -> syn::Result<TokenStream> {
274 let item = quote_spanned! { item_span => #item };
275 Ok(quote_spanned! { item_span => {
276 let mut iter = ::inpt::InptIter::new(#input, #trimmed);
277 let data = <#ty as ::std::iter::FromIterator<#item>>::from_iter(&mut iter);
278 iter.outcome.map(|_| data)
279 } })
280}
281
282type Predicates = syn::punctuated::Punctuated<syn::WherePredicate, Token![,]>;
283
284fn type_as_option(ty: &syn::Type) -> Option<&syn::Type> {
285 let path = match ty {
286 syn::Type::Path(p) => p,
287 _ => return None,
288 };
289 if path.qself.is_some() {
290 return None;
291 }
292 if path.path.leading_colon.is_some() {
293 return None;
294 }
295 if path.path.segments.len() != 1 {
296 return None;
297 }
298 let segment = &path.path.segments[0];
299 if segment.ident != "Option" {
300 return None;
301 }
302 let args = match &segment.arguments {
303 syn::PathArguments::AngleBracketed(a) => a,
304 _ => return None,
305 };
306 if args.args.len() != 1 {
307 return None;
308 }
309 match &args.args[0] {
310 syn::GenericArgument::Type(ty) => Some(ty),
311 _ => None,
312 }
313}
314
315fn regex_definition<'a>(
316 regex: &str,
317 fields: impl IntoIterator<Item = &'a InputField>,
318 span: Span,
319) -> Result<(TokenStream, TokenStream), syn::Error> {
320 struct CountCaptures(pub u32);
321
322 impl regex_ast::Visitor for CountCaptures {
323 type Output = u32;
324 type Err = Infallible;
325
326 fn visit_pre(&mut self, ast: ®ex_ast::Ast) -> Result<(), Infallible> {
327 if let regex_ast::Ast::Group(group) = ast {
328 if let regex_ast::GroupKind::CaptureIndex(idx) = group.kind {
329 self.0 = self.0.max(idx);
330 }
331 }
332 Ok(())
333 }
334
335 fn finish(self) -> Result<u32, Infallible> {
336 Ok(self.0)
337 }
338 }
339
340 let ast = match regex_ast::parse::Parser::new().parse(regex) {
341 Ok(ast) => ast,
342 Err(err) => return Err(syn::Error::new(span, err.to_string())),
343 };
344 let captures = regex_ast::visit(&ast, CountCaptures(0)).unwrap();
345 let fields = fields.into_iter().filter(|field| field.capture()).count();
346 if captures as usize != fields {
347 return Err(syn::Error::new(
348 span,
349 format!("expected {fields} capture groups for struture fields, found {captures}"),
350 ));
351 }
352 let start_regex = format!("^(?:{})", regex);
353 let end_regex = format!("^(?:{})$", regex);
354 Ok((
355 quote! { ::inpt::LazyRegex::new(#start_regex) },
356 quote! { ::inpt::LazyRegex::new(#end_regex) },
357 ))
358}
359
360fn sequential_field(
361 f: &SpannedValue<InputField>,
362 lt: &syn::LifetimeDef,
363 preds: &mut Predicates,
364 prefix: &str,
365 is_last: bool,
366) -> Result<TokenStream, syn::Error> {
367 let ty = &f.ty;
368 let name = format_ident!("{}_{}", prefix, f.index);
369 let trimmed_name = format_ident!("{}_{}_trim", prefix, f.index);
370 let mut trim_init = quote! { let #trimmed_name = trimmed; };
371 let expr = if f.skip == Some(true) {
372 quote! { <#ty as ::std::default::Default>::default() }
373 } else if let Some(split) = &f.split {
374 let mut split_ty = parse_type(split)?;
375 split_ty = parse_quote! { ::inpt::split::#split_ty<&'s str> };
376 trim_init =
377 quote! { let #trimmed_name = <#split_ty as ::inpt::Inpt>::default_trim(trimmed); };
378 let (inner, is_opt) = regex_field(f, lt, preds, prefix)?;
379 if is_opt {
380 return Err(syn::Error::new(
381 split.span(),
382 "splitting can not produce None",
383 ));
384 }
385 quote! { {
386 let step = <#split_ty as ::inpt::Inpt>::step(rest, #is_last && end, #trimmed_name, guard);
387 rest = step.rest;
388 step.data.map(|split| split.inner).and_then(|full_group| #inner)
389 } }
390 } else if f.from_str() {
391 if !is_last {
392 return Err(syn::Error::new(
393 f.from_str.span(),
394 "without a regex or split, from_str can only be used on the last field",
395 ));
396 }
397 from_str_field(ty, format_ident!("rest"))
398 } else if let Some(item) = &*f.from_iter {
399 let item_ty = parse_type(item)?;
400 trim_init =
401 quote! { let #trimmed_name = <#item_ty as ::inpt::Inpt>::default_trim(trimmed); };
402 if !is_last {
403 return Err(syn::Error::new(
404 f.from_iter.span(),
405 "without a regex, from_iter can only be used on the last field",
406 ));
407 }
408 from_iter_field(
409 ty,
410 &item_ty,
411 item.span(),
412 format_ident!("rest"),
413 trimmed_name.clone(),
414 )?
415 } else {
416 trim_init = quote! { let #trimmed_name = <#ty as ::inpt::Inpt>::default_trim(trimmed); };
417 preds.push(parse_quote_spanned! { f.ty.span() => #ty: ::inpt::Inpt<#lt> });
418 quote! { {
419 let step = <#ty as ::inpt::Inpt>::step(rest, #is_last && end, #trimmed_name, guard);
420 rest = step.rest;
421 step.data
422 } }
423 };
424 if let Some(source) = &f.trim {
425 let expr = parse_char_class(source)?;
426 trim_init = quote! { let #trimmed_name = #expr; };
427 }
428 Ok(quote_spanned! { f.span() =>
429 #trim_init
430 let after_trim = #trimmed_name.trim(rest, #is_last && end);
431 rest = after_trim;
432 #name = #expr?;
433 })
434}
435
436fn regex_field(
437 f: &SpannedValue<InputField>,
438 lt: &syn::LifetimeDef,
439 preds: &mut Predicates,
440 prefix: &str,
441) -> Result<(TokenStream, bool), syn::Error> {
442 let trimmed_name = format_ident!("{}_{}_trim", prefix, f.index);
443 let mut trim_init = quote! { let #trimmed_name = trimmed; };
444 let (ty, is_opt) = match type_as_option(&f.ty) {
445 Some(ty) => (ty, true),
446 None => (&f.ty, false),
447 };
448 let trimmed_name = format_ident!("{}_{}_trim", prefix, f.index);
449 let expr = if f.from_str() {
450 from_str_field(ty, format_ident!("group"))
451 } else if let Some(item) = &*f.from_iter {
452 let item_ty = parse_type(item)?;
453 trim_init =
454 quote! { let #trimmed_name = <#item_ty as ::inpt::Inpt>::default_trim(trimmed); };
455 from_iter_field(
456 ty,
457 &item_ty,
458 item.span(),
459 format_ident!("group"),
460 trimmed_name.clone(),
461 )?
462 } else {
463 trim_init = quote! { let #trimmed_name = <#ty as ::inpt::Inpt>::default_trim(trimmed); };
464 preds.push(parse_quote_spanned! { ty.span() => #ty: ::inpt::Inpt<#lt> });
465 quote! {
466 <#ty as ::inpt::Inpt>::step(group, true, trimmed, guard).data
467 }
468 };
469
470 if let Some(source) = &f.trim {
471 let expr = parse_char_class(source)?;
472 trim_init = quote! { let #trimmed_name = #expr; };
473 }
474
475 Ok((
476 quote! { {
477 #trim_init
478 let group = #trimmed_name.trim(full_group, true);
479 #expr.within(full_group)
480 } },
481 is_opt,
482 ))
483}
484
485fn field_exprs(
486 fields: &darling::ast::Fields<SpannedValue<InputField>>,
487 lt: &syn::LifetimeDef,
488 preds: &mut Predicates,
489 prefix: &str,
490 regex: Option<&SpannedValue<String>>,
491) -> Result<TokenStream, syn::Error> {
492 let mut this = TokenStream::new();
493
494 for f in fields.iter() {
495 match (regex.is_some(), f.before(), f.after()) {
496 (false, true, _) | (false, _, true) => {
497 return Err(syn::Error::new(
498 f.span(),
499 "before and after only apply when matching a regex",
500 ))
501 }
502 (_, true, true) => {
503 return Err(syn::Error::new(
504 f.span(),
505 "a field can not be marked before and after",
506 ));
507 }
508 _ => (),
509 }
510 }
511
512 for f in fields.iter().filter(|f| f.before()) {
513 this.extend(sequential_field(f, lt, preds, prefix, false)?);
514 }
515
516 if let Some(regex) = regex {
517 let (start_regex, end_regex) =
518 regex_definition(&**regex, fields.iter().map(|f| &**f), regex.span())?;
519 let regex = &**regex;
520 let no_after = fields.iter().all(|f| !f.after());
521 this.extend(quote! {
522 static RE_SOURCE: &str = #regex;
523 static RE_START: ::inpt::LazyRegex = #start_regex;
524 static RE_END: ::inpt::LazyRegex = #end_regex;
525 rest = trimmed.trim(rest, #no_after && end);
526 let regex = if #no_after && end { &RE_END } else { &RE_START};
527 let regex_text = rest;
528 let capture = regex
529 .captures(regex_text)
530 .ok_or_else(|| ::inpt::InptError::expected_regex(RE_SOURCE, text))?;
531 matched = true;
532 rest = &rest[capture.get(0).unwrap().end()..];
533 });
534
535 let mut group_idx: usize = 1;
536 for f in fields.iter().filter(|f| f.capture()) {
537 if let Some(split) = &f.split {
538 return Err(syn::Error::new(
539 split.span(),
540 "don't use split with a capture group",
541 ));
542 }
543 let name = format_ident!("{}_{}", prefix, f.index);
544 let (expr, is_opt) = regex_field(f, lt, preds, prefix)?;
545 if is_opt {
546 this.extend(quote_spanned! { f.span() =>
547 #name = match capture.get(#group_idx).map(|m| m.as_str()){
548 None => None,
549 Some(full_group) => Some(#expr.regex_group(#group_idx)
550 .within(regex_text)
551 .regex(RE_SOURCE)?)
552 };
553 });
554 } else {
555 this.extend(quote_spanned! { f.span() =>
556 #name = match capture.get(#group_idx).map(|m| m.as_str()) {
557 None => return Err(::inpt::InptError::expected_regex_group(#group_idx))
558 .within(regex_text)
559 .regex(RE_SOURCE),
560 Some(full_group) => #expr.regex_group(#group_idx)
561 .within(regex_text)
562 .regex(RE_SOURCE)?,
563 };
564 });
565 }
566 group_idx += 1;
567 }
568 }
569
570 let last_index = fields
571 .iter()
572 .rposition(|f| {
573 if regex.is_some() {
574 f.after()
575 } else {
576 !f.skip()
577 }
578 })
579 .unwrap_or(fields.len());
580 for f in fields
581 .iter()
582 .filter(|f| !f.skip() && (regex.is_none() || f.after()))
583 {
584 this.extend(sequential_field(
585 f,
586 lt,
587 preds,
588 prefix,
589 f.index == last_index,
590 )?);
591 }
592
593 this.extend(quote! { matched = true; });
594
595 for f in fields.iter().filter(|f| f.skip()) {
596 let ty = &f.ty;
597 let name = format_ident!("{}_{}", prefix, f.index);
598 this.extend(quote! { #name = <#ty as ::std::default::Default>::default(); })
599 }
600
601 Ok(this)
602}
603
604fn field_setup(
605 fields: &darling::ast::Fields<SpannedValue<InputField>>,
606 prefix: &str,
607) -> (TokenStream, TokenStream) {
608 let mut head = TokenStream::new();
609 let mut inst = TokenStream::new();
610 for f in fields.iter() {
611 let ty = &f.ty;
612 let name = format_ident!("{}_{}", prefix, f.index);
613 head.extend(quote! { let mut #name: #ty; });
614 if let Some(ident) = &f.ident {
615 inst.extend(quote! { #ident: #name, });
616 } else {
617 let idx = Index {
618 index: f.index as _,
619 span: Span::call_site(),
620 };
621 inst.extend(quote! { #idx: #name, });
622 }
623 }
624 (head, inst)
625}
626
627fn impl_inpt_derive(
628 InputOpts {
629 ident,
630 generics,
631 data,
632 regex,
633 bounds,
634 trim,
635 from,
636 try_from,
637 }: InputOpts,
638) -> Result<TokenStream, syn::Error> {
639 let mut generics_with_lt = generics.clone();
640 let lt = match generics.lifetimes().next() {
641 Some(lt) => lt.clone(),
642 None => {
643 let lt: syn::LifetimeDef = parse_quote! { 's };
644 generics_with_lt
645 .params
646 .insert(0, GenericParam::Lifetime(lt.clone()));
647 lt
648 }
649 };
650 let lt = <
651
652 let default_trim = if let Some(source) = &trim {
653 let expr = parse_char_class(source)?;
654 quote! {
655 fn default_trim(_inherited: ::inpt::CharClass) -> ::inpt::CharClass {
656 #expr
657 }
658 }
659 } else if let Some(from) = from.as_ref().or(try_from.as_ref()) {
660 let from = from.parse::<syn::Type>()?;
661 quote! {
662 fn default_trim(inherited: ::inpt::CharClass) -> ::inpt::CharClass {
663 <#from as inpt::Inpt<#lt>>::default_trim(inherited)
664 }
665 }
666 } else {
667 TokenStream::new()
668 };
669
670 if from.is_some() || try_from.is_some() {
671 if let Some(regex) = ®ex {
672 return Err(syn::Error::new(
673 regex.span(),
674 "don't use from or try_from with a regex",
675 ));
676 }
677 }
678
679 let preds = &mut generics_with_lt
680 .where_clause
681 .get_or_insert_with(|| parse_quote! { where })
682 .predicates;
683 preds.push(parse_quote! { Self: #lt });
684
685 let mut head = TokenStream::new();
686 let mut body = TokenStream::new();
687
688 match (from, try_from, data) {
689 (Some(from), _, _) => {
690 let from = from.parse::<syn::Type>()?;
691 preds.push(parse_quote! { #from: Inpt<#lt> });
692 body.extend(quote! {
693 let mut res = <#from as ::inpt::Inpt<#lt>>::step(text, end, trimmed, guard)
694 .map(From::from);
695 rest = res.rest;
696 res.data
697 });
698 }
699 (_, Some(from), _) => {
700 let from = from.parse::<syn::Type>()?;
701 preds.push(parse_quote! { #from: Inpt<#lt> });
702 body.extend(quote! {
703 let mut res = <#from as ::inpt::Inpt<#lt>>::step(text, end, trimmed, guard)
704 .try_map(core::convert::TryFrom::try_from);
705 rest = res.rest;
706 res.data
707 });
708 }
709 (_, _, Data::Struct(fields)) => {
710 let (struct_head, inst) = field_setup(&fields, "field");
711 head.extend(struct_head);
712 let inner = field_exprs(&fields, <, preds, "field", regex.as_ref())?;
713 body.extend(quote! {
714 #inner
715 Ok(Self {
716 #inst
717 })
718 });
719 }
720 (_, _, Data::Enum(varis)) => {
721 for (idx, vari) in varis.into_iter().enumerate() {
722 let prefix = format!("field_{}", idx);
723 let (vari_head, inst) = field_setup(&vari.fields, &prefix);
724 let inner = field_exprs(&vari.fields, <, preds, &prefix, vari.regex.as_ref())?;
726 let vari_ident = &vari.ident;
727 body.extend(quote! {
728 rest = text;
729 let mut vari = || {
730 #vari_head
731 #inner
732 Ok(Self::#vari_ident {
733 #inst
734 })
735 };
736 let res = vari();
737 if matched {
738 return res;
739 }
740 });
741 }
742 body.extend(quote! {
743 if let Err(err) = res {
744 Err(err).expected::<Self>()
745 } else {
746 Err(::inpt::InptError::expected::<Self>(text))
747 }
748 });
749 }
750 }
751
752 if let Some(bounds) = bounds {
753 struct Bounds {
754 preds: Predicates,
755 }
756
757 impl Parse for Bounds {
758 fn parse(input: ParseStream) -> syn::Result<Self> {
759 Ok(Self {
760 preds: Punctuated::parse_terminated(input)?,
761 })
762 }
763 }
764
765 preds.clear();
766 *preds = bounds.parse::<Bounds>()?.preds;
767 }
768
769 let (impl_generics, _, where_clause) = generics_with_lt.split_for_impl();
770 let (_, ty_generics, _) = generics.split_for_impl();
771
772 Ok(quote! {
773 impl #impl_generics ::inpt::Inpt<#lt> for #ident #ty_generics #where_clause {
774 fn step(text: &#lt str, end: bool, trimmed: ::inpt::CharClass, guard: &mut ::inpt::RecursionGuard) -> ::inpt::InptStep<#lt, Self> {
775 use ::inpt::ResultExt as _;
776
777 guard.check(text, |guard| {
778 let mut rest = text;
779 let mut matched = false;
780 let mut this = || { #head #body };
781 ::inpt::InptStep {
782 data: this().within(text).expected::<Self>(),
783 rest,
784 }
785 })
786 }
787
788 #default_trim
789 }
790 })
791}
792
793#[proc_macro_derive(Inpt, attributes(inpt))]
794pub fn inpt_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
795 let input = parse_macro_input!(input as DeriveInput);
796 let mut input = match InputOpts::from_derive_input(&input) {
797 Ok(opts) => opts,
798 Err(err) => return err.write_errors().into(),
799 };
800 match &mut input.data {
801 Data::Enum(e) => {
802 for v in e {
803 for (idx, f) in v.fields.fields.iter_mut().enumerate() {
804 f.index = idx;
805 }
806 }
807 }
808 Data::Struct(s) => {
809 for (idx, f) in s.fields.iter_mut().enumerate() {
810 f.index = idx;
811 }
812 }
813 }
814 match impl_inpt_derive(input) {
815 Ok(out) => out.into(),
816 Err(err) => err.into_compile_error().into(),
817 }
818}
819
820fn impl_main_attribute(args: TokenStream, mut item: ItemFn) -> Result<TokenStream, syn::Error> {
821 let mut field_defs = Vec::new();
822 let mut field_pats = Vec::new();
823 for (index, arg) in item.sig.inputs.iter_mut().enumerate() {
824 if let syn::FnArg::Typed(arg) = arg {
825 let name = format_ident!("arg{}", index);
826 let ty = &arg.ty;
827 let pat = &arg.pat;
828 let (inpt_attrs, other_attrs): (Vec<_>, Vec<_>) = arg
829 .attrs
830 .drain(..)
831 .partition(|attr| attr.path.is_ident("inpt"));
832 arg.attrs.extend(other_attrs.into_iter());
833 field_defs.push(quote! { #(#inpt_attrs)* #name: #ty });
834 field_pats.push(quote! { #name: #pat });
835 }
836 }
837 let id = &item.sig.ident;
838 let gen = &item.sig.generics;
839 let output = &item.sig.output;
840 let vis = &item.vis;
841 let body = &item.block;
842 let attrs = replace(&mut item.attrs, Default::default());
843
844 Ok(quote! {
845 #(#attrs)*
846 #vis fn #id() #output {
847 #[derive(::inpt::Inpt)]
848 #[inpt(#args)]
849 struct Arguments #gen {
850 #(#field_defs,)*
851 }
852
853 let Arguments { #(#field_pats,)* } = ::inpt::inpt_stdio();
854 #body
855 }
856 })
857}
858
859#[proc_macro_attribute]
860pub fn main(
861 args: proc_macro::TokenStream,
862 item: proc_macro::TokenStream,
863) -> proc_macro::TokenStream {
864 let item = parse_macro_input!(item as ItemFn);
865 match impl_main_attribute(args.into(), item) {
866 Ok(out) => out.into(),
867 Err(err) => err.into_compile_error().into(),
868 }
869}