1mod fmtparser;
2mod builder;
3
4use fmtparser::*;
5use builder::*;
6use syn::*;
7use quote::{quote, ToTokens};
8use proc_macro2::*;
9
10macro_rules! bail {
12 ($x: expr) => {match $x {
13 Ok(out) => out,
14 Err(err) => return err.into_compile_error().into()
15 }};
16}
17
18pub(crate) const CRATE: &str = "pigeon";
19
20#[proc_macro_derive(ParseImpl, attributes(rule))]
22pub fn parse_impl_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
23 let input = bail!(parse::<DeriveInput>(input));
24 let builder = bail!(Builder::new(input));
25 let mut output = TokenStream::new();
26 output.extend(bail!(builder.parse_impl_build()));
27 output.extend(bail!(builder.rules_impl_build()));
28 output.into()
29}
30
31#[proc_macro_derive(EnumAstImpl, attributes(rule, with))]
33pub fn ast_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
34 let input = bail!(parse::<DeriveInput>(input));
35 let builder = bail!(Builder::new(input));
36 let mut output = TokenStream::new();
37 output.extend(bail!(builder.ast_impl_build()));
38 output.into()
39}
40
41#[proc_macro_derive(PrependAstImpl)]
43pub fn prepend_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
44 let input = bail!(parse::<DeriveInput>(input));
45 let _crate = parse_str::<Ident>(CRATE).unwrap();
46 let generics = input.generics.params;
47 let ident = input.ident;
48 quote! {
49 impl<#generics, Extra: Copy> AstImpl<Extra> for #ident<#generics> where
50 Self: Prepend<Extra>,
51 <Self as Prepend<Extra>>::Item: AstImpl<Extra>
52 {
53 fn ast<'lifetime>(
54 input: &'lifetime str,
55 stack: &'lifetime [#_crate::Tag],
56 with: Extra
57 ) -> (&'lifetime [#_crate::Tag], Self) {
58 let tag = &stack[stack.len()-1];
59 let mut stack = &stack[..stack.len()-1];
60 let mut this = <Self as Prepend<Extra>>::empty(with);
61 for i in 0..tag.rule {
62 let (stack_, value) = <<Self as Prepend<Extra>>::Item as AstImpl<Extra>>::ast(input, stack, with);
63 this.prepend(value, with);
64 stack = stack_;
65 }
66 (stack, this)
67 }
68 }
69 }.into()
70}
71
72#[proc_macro_derive(Num, attributes(rule))]
74pub fn num_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
75 let input = bail!(parse::<DeriveInput>(input));
76 let builder = bail!(Builder::new(input));
77 bail!(builder.num_build()).into()
78}
79
80#[proc_macro_derive(Space)]
82pub fn space_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
83 let input = bail!(syn::parse::<DeriveInput>(input));
84 let ident = input.ident;
85 let generics = input.generics.params;
86 let comma = generics.to_token_stream().into_iter().last().map(|x| x.to_string() == ",").unwrap_or(false);
87 let generics =
88 if !comma && !generics.is_empty() { quote! { #generics, } }
89 else { quote! { #generics } };
90 quote! {
91 impl<#generics> Space for #ident<#generics> {}
92 }.into()
93}