aboutsummaryrefslogtreecommitdiff
path: root/syn/codegen/src/gen.rs
blob: ef431829bf4a854def5686d1ec9421ca6e450f12 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
use inflections::Inflect;
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
use syn_codegen::{Data, Definitions, Features, Node};

pub const TERMINAL_TYPES: &[&str] = &["Span", "Ident"];

pub fn under_name(name: &str) -> Ident {
    Ident::new(&name.to_snake_case(), Span::call_site())
}

pub fn traverse(
    defs: &Definitions,
    node: fn(&mut TokenStream, &mut TokenStream, &Node, &Definitions),
) -> (TokenStream, TokenStream) {
    let mut types = defs.types.clone();
    for terminal in TERMINAL_TYPES {
        types.push(Node {
            ident: terminal.to_string(),
            features: Features::default(),
            data: Data::Private,
            exhaustive: true,
        });
    }
    types.sort_by(|a, b| a.ident.cmp(&b.ident));

    let mut traits = TokenStream::new();
    let mut impls = TokenStream::new();
    for s in types {
        if s.ident == "Reserved" {
            continue;
        }
        let features = &s.features.any;
        let features = match features.len() {
            0 => quote!(),
            1 => quote!(#[cfg(feature = #(#features)*)]),
            _ => quote!(#[cfg(any(#(feature = #features),*))]),
        };
        traits.extend(features.clone());
        impls.extend(features);
        node(&mut traits, &mut impls, &s, defs);
    }

    (traits, impls)
}