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