# topdown-rs

A top-down parsing library for Rust.

## Example

```rust
#![allow(unused_variables)]
#![allow(unstable)]
#[macro_use]
extern crate topdown;
use topdown::{CharSeq, skip, Parser, wrap, choice, ParserResult, re, chainl};
use topdown::ParserResult::{Succ, Error, Fail};

fn op1<'a>(cs: &mut CharSeq) -> ParserResult<Box<Fn(isize, isize) -> isize + 'a>> {
    return run_parser!(
        cs >> &re("\\+|-"), |o|
            match o.as_slice() {
                "+" => (Box::new(|&: a:isize, b:isize| a+b)) as Box<Fn(isize, isize) -> isize + 'a>,
                "-" => (Box::new(|&: a:isize, b:isize| a-b)) as Box<Fn(isize, isize) -> isize + 'a>,
                _ => panic!(o)
            }
        )
}

fn op2<'a>(cs: &mut CharSeq) -> ParserResult<Box<Fn(isize, isize) -> isize + 'a>> {
    return run_parser!(
        cs >> &re("\\*|/|%"), |o| 
        match o.as_slice() {
            "*" => (Box::new(|&: a:isize, b:isize| a*b)) as Box<Fn(isize, isize) -> isize + 'a>,
            "/" => (Box::new(|&: a:isize, b:isize| a/b)) as Box<Fn(isize, isize) -> isize + 'a>,
            "%" => (Box::new(|&: a:isize, b:isize| a%b)) as Box<Fn(isize, isize) -> isize + 'a>,
            _ => panic!(o)
        }  
    )
}

fn digit(cs: &mut CharSeq) -> ParserResult<isize> {
    run_parser!(cs >> &re("-?[1-9][0-9]*"), |x| x.as_slice().parse().unwrap())
}

#[allow(unused_variables)]
fn factor(cs: &mut CharSeq) -> ParserResult<isize> {
    run_parser!(
        cs >> &"(", |i|
        &wrap(expr), |e|
        &")", |i2| e
    )
}

fn term(cs: &mut CharSeq) -> ParserResult<isize> {
    let f = wrap(factor);
    let d = wrap(digit);
    let l = [&d as &Parser<isize>, &f as &Parser<isize>];
    let c = choice(&l);
    let o = wrap(op2);
    let cl = chainl(&c, &o, false);
    cs.accept(&cl)
}

fn expr(cs: &mut CharSeq) -> ParserResult<isize> {
    let t = wrap(term);
    let o = wrap(op1);
    let cl = chainl(&t, &o, false);
    return cs.accept(&cl);
}

fn calc(e: &str) {
    let mut cs = CharSeq::new(e, "");
    let skip = skip(" ");
    cs.add_hook(&skip);
    match cs.accept(&wrap(expr)) {
        Succ(x) => {
            if !cs.eof() {
                println!("error: {}", e);
            } else {
                println!("{}={}", e, x)
            }
        },
        Fail(m, l) => println!("error: {}", e),
        Error(m, l) => println!("error: {}", e)
    }
}

fn main() {
    calc("1 + 2 - 3 * 4");
    calc("1 + (2 - 3) * 4");
    calc("1 + (2 - 3)) * 4");
    calc("1 + (2 - 3 * 4");
}
```

## License

MIT