topdown/
chainr.rs

1use super::{CharSeq, ParserResult, Parser, Succ, Fail, Error};
2
3pub struct Chainr<'a, T:'a> {
4    term: &'a (Parser<T>+'a),
5    operator: &'a (Parser<Box<Fn(T, T) -> T + 'a>>+'a),
6    allow_trailing_operator: bool
7}
8
9pub fn chainr<'a, T>(p: &'a (Parser<T>+'a), o: &'a (Parser<Box<Fn(T, T) -> T + 'a>> + 'a), a: bool) -> Chainr<'a, T> {
10    return Chainr{term: p, operator: o, allow_trailing_operator: a};
11}
12
13impl<'a, T> Parser<T> for Chainr<'a, T> {
14    #[allow(unused_variables)]
15    fn _parse(&self, cs: &mut CharSeq) -> ParserResult<T> {
16        match cs.accept(self.term) {
17            Succ(l) => {
18                match cs.accept(self.operator) {
19                    Succ(o) => match cs.accept(self) {
20                        Succ(r) => return Succ(o(l, r)),
21                        Fail(m, lo) => {
22                            if self.allow_trailing_operator {
23                                return Succ(l)
24                            } else {
25                                return Fail(m, lo)
26                            }
27                        },
28                        Error(m, l) => return Error(m, l)
29                    },
30                    Fail(m, lo) => return Succ(l),
31                    Error(m, lo) => return Succ(l),
32                }
33            },
34            Fail(m, l) => return Fail(m, l),
35            Error(m, l) => return Error(m, l)
36        }
37    }
38}
39
40#[cfg(test)]
41#[allow(unused_variables)]
42#[allow(unused_imports)]
43mod tests {
44    use super::chainr;
45    use super::super::{CharSeq, re, ParserResult, Parser, Succ, Fail, Error};
46
47    struct Op<'a>;
48
49    impl<'a> Parser<Box<Fn(isize, isize) -> isize + 'a>> for Op<'a> {
50        fn _parse(&self, cs: &mut CharSeq) -> ParserResult<Box<Fn(isize, isize) -> isize + 'a>> {
51            return cs.accept(&re("\\+|-"))
52                .map(|o| {
53                        if o == "+" {
54                             return (Box::new(|a:isize, b:isize|  a+b)) as Box<Fn(isize, isize) -> isize + 'a>;
55                        } else {
56                             return (Box::new(|a:isize, b:isize|  a-b)) as Box<Fn(isize, isize) -> isize + 'a>;
57                        }
58                });
59        }
60    }
61
62    struct Expr;
63
64    impl Parser<isize> for Expr {
65        fn _parse(&self, cs: &mut CharSeq) -> ParserResult<isize> {
66            return cs.accept(&re("[1-9][0-9]*")).map(|x| x.as_slice().parse().unwrap());
67        }
68    }
69
70    #[test]
71    fn test_chainr1() {
72        let mut cs = CharSeq::new("1-5", "<mem>");
73        let term = Expr;
74        let op = Op;
75        let expr = chainr(&term, &op, false);
76        match cs.accept(&expr) {
77            Succ(c) => assert_eq!(c, -4),
78            Fail(a, b) => assert!(false, "failed"),
79            Error(a, b) => assert!(false, "error")
80        }
81    }
82
83
84    #[test]
85    fn test_chainr2() {
86        let mut cs = CharSeq::new("1-5-6", "<mem>");
87        let term = Expr;
88        let op = Op;
89        let expr = chainr(&term, &op, false);
90        match cs.accept(&expr) {
91            Succ(c) => assert_eq!(c, 2),
92            Fail(a, b) => assert!(false, "failed"),
93            Error(a, b) => assert!(false, "error")
94        }
95    }
96
97
98    #[test]
99    fn test_chainr3() {
100        let mut cs = CharSeq::new("30+5-6+12", "<mem>");
101        let term = Expr;
102        let op = Op;
103        let expr = chainr(&term, &op, false);
104        match cs.accept(&expr) {
105            Succ(c) => assert_eq!(c, 17),
106            Fail(a, b) => assert!(false, "failed"),
107            Error(a, b) => assert!(false, "error")
108        }
109    }
110
111
112    #[test]
113    fn test_chainr4() {
114        let mut cs = CharSeq::new("30+5-", "<mem>");
115        let term = Expr;
116        let op = Op;
117        let expr = chainr(&term, &op, true);
118        match cs.accept(&expr) {
119            Succ(c) => assert_eq!(c, 35),
120            Fail(a, b) => assert!(false, "failed"),
121            Error(a, b) => assert!(false, "error")
122        }
123    }
124}
125