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 crate::ast::*;
11 
unroll(rule: Rule) -> Rule12 pub fn unroll(rule: Rule) -> Rule {
13     let Rule { name, ty, expr } = rule;
14     Rule {
15         name,
16         ty,
17         expr: expr.map_bottom_up(|expr| match expr {
18             #[cfg(not(feature = "grammar-extras"))]
19             Expr::RepOnce(expr) => Expr::Seq(expr.clone(), Box::new(Expr::Rep(expr))),
20             Expr::RepExact(expr, num) => (1..num + 1)
21                 .map(|_| *expr.clone())
22                 .rev()
23                 .fold(None, |rep, expr| match rep {
24                     None => Some(expr),
25                     Some(rep) => Some(Expr::Seq(Box::new(expr), Box::new(rep))),
26                 })
27                 .unwrap(),
28             Expr::RepMin(expr, min) => (1..min + 2)
29                 .map(|i| {
30                     if i <= min {
31                         *expr.clone()
32                     } else {
33                         Expr::Rep(expr.clone())
34                     }
35                 })
36                 .rev()
37                 .fold(None, |rep, expr| match rep {
38                     None => Some(expr),
39                     Some(rep) => Some(Expr::Seq(Box::new(expr), Box::new(rep))),
40                 })
41                 .unwrap(),
42             Expr::RepMax(expr, max) => (1..max + 1)
43                 .map(|_| Expr::Opt(expr.clone()))
44                 .rev()
45                 .fold(None, |rep, expr| match rep {
46                     None => Some(expr),
47                     Some(rep) => Some(Expr::Seq(Box::new(expr), Box::new(rep))),
48                 })
49                 .unwrap(),
50             Expr::RepMinMax(expr, min, max) => (1..max + 1)
51                 .map(|i| {
52                     if i <= min {
53                         *expr.clone()
54                     } else {
55                         Expr::Opt(expr.clone())
56                     }
57                 })
58                 .rev()
59                 .fold(None, |rep, expr| match rep {
60                     None => Some(expr),
61                     Some(rep) => Some(Expr::Seq(Box::new(expr), Box::new(rep))),
62                 })
63                 .unwrap(),
64             expr => expr,
65         }),
66     }
67 }
68