lalr 0.0.2

a library for creating LALR(1) parsers from context-free grammars
Documentation
use super::*;
use std::collections::BTreeMap;

macro_rules! map {
    ($($l: expr => $r: expr),*) => ({
        let mut r = BTreeMap::new();
        $(r.insert($l, $r);)*
        r
    });
}

macro_rules! coll {
    ($($x: expr),*) => (vec!($($x),*).into_iter().collect());
    () => (None.into_iter().collect());
}

fn rhs<T, N, A>(syms: Vec<Symbol<T, N>>, act: A) -> Rhs<T, N, A> {
    Rhs {
        syms: syms,
        act: act,
    }
}

fn grammar() -> Grammar<&'static str, &'static str, ()> {
    Grammar {
        rules: map![
            "S" => vec![
                rhs(vec![Nonterminal("N")], ()),
            ],
            "N" => vec![
                rhs(vec![Nonterminal("V"), Terminal("="), Nonterminal("E")], ()),
                rhs(vec![Nonterminal("E")], ()),
            ],
            "E" => vec![
                rhs(vec![Nonterminal("V")], ()),
            ],
            "V" => vec![
                rhs(vec![Terminal("x")], ()),
                rhs(vec![Terminal("*"), Nonterminal("E")], ()),
            ]
        ],
        start: "S"
    }
}

static S: &'static &'static str = &"S";
static N: &'static &'static str = &"N";
static E: &'static &'static str = &"E";
static V: &'static &'static str = &"V";
static X: &'static &'static str = &"x";
static STAR: &'static &'static str = &"*";
static EQ: &'static &'static str = &"=";

#[test]
fn test_first_sets() {
    let g = grammar();
    assert_eq!(g.first_sets(), map! {
        S => (coll![X, STAR], false),
        N => (coll![X, STAR], false),
        E => (coll![X, STAR], false),
        V => (coll![X, STAR], false)
    });
}

#[test]
fn test_follow_sets() {
    let g = grammar();
    assert_eq!(g.follow_sets(g.first_sets()), map! {
        S => (coll![], true),
        N => (coll![], true),
        E => (coll![EQ], true),
        V => (coll![EQ], true)
    });
}

#[test]
fn test_extended_grammar() {
    let g = grammar();
    let state_machine = g.lr0_state_machine();
    let extended = state_machine.extended_grammar();
    assert_eq!(extended.start.1, S);
    // Too difficult to test the actual output so just do a sanity check
    assert_eq!(extended.rules.len(), 8);
    let total: usize = extended.rules.values().map(|rhss| rhss.len()).fold(0, |x, y| x + y);
    assert_eq!(total, 12);
}

#[test]
fn test_lalr1() {
    let g = grammar();
    // FIXME: write a test
    assert!(g.lalr1(|_, _| true, |_, _| 0).is_ok());
}