proc_macro_rules_macros/
lib.rs1#![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 }
26
27fn 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 let ast = ast::SubRule { matchers: vec![] };
76 run_test(ast, vec![]);
77
78 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 let ast = ast::SubRule {
95 matchers: vec![Fragment::Ident(Ident::new("foo", Span::call_site()))],
96 };
97 run_test(ast, vec![]);
98
99 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}