1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use super::{CharSeq, ParserResult, Parser, Succ, Fail, Error};

pub struct Chainr<'a, T:'a> {
    term: &'a (Parser<T>+'a),
    operator: &'a (Parser<Box<Fn(T, T) -> T + 'a>>+'a),
    allow_trailing_operator: bool
}

pub fn chainr<'a, T>(p: &'a (Parser<T>+'a), o: &'a (Parser<Box<Fn(T, T) -> T + 'a>> + 'a), a: bool) -> Chainr<'a, T> {
    return Chainr{term: p, operator: o, allow_trailing_operator: a};
}

impl<'a, T> Parser<T> for Chainr<'a, T> {
    #[allow(unused_variables)]
    fn _parse(&self, cs: &mut CharSeq) -> ParserResult<T> {
        match cs.accept(self.term) {
            Succ(l) => {
                match cs.accept(self.operator) {
                    Succ(o) => match cs.accept(self) {
                        Succ(r) => return Succ(o(l, r)),
                        Fail(m, lo) => {
                            if self.allow_trailing_operator {
                                return Succ(l)
                            } else {
                                return Fail(m, lo)
                            }
                        },
                        Error(m, l) => return Error(m, l)
                    },
                    Fail(m, lo) => return Succ(l),
                    Error(m, lo) => return Succ(l),
                }
            },
            Fail(m, l) => return Fail(m, l),
            Error(m, l) => return Error(m, l)
        }
    }
}

#[cfg(test)]
#[allow(unused_variables)]
#[allow(unused_imports)]
mod tests {
    use super::chainr;
    use super::super::{CharSeq, re, ParserResult, Parser, Succ, Fail, Error};

    struct Op<'a>;

    impl<'a> Parser<Box<Fn(isize, isize) -> isize + 'a>> for Op<'a> {
        fn _parse(&self, cs: &mut CharSeq) -> ParserResult<Box<Fn(isize, isize) -> isize + 'a>> {
            return cs.accept(&re("\\+|-"))
                .map(|o| {
                        if o == "+" {
                             return (Box::new(|a:isize, b:isize|  a+b)) as Box<Fn(isize, isize) -> isize + 'a>;
                        } else {
                             return (Box::new(|a:isize, b:isize|  a-b)) as Box<Fn(isize, isize) -> isize + 'a>;
                        }
                });
        }
    }

    struct Expr;

    impl Parser<isize> for Expr {
        fn _parse(&self, cs: &mut CharSeq) -> ParserResult<isize> {
            return cs.accept(&re("[1-9][0-9]*")).map(|x| x.as_slice().parse().unwrap());
        }
    }

    #[test]
    fn test_chainr1() {
        let mut cs = CharSeq::new("1-5", "<mem>");
        let term = Expr;
        let op = Op;
        let expr = chainr(&term, &op, false);
        match cs.accept(&expr) {
            Succ(c) => assert_eq!(c, -4),
            Fail(a, b) => assert!(false, "failed"),
            Error(a, b) => assert!(false, "error")
        }
    }


    #[test]
    fn test_chainr2() {
        let mut cs = CharSeq::new("1-5-6", "<mem>");
        let term = Expr;
        let op = Op;
        let expr = chainr(&term, &op, false);
        match cs.accept(&expr) {
            Succ(c) => assert_eq!(c, 2),
            Fail(a, b) => assert!(false, "failed"),
            Error(a, b) => assert!(false, "error")
        }
    }


    #[test]
    fn test_chainr3() {
        let mut cs = CharSeq::new("30+5-6+12", "<mem>");
        let term = Expr;
        let op = Op;
        let expr = chainr(&term, &op, false);
        match cs.accept(&expr) {
            Succ(c) => assert_eq!(c, 17),
            Fail(a, b) => assert!(false, "failed"),
            Error(a, b) => assert!(false, "error")
        }
    }


    #[test]
    fn test_chainr4() {
        let mut cs = CharSeq::new("30+5-", "<mem>");
        let term = Expr;
        let op = Op;
        let expr = chainr(&term, &op, true);
        match cs.accept(&expr) {
            Succ(c) => assert_eq!(c, 35),
            Fail(a, b) => assert!(false, "failed"),
            Error(a, b) => assert!(false, "error")
        }
    }
}