use super::{CharSeq, ParserResult, Parser, Succ, Fail, Error};
pub struct Choice<'a, T: 'a> {
parsers: &'a [&'a(Parser<T>+'a)]
}
pub fn choice<'a, T>(p: &'a [&'a (Parser<T> + 'a)]) -> Choice<'a, T> {
return Choice{parsers: p};
}
impl<'a, T> Parser<T> for Choice<'a, T> {
#[allow(unused_variables)]
fn _parse(&self, cs: &mut CharSeq) -> ParserResult<T> {
let pos = cs.pos;
let mut vec = Vec::new();
for p in self.parsers.iter() {
match p.parse(cs) {
Succ(r) => return Succ(r),
Fail(m, l) => {
vec.push((m, l));
cs.pos = pos;
},
Error(m, l) => return Error(m, l)
}
}
vec.sort_by(|a, b| a.1.cmp(&b.1));
match vec.pop() {
Some(p) => {
cs.pos = pos;
let (m, l) = p;
return Fail(m, l);
},
None => ()
}
let r = cs.fail("");
cs.pos = pos;
return r;
}
}
#[cfg(test)]
#[allow(unused_variables)]
#[allow(unused_imports)]
mod tests {
use super::choice;
use super::super::{CharSeq, ParserResult, Parser, Succ, Fail, Error};
#[test]
fn test_choice1() {
let mut cs = CharSeq::new("abcdefghi", "<mem>");
let l: &[&Parser<String>] = &[&("abc"), &("def")];
let choice = choice(l);
match cs.accept(&choice) {
Succ(c) => assert!(c.as_slice() == "abc"),
Fail(a, b) => assert!(false, "failed"),
Error(a, b) => assert!(false, "error")
}
}
#[test]
fn test_choice2() {
let mut cs = CharSeq::new("abcdefghi", "<mem>");
let l: &[&Parser<String>] = &[&("ghi"), &("def")];
let choice = choice(l);
match cs.accept(&choice) {
Succ(c) => assert!(false, c),
Fail(a, b) => (),
Error(a, b) => assert!(false, "error")
}
}
#[test]
fn test_choice3() {
let mut cs = CharSeq::new("abcdefghi", "<mem>");
let a = S{fst: "abc", snd:"ghi"};
let b = S{fst: "abc", snd:"jkl"};
let l: &[&Parser<String>] = &[&a, &b];
let choice = choice(l);
match cs.accept(&choice) {
Succ(c) => assert!(false, c),
Fail(a, b) => {
assert_eq!(0, cs.pos);
assert_eq!(4, b.col);
},
Error(a, b) => assert!(false, "error")
}
}
struct S<'a> {
fst: &'a str,
snd: &'a str
}
impl<'a> Parser<String> for S<'a> {
fn _parse(&self, cs: &mut CharSeq) -> ParserResult<String> {
cs.accept(&self.fst).and_then(|x| cs.accept(&self.snd))
}
}
}