pest_meta/optimizer/
skipper.rs
1use std::collections::HashMap;
11
12use crate::ast::*;
13
14pub fn skip(rule: Rule, map: &HashMap<String, Expr>) -> Rule {
15 fn populate_choices(
16 expr: Expr,
17 map: &HashMap<String, Expr>,
18 mut choices: Vec<String>,
19 ) -> Option<Expr> {
20 match expr {
21 Expr::Choice(lhs, rhs) => {
22 if let Expr::Str(string) = *lhs {
23 choices.push(string);
24 populate_choices(*rhs, map, choices)
25 } else if let Expr::Ident(name) = *lhs {
26 if let Some(Expr::Skip(mut inlined_choices)) = map
28 .get(&name)
29 .and_then(|expr| populate_choices(expr.clone(), map, vec![]))
30 {
31 choices.append(&mut inlined_choices);
32 populate_choices(*rhs, map, choices)
33 } else {
34 None
35 }
36 } else {
37 None
38 }
39 }
40 Expr::Str(string) => {
41 choices.push(string);
42 Some(Expr::Skip(choices))
43 }
44 Expr::Ident(name) => map
46 .get(&name)
47 .and_then(|expr| populate_choices(expr.clone(), map, choices)),
48 _ => None,
49 }
50 }
51
52 let Rule { name, ty, expr } = rule;
53 Rule {
54 name,
55 ty,
56 expr: if ty == RuleType::Atomic {
57 expr.map_top_down(|expr| {
58 if let Expr::Rep(expr) = expr.clone() {
59 if let Expr::Seq(lhs, rhs) = *expr {
60 if let (Expr::NegPred(expr), Expr::Ident(ident)) = (*lhs, *rhs) {
61 if ident == "ANY" {
62 if let Some(expr) = populate_choices(*expr, map, vec![]) {
63 return expr;
64 }
65 }
66 }
67 }
68 };
69
70 expr
71 })
72 } else {
73 expr
74 },
75 }
76}