use crate::data::*;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Table {
pub start: StateIndex,
pub terminals: Vec<DollarlessTerminalName>,
pub nonterminals: Vec<String>,
pub actions: Vec<Action>,
pub gotos: Vec<Goto>,
}
pub use machine::StateIndex;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Action {
Shift(StateIndex),
Reduce(usize),
Accept,
Err,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Goto {
State(StateIndex),
Err,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Quasiterminal<'a> {
Terminal(&'a DollarlessTerminalName),
Eof,
}
impl Table {
pub fn state_count(&self) -> usize {
self.actions.len() / (self.terminals.len() + 1)
}
pub fn action(&self, state_index: StateIndex, terminal: Quasiterminal) -> Action {
let i = self.action_index(state_index, terminal);
self.actions[i]
}
pub fn set_action(&mut self, state_index: StateIndex, terminal: Quasiterminal, val: Action) {
let i = self.action_index(state_index, terminal);
self.actions[i] = val;
}
fn action_index(
&self,
StateIndex(state_index): StateIndex,
quasiterminal: Quasiterminal,
) -> usize {
let quasiterminal_index = match quasiterminal {
Quasiterminal::Terminal(terminal) => self
.terminals
.iter()
.position(|t| t == terminal)
.expect("Terminal not found in table"),
Quasiterminal::Eof => self.terminals.len(),
};
if state_index >= self.state_count() {
let states = self.state_count();
panic!("State index {state_index} is too large. There are only {states} states.");
}
state_index * (self.terminals.len() + 1) + quasiterminal_index
}
pub fn goto(&self, state_index: StateIndex, nonterminal: &str) -> Goto {
let i = self.goto_index(state_index, nonterminal);
self.gotos[i]
}
pub fn set_goto(&mut self, state_index: StateIndex, nonterminal: &str, val: Goto) {
let i = self.goto_index(state_index, nonterminal);
self.gotos[i] = val;
}
fn goto_index(&self, StateIndex(state_index): StateIndex, nonterminal: &str) -> usize {
let nonterminal_index = self
.nonterminals
.iter()
.position(|t| t == nonterminal)
.expect("Nonterminal not found in table");
if state_index >= self.state_count() {
let states = self.state_count();
panic!("State index {state_index} is too large. There are only {states} states.");
}
state_index * self.nonterminals.len() + nonterminal_index
}
}