use collections::{Map, map};
use grammar::repr::*;
use lr1::lookahead::{Token, TokenSet};
#[cfg(test)]
mod test;
#[derive(Clone)]
pub struct FirstSets {
map: Map<NonterminalString, TokenSet>
}
impl FirstSets {
pub fn new(grammar: &Grammar) -> FirstSets {
let mut this = FirstSets { map: map() };
let mut changed = true;
while changed {
changed = false;
for production in grammar.nonterminals.values()
.flat_map(|p| &p.productions) {
let nt = production.nonterminal;
let lookahead = this.first0(&production.symbols);
let first_set =
this.map.entry(nt).or_insert_with(|| TokenSet::new());
changed |= first_set.union_with(&lookahead);
}
}
this
}
pub fn first0<'s,I>(&self, symbols: I) -> TokenSet
where I: IntoIterator<Item=&'s Symbol>
{
let mut result = TokenSet::new();
for symbol in symbols {
match *symbol {
Symbol::Terminal(t) => {
result.insert(Token::Terminal(t));
return result;
}
Symbol::Nonterminal(nt) => {
let mut empty_prod = false;
match self.map.get(&nt) {
None => {
}
Some(set) => {
for lookahead in set.iter() {
match lookahead {
Token::EOF => {
empty_prod = true;
}
Token::Error | Token::Terminal(_) => {
result.insert(lookahead);
}
}
}
}
}
if !empty_prod {
return result;
}
}
}
}
result.insert(Token::EOF);
result
}
pub fn first1(&self, symbols: &[Symbol], lookahead: &TokenSet)
-> TokenSet
{
let mut set = self.first0(symbols);
let epsilon = set.take_eof();
if epsilon {
set.union_with(&lookahead);
}
set
}
}