topdown-rs 0.1.0

A top-down parsing library
use super::{CharSeq, ParserResult, Parser, ParserHook};
use std::cell::RefCell;

struct FunctionWrapper<'a, T> {
    func: |&mut CharSeq|: 'a -> ParserResult<T>
}

impl<'a, T> FunctionWrapper<'a, T> {
    fn call(&mut self, cs: &mut CharSeq) -> ParserResult<T> {
        (self.func)(cs)
    }
}

pub struct WrappedParser<'a, T:'a> {
    func: RefCell<FunctionWrapper<'a, T>>
}


pub fn wrap<'a, T>(f: |&mut CharSeq|: 'a -> ParserResult<T>) -> WrappedParser<'a T> {
    WrappedParser{func: RefCell::new(FunctionWrapper{func: f})}
}

impl<'a, T> Parser<T> for WrappedParser<'a T> {
    fn _parse(&self, cs: &mut CharSeq) -> ParserResult<T> {
        self.func.borrow_mut().call(cs)
    }
}

impl<'a, T> ParserHook for WrappedParser<'a T> {
    fn hook(&self, cs: &mut CharSeq) {
        self.func.borrow_mut().call(cs);
    }
}

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

    fn some_parser(cs: &mut CharSeq) -> ParserResult<Vec<String>> {
        let x = "abc";
        let y = "def";
        let z = "ghi";
        cs.accept(&x).and_then(|a|
            cs.accept(&y).and_then(|b|
            cs.accept(&z).map(|c| {
                vec!(a.to_string(), b.to_string(), c.to_string())
            }
        )))
    }

    #[test]
    fn test_wrap1() {
        let mut cs = CharSeq::new("abcdefghi", "");
        let w = wrap(some_parser);
        match cs.accept(&w) {
            Succ(x) => assert_eq!(x, vec!("abc".to_string(), "def".to_string(), "ghi".to_string())),
            Fail(m, l) => assert!(false, "failed"),
            Error(m, l) => assert!(false, "error")
        }
    }

    #[test]
    fn test_wrap2() {
        let mut cs = CharSeq::new("abcdefghixxxabcdefghi", "");
        let w = wrap(some_parser);
        cs.add_hook(&w);
        match cs.accept(&"xxx") {
            Succ(x) => assert_eq!(x.as_slice(), "xxx"),
            Fail(m, l) => assert!(false, "failed"),
            Error(m, l) => assert!(false, "error")
        }
    }
}