• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // pest. The Elegant Parser
2 // Copyright (c) 2018 Dragoș Tiselice
3 //
4 // Licensed under the Apache License, Version 2.0
5 // <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
6 // license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. All files in the project carrying such notice may not be copied,
8 // modified, or distributed except according to those terms.
9 
10 use std::collections::HashMap;
11 
12 use crate::ast::*;
13 
skip(rule: Rule, map: &HashMap<String, Expr>) -> Rule14 pub 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                     // Try inlining rule in choices
27                     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             // Try inlining single rule
45             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 }
77