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