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 let ast = syn::parse::<DeriveInput>(input).unwrap();
12 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 let ast = syn::parse2::<DeriveInput>(input).unwrap();
28 let Data::Enum(data) = ast.data else {
30 Err(syn::Error::new_spanned(&ast.ident, "#[derive(ParserImpl)] can only handle enum. "))?
31 };
32 let name = &ast.ident;
34 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 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 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}