pub mod error;
mod lookahead;
mod state;
mod statistics;
pub use self::{
error::Error,
lookahead::Lookahead,
state::{Action, ActionTable, GotoTable, Item, State, StateIdx},
statistics::Statistics,
};
use crate::{grammar_data::GrammarData, indices::StateIdxRaw, input::Node, structures::Map};
use std::collections::BTreeMap;
#[derive(Debug, Clone)]
pub struct Table {
pub states: Vec<State>,
pub(crate) starting_states: BTreeMap<Node, StateIdx>,
}
impl Table {
pub fn get_starting_state(&self, node: Node) -> Option<StateIdx> {
self.starting_states.get(&node).copied()
}
pub fn get_all_starts(&self) -> impl Iterator<Item = (Node, StateIdx)> + '_ {
self.starting_states
.iter()
.map(|(node, state)| (*node, *state))
}
pub(crate) fn finish(&mut self, grammar_data: &GrammarData) {
let end_states = {
let mut end_states = Map::default();
for (node, &state) in &self.starting_states {
let state = &self.states[state];
let end_state = state.goto_table[node];
end_states.insert(end_state, *node);
}
end_states
};
for (state_idx, state) in self.states.iter_mut().enumerate() {
let state_idx = StateIdx(state_idx as StateIdxRaw);
let mut has_reduce_on_eof = false;
for item in &mut state.items {
let rhs = grammar_data.get_rhs(item.production).unwrap_or_default();
if item.index as usize != rhs.len() {
continue;
}
for &lookahead in &item.lookaheads {
has_reduce_on_eof |= lookahead == Lookahead::Eof;
state
.action_table
.insert(lookahead, Action::Reduce(item.production));
}
}
if let Some(&node) = end_states.get(&state_idx) {
if has_reduce_on_eof {
todo!("handle reduce/accept conflicts")
} else {
state
.action_table
.insert(Lookahead::Eof, Action::Accept(node));
}
}
}
}
}