proc_macro_rules_macros/
lib.rs

1#![recursion_limit = "256"]
2
3extern crate proc_macro;
4extern crate proc_macro2;
5extern crate quote;
6extern crate syn;
7
8use proc_macro::TokenStream;
9use quote::ToTokens;
10use syn::parse_macro_input;
11
12mod ast;
13mod expand;
14mod parse;
15
16#[proc_macro]
17pub fn rules(input: TokenStream) -> TokenStream {
18    parse_macro_input!(input as ast::Rules)
19        .into_token_stream()
20        .into()
21}
22
23fn verify_rule(_rule: &ast::SubRule) {
24    // FIXME(#11) pattern rule verification
25}
26
27// FIXME(#12) we could save some computation by using intermediate results from the SubRules.
28fn collect_vars(rule: &ast::SubRule, vars: &mut Vec<ast::MetaVar>) {
29    for m in &rule.matchers {
30        match m {
31            ast::Fragment::Var(id, ty) => vars.push(ast::MetaVar {
32                name: id.clone(),
33                ty: ast::MetaVarType::T(*ty),
34            }),
35            ast::Fragment::Repeat(sub_rule, rkind, _) => {
36                let mut sub = vec![];
37                collect_vars(sub_rule, &mut sub);
38                for s in sub {
39                    vars.push(match rkind {
40                        ast::RepeatKind::ZeroOrMore | ast::RepeatKind::OneOrMore => ast::MetaVar {
41                            name: s.name,
42                            ty: ast::MetaVarType::Vec(Box::new(s.ty)),
43                        },
44                        ast::RepeatKind::ZeroOrOne => ast::MetaVar {
45                            name: s.name,
46                            ty: ast::MetaVarType::Option(Box::new(s.ty)),
47                        },
48                    })
49                }
50            }
51            ast::Fragment::Group(sub_rule, _) => {
52                collect_vars(sub_rule, vars);
53            }
54            _ => {}
55        }
56    }
57}
58
59#[cfg(test)]
60mod test {
61    use super::*;
62    use crate::ast::*;
63    use proc_macro2::Span;
64    use syn::Ident;
65
66    #[test]
67    fn test_collect_vars() {
68        fn run_test(rule: ast::SubRule, expected: Vec<MetaVar>) {
69            let mut result = vec![];
70            collect_vars(&rule, &mut result);
71            assert_eq!(result, expected);
72        }
73
74        // ``
75        let ast = ast::SubRule { matchers: vec![] };
76        run_test(ast, vec![]);
77
78        // `$foo:vis`
79        let ast = ast::SubRule {
80            matchers: vec![Fragment::Var(
81                Ident::new("foo", Span::call_site()),
82                Type::Vis,
83            )],
84        };
85        run_test(
86            ast,
87            vec![MetaVar {
88                name: Ident::new("foo", Span::call_site()),
89                ty: MetaVarType::T(Type::Vis),
90            }],
91        );
92
93        // `foo`
94        let ast = ast::SubRule {
95            matchers: vec![Fragment::Ident(Ident::new("foo", Span::call_site()))],
96        };
97        run_test(ast, vec![]);
98
99        // `foo $bar:Tt $($foo:expr)*`
100        let ast = ast::SubRule {
101            matchers: vec![
102                Fragment::Ident(Ident::new("foo", Span::call_site())),
103                Fragment::Var(Ident::new("bar", Span::call_site()), Type::Tt),
104                Fragment::Repeat(
105                    SubRule {
106                        matchers: vec![Fragment::Var(
107                            Ident::new("foo", Span::call_site()),
108                            Type::Expr,
109                        )],
110                    },
111                    RepeatKind::OneOrMore,
112                    None,
113                ),
114            ],
115        };
116        run_test(
117            ast,
118            vec![
119                MetaVar {
120                    name: Ident::new("bar", Span::call_site()),
121                    ty: MetaVarType::T(Type::Tt),
122                },
123                MetaVar {
124                    name: Ident::new("foo", Span::call_site()),
125                    ty: MetaVarType::Vec(Box::new(MetaVarType::T(Type::Expr))),
126                },
127            ],
128        );
129    }
130}