use crate::collections::{map, Map};
use crate::grammar::repr::*;
use crate::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.clone()).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(ref t) => {
result.insert(Token::Terminal(t.clone()));
return result;
}
Symbol::Nonterminal(ref 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
}
}