topdown/
chainl.rs

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