use crate::collections::Set;
use crate::grammar::repr::*;
use crate::lr1::core::*;
use crate::lr1::first::FirstSets;
use crate::lr1::lookahead::*;
use crate::lr1::state_graph::StateGraph;
use super::table::{ConflictIndex, LaneTable};
pub struct LaneTracer<'trace, 'grammar: 'trace, L: Lookahead + 'trace> {
states: &'trace [State<'grammar, L>],
first_sets: &'trace FirstSets,
state_graph: &'trace StateGraph,
table: LaneTable<'grammar>,
start_nt: NonterminalString,
}
impl<'trace, 'grammar, L: Lookahead> LaneTracer<'trace, 'grammar, L> {
pub fn new(
grammar: &'grammar Grammar,
start_nt: NonterminalString,
states: &'trace [State<'grammar, L>],
first_sets: &'trace FirstSets,
state_graph: &'trace StateGraph,
conflicts: usize,
) -> Self {
LaneTracer {
states,
first_sets,
state_graph,
start_nt,
table: LaneTable::new(grammar, conflicts),
}
}
pub fn into_table(self) -> LaneTable<'grammar> {
self.table
}
pub fn start_trace(
&mut self,
state: StateIndex,
conflict: ConflictIndex,
action: Action<'grammar>,
) {
let mut visited_set = Set::default();
match action {
Action::Shift(term, _) => {
let mut token_set = TokenSet::new();
token_set.insert(Token::Terminal(term));
self.table.add_lookahead(state, conflict, &token_set);
}
Action::Reduce(prod) => {
let item = Item::lr0(prod, prod.symbols.len());
self.continue_trace(state, conflict, item, &mut visited_set);
}
}
}
fn continue_trace(
&mut self,
state: StateIndex,
conflict: ConflictIndex,
item: LR0Item<'grammar>,
visited: &mut Set<(StateIndex, LR0Item<'grammar>)>,
) {
if !visited.insert((state, item)) {
return;
}
if item.index > 0 {
let shifted_symbol = item.production.symbols[item.index - 1].clone();
let unshifted_item = Item {
index: item.index - 1,
..item
};
let predecessors = self.state_graph.predecessors(state, shifted_symbol);
for predecessor in predecessors {
self.table.add_successor(predecessor, state);
self.continue_trace(predecessor, conflict, unshifted_item, visited);
}
return;
}
let state_items = &self.states[state.0].items.vec;
let nonterminal = &item.production.nonterminal;
if *nonterminal == self.start_nt {
self.table.add_lookahead(state, conflict, &TokenSet::eof());
}
for pred_item in state_items
.iter()
.filter(|i| i.can_shift_nonterminal(nonterminal))
{
let symbol_sets = pred_item.symbol_sets();
let mut first = self.first_sets.first0(symbol_sets.suffix);
let derives_epsilon = first.take_eof();
self.table.add_lookahead(state, conflict, &first);
if derives_epsilon {
self.continue_trace(state, conflict, pred_item.to_lr0(), visited);
}
}
}
}