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
10use crate::ast::*;
11
12pub 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 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