1use proc_macro2::Span;
2use std::collections::HashMap;
3
4use crate::ast::*;
5
6pub struct GrammarAnalysis<'a> {
7 pub rules: HashMap<String, &'a Rule>,
8 pub left_recursion: Vec<LeftRecursionError>,
9 pub loop_nullability: Vec<LoopNullabilityError>,
10}
11
12pub fn check<'a>(grammar: &'a Grammar) -> GrammarAnalysis<'a> {
13 let mut rules = HashMap::new();
14
15 for rule in grammar.iter_rules() {
17 rules.entry(rule.name.to_string()).or_insert(rule);
18 }
19
20 let (rule_nullability, left_recursion) = LeftRecursionVisitor::check(grammar, &rules);
21 let loop_nullability = LoopNullabilityVisitor::check(grammar, &rule_nullability);
22
23 GrammarAnalysis {
24 rules,
25 left_recursion,
26 loop_nullability,
27 }
28}
29
30struct LeftRecursionVisitor<'a> {
35 stack: Vec<String>,
36 rules: &'a HashMap<String, &'a Rule>,
37 errors: Vec<LeftRecursionError>,
38}
39
40pub struct LeftRecursionError {
41 pub span: Span,
42 pub path: Vec<String>,
43}
44
45impl LeftRecursionError {
46 pub fn msg(&self) -> String {
47 format!(
48 "left recursive rules create an infinite loop: {}",
49 self.path.join(" -> ")
50 )
51 }
52}
53
54impl<'a> LeftRecursionVisitor<'a> {
55 fn check(grammar: &'a Grammar, rules: &HashMap<String, &'a Rule>) -> (HashMap<String, bool>, Vec<LeftRecursionError>) {
56 let mut visitor = LeftRecursionVisitor {
57 rules,
58 errors: Vec::new(),
59 stack: Vec::new(),
60 };
61
62 let mut rule_nullability: HashMap<String, bool> = HashMap::new();
63
64 for rule in grammar.iter_rules() {
65 let nullable = visitor.walk_rule(rule);
66 debug_assert!(visitor.stack.is_empty());
67 rule_nullability.entry(rule.name.to_string()).or_insert(nullable);
68 }
69
70 (rule_nullability, visitor.errors)
71 }
72
73 fn walk_rule(&mut self, rule: &'a Rule) -> bool {
74 self.stack.push(rule.name.to_string());
75 let res = self.walk_expr(&rule.expr);
76 self.stack.pop().unwrap();
77 res
78 }
79
80 fn walk_expr(&mut self, this_expr: &SpannedExpr) -> bool {
87 use self::Expr::*;
88 match this_expr.expr {
89 RuleExpr(ref rule_ident, _, _) => {
90 let name = rule_ident.to_string();
91
92 if let Some(rule) = self.rules.get(&name) {
93 if let Some(loop_start) = self
94 .stack
95 .iter()
96 .position(|caller_name| caller_name == &name)
97 {
98 let mut recursive_loop = self.stack[loop_start..].to_vec();
99 recursive_loop.push(name.clone());
100 match rule.cache {
101 None | Some(Cache::Simple) =>
102 self.errors.push(LeftRecursionError {
103 path: recursive_loop,
104 span: rule_ident.span(),
105 }),
106 _ => ()
107
108 }
109 return false;
110 }
111 self.walk_rule(rule)
112 } else {
113 false
115 }
116 }
117
118 ActionExpr(ref elems, ..) => {
119 for elem in elems {
120 if !self.walk_expr(&elem.expr) {
121 return false;
122 }
123 }
124
125 true
126 }
127
128 ChoiceExpr(ref choices) => {
129 let mut nullable = false;
130 for expr in choices {
131 nullable |= self.walk_expr(expr);
132 }
133 nullable
134 }
135
136 OptionalExpr(ref expr) | PosAssertExpr(ref expr) | NegAssertExpr(ref expr) => {
137 self.walk_expr(expr);
138 true
139 }
140
141 Repeat { ref inner, ref bound, .. } => {
142 let inner_nullable = self.walk_expr(inner);
143 inner_nullable | !bound.has_lower_bound()
144 }
145
146 MatchStrExpr(ref expr) | QuietExpr(ref expr) => self.walk_expr(expr),
147
148 PrecedenceExpr { ref levels } => {
149 let mut nullable = false;
150
151 for level in levels {
152 for operator in &level.operators {
153 let mut operator_nullable = true;
154 for element in &operator.elements {
155 if !self.walk_expr(&element.expr) {
156 operator_nullable = false;
157 break;
158 }
159 }
160 nullable |= operator_nullable;
161 }
162 }
163
164 nullable
165 }
166
167 | LiteralExpr(_)
168 | PatternExpr(_)
169 | MethodExpr(_, _)
170 | CustomExpr(_)
171 | FailExpr(_)
172 | MarkerExpr(_) => false,
173
174 PositionExpr => true,
175 }
176 }
177}
178
179struct LoopNullabilityVisitor<'a> {
182 rule_nullability: &'a HashMap<String, bool>,
183 errors: Vec<LoopNullabilityError>,
184}
185
186pub struct LoopNullabilityError {
187 pub span: Span,
188}
189
190impl LoopNullabilityError {
191 pub fn msg(&self) -> String {
192 format!("loops infinitely because loop body can match without consuming input")
193 }
194}
195
196
197impl<'a> LoopNullabilityVisitor<'a> {
198 fn check(grammar: &'a Grammar, rule_nullability: &HashMap<String, bool>) -> Vec<LoopNullabilityError> {
199 let mut visitor = LoopNullabilityVisitor {
200 rule_nullability,
201 errors: Vec::new(),
202 };
203
204 for rule in grammar.iter_rules() {
205 visitor.walk_expr(&rule.expr);
206 }
207
208 visitor.errors
209 }
210
211
212 fn walk_expr(&mut self, this_expr: &SpannedExpr) -> bool {
222 use self::Expr::*;
223 match this_expr.expr {
224 RuleExpr(ref rule_ident, _, _) => {
225 let name = rule_ident.to_string();
226 *self.rule_nullability.get(&name).unwrap_or(&false)
227 }
228
229 ActionExpr(ref elems, ..) => {
230 let mut nullable = true;
231 for elem in elems {
232 nullable &= self.walk_expr(&elem.expr);
233 }
234 nullable
235 }
236
237 ChoiceExpr(ref choices) => {
238 let mut nullable = false;
239 for expr in choices {
240 nullable |= self.walk_expr(expr);
241 }
242 nullable
243 }
244
245 OptionalExpr(ref expr) | PosAssertExpr(ref expr) | NegAssertExpr(ref expr) => {
246 self.walk_expr(expr);
247 true
248 }
249
250 Repeat { ref inner, ref bound, ref sep } => {
251 let inner_nullable = self.walk_expr(inner);
252 let sep_nullable = sep.as_ref().map_or(true, |sep| self.walk_expr(sep));
253
254 if inner_nullable && sep_nullable && !bound.has_upper_bound() {
256 self.errors.push(LoopNullabilityError { span: this_expr.span });
257 }
258
259 inner_nullable | !bound.has_lower_bound()
260 }
261
262 MatchStrExpr(ref expr) | QuietExpr(ref expr) => self.walk_expr(expr),
263
264 PrecedenceExpr { ref levels } => {
265 let mut nullable = false;
266
267 for level in levels {
268 for operator in &level.operators {
269 let mut operator_nullable = true;
270 for element in &operator.elements {
271 operator_nullable &= self.walk_expr(&element.expr);
272 }
273 nullable |= operator_nullable;
274 }
275 }
276
277 nullable
278 }
279
280 | LiteralExpr(_)
281 | PatternExpr(_)
282 | MethodExpr(_, _)
283 | CustomExpr(_)
284 | FailExpr(_)
285 | MarkerExpr(_) => false,
286
287 PositionExpr => true,
288 }
289 }
290}