use super::{CharSeq, ParserResult, Parser, Succ, Fail, Error};
pub struct Chainr<'a, T> {
term: &'a (Parser<T>+'a),
operator: &'a (Parser< |T, T|: 'a -> T>+'a),
allow_trailing_operator: bool
}
pub fn chainr<'a, T>(p: &'a (Parser<T>+'a), o: &'a (Parser<|T, T|: 'a -> T>+'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<|int, int|:'a->int> for Op<'a> {
fn _parse(&self, cs: &mut CharSeq) -> ParserResult<|int, int|:'a->int> {
return cs.accept(&re("\\+|-"))
.map(|o|
if o.as_slice() == "+" {
return |a:int, b:int| a+b;
} else {
return |a:int, b:int| a-b
}
);
}
}
struct Expr;
impl Parser<int> for Expr {
fn _parse(&self, cs: &mut CharSeq) -> ParserResult<int> {
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")
}
}
}