pratt_gen_macros/
lib.rs

1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::{self, Data, DeriveInput, Result};
4mod variant;
5mod fmt;
6use fmt::*;
7
8#[proc_macro_derive(Space)]
9pub fn space_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
10    // Parse the input tokens into a syntax tree
11    let ast = syn::parse::<DeriveInput>(input).unwrap();
12    // Get the enum name
13    let name = &ast.ident;
14    quote! {impl<'a> Space<'a> for #name<'a> {}}.into()
15}
16
17#[proc_macro_derive(ParserImpl, attributes(parse))]
18pub fn parser_impl_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
19    match impl_parser(input.into()) {
20        Ok(out) => out.into(),
21        Err(err) => err.to_compile_error().into(),
22    }
23}
24
25fn impl_parser(input: TokenStream) -> Result<TokenStream> {
26    // Parse the input tokens into a syntax tree
27    let ast = syn::parse2::<DeriveInput>(input).unwrap();
28    // Only allow enum
29    let Data::Enum(data) = ast.data else {
30        Err(syn::Error::new_spanned(&ast.ident, "#[derive(ParserImpl)] can only handle enum. "))?
31    };
32    // Get the enum name
33    let name = &ast.ident;
34    // Verify there is exactly one generic parameter
35    if ast.generics.lifetimes().into_iter().count() != 1 {
36        Err(syn::Error::new_spanned(&ast.ident, "#[derive(ParserImpl)] need the enum to have exactly one lifetime argument. "))?
37    }
38    // Implement parser_impl... for each variant arm
39    let mut arm_names = Vec::new();
40    let mut arm_impls = TokenStream::new();
41    for arm in data.variants {
42        let (name, func) = variant::impl_parser_variant(&name, arm)?;
43        arm_names.push(name);
44        arm_impls.extend(func);
45    }
46    let body = impl_parser_body(arm_names);
47    // Implement ParserImpl for enum
48    Ok(quote! {
49        impl<'a> ParserImpl<'a> for #name<'a> {
50            fn parser_impl(
51                source: Source<'a>, 
52                out_arena: &'a Arena,
53                err_arena: &'a Arena,
54                precedence: u16,
55            ) -> Result<(Self, Source<'a>), Error<'a>> {
56                #body
57            }
58        }
59        #arm_impls
60    }.into())
61}
62
63fn impl_parser_body(arm_names: Vec<syn::Ident>) -> TokenStream {
64    let mut body = TokenStream::new();
65    body.extend(quote! {
66        let err_len = unsafe { err_arena.size() };
67        let out_len = unsafe { out_arena.size() };
68        let chain = List::new();
69    });
70    for arm in arm_names {body.extend(quote! {
71        let chain = match Self::#arm(source, out_arena, err_arena, precedence) {
72            Ok(out) => unsafe {err_arena.pop(err_len); return Ok(out)},
73            Err(e) => unsafe {out_arena.pop(out_len); chain.push(&err_arena, e)},
74        };
75    })}
76    body.extend(quote! {
77        Err(Error::List(unsafe { err_arena.alloc(chain) }))
78    });
79    body
80}