use adze_glr_core::{Action, ParseError, ParseForest, ParseTable};
use adze_glr_core::{parse_forest::ErrorMeta, parse_forest::ForestAlternative};
use adze_ir::{RuleId, StateId, SymbolId};
use std::collections::HashMap;
pub struct GLRParser {
table: ParseTable,
}
impl GLRParser {
pub fn new(table: ParseTable) -> Self {
Self { table }
}
pub fn parse(&mut self, tokens: &[SymbolId]) -> Result<ParseForest, ParseError> {
use adze_glr_core::ForestNode;
let mut forest = ParseForest {
roots: vec![],
nodes: HashMap::new(),
grammar: self.table.grammar.clone(),
source: String::new(),
next_node_id: 0,
};
let mut input: Vec<SymbolId> = tokens.to_vec();
input.push(self.table.eof_symbol);
let mut stacks = vec![ParseStack::new(self.table.initial_state)];
for (position, symbol) in input.iter().enumerate() {
let mut reduced = Vec::new();
for stack in stacks.drain(..) {
reduced.extend(self.reduce_all(stack, *symbol, &mut forest));
}
let mut new_stacks = Vec::new();
let mut accepted = false;
for stack in reduced {
let actions = self.get_actions(stack.current_state(), *symbol);
if actions.is_empty() {
continue;
}
for action in actions {
self.handle_terminal_action(
&stack,
&action,
*symbol,
position,
&mut new_stacks,
&mut forest,
&mut accepted,
);
}
}
if new_stacks.is_empty() && !accepted {
return Err(ParseError::Failed(format!(
"Parse error at token position {}",
position
)));
}
stacks = new_stacks;
}
if forest.roots.is_empty() {
Err(ParseError::Incomplete)
} else {
Ok(forest)
}
}
pub fn get_actions(&self, state: StateId, symbol: SymbolId) -> Vec<Action> {
let state_idx = state.0 as usize;
let symbol_idx = self
.table
.symbol_to_index
.get(&symbol)
.copied()
.unwrap_or(0);
if state_idx < self.table.action_table.len()
&& symbol_idx < self.table.action_table[0].len()
{
self.table.action_table[state_idx][symbol_idx].clone()
} else {
vec![]
}
}
fn handle_terminal_action(
&self,
stack: &ParseStack,
action: &Action,
symbol: SymbolId,
position: usize,
new_stacks: &mut Vec<ParseStack>,
forest: &mut ParseForest,
accepted: &mut bool,
) {
match action {
Action::Shift(next_state) => {
let node_id = self.create_leaf(symbol, position, forest);
let mut new_stack = stack.clone();
new_stack.states.push(*next_state);
new_stack.nodes.push(node_id);
new_stacks.push(new_stack);
}
Action::Accept => {
if let Some(&root_id) = stack.nodes.last() {
if let Some(node) = forest.nodes.get(&root_id).cloned() {
forest.roots.push(node);
*accepted = true;
}
}
}
Action::Fork(fork_actions) => {
for fork_action in fork_actions {
self.handle_terminal_action(
stack,
fork_action,
symbol,
position,
new_stacks,
forest,
accepted,
);
}
}
_ => {}
}
}
fn reduce_all(
&self,
stack: ParseStack,
lookahead: SymbolId,
forest: &mut ParseForest,
) -> Vec<ParseStack> {
let actions = self.get_actions(stack.current_state(), lookahead);
let mut results = Vec::new();
let mut reduced_any = false;
for action in actions {
match action {
Action::Reduce(rule_id) => {
reduced_any = true;
if let Some(reduced) = self.apply_reduction(stack.clone(), rule_id, forest) {
results.extend(self.reduce_all(reduced, lookahead, forest));
}
}
Action::Fork(fork_actions) => {
for a in fork_actions {
if let Action::Reduce(rule_id) = a {
reduced_any = true;
if let Some(reduced) =
self.apply_reduction(stack.clone(), rule_id, forest)
{
results.extend(self.reduce_all(reduced, lookahead, forest));
}
}
}
}
_ => {}
}
}
if !reduced_any {
results.push(stack);
}
results
}
fn apply_reduction(
&self,
mut stack: ParseStack,
rule_id: RuleId,
forest: &mut ParseForest,
) -> Option<ParseStack> {
let rule = self.table.rules.get(rule_id.0 as usize)?;
let rhs_len = rule.rhs_len as usize;
let children = stack.pop(rhs_len);
let (start, end) = if let (Some(first), Some(last)) = (children.first(), children.last()) {
let s = forest.nodes.get(first)?.span.0;
let e = forest.nodes.get(last)?.span.1;
(s, e)
} else {
(0, 0)
};
let base_state = stack.current_state();
let goto_state = self.get_goto(base_state, rule.lhs)?;
let node_id = forest.next_node_id;
forest.next_node_id += 1;
forest.nodes.insert(
node_id,
ForestNode {
id: node_id,
symbol: rule.lhs,
span: (start, end),
alternatives: vec![ForestAlternative {
children: children.clone(),
}],
error_meta: ErrorMeta::default(),
},
);
stack.states.push(goto_state);
stack.nodes.push(node_id);
Some(stack)
}
fn get_goto(&self, state: StateId, symbol: SymbolId) -> Option<StateId> {
let row = self.table.goto_table.get(state.0 as usize)?;
let col = match self.table.goto_indexing {
adze_glr_core::GotoIndexing::NonterminalMap => {
*self.table.nonterminal_to_index.get(&symbol)?
}
adze_glr_core::GotoIndexing::DirectSymbolId => symbol.0 as usize,
};
row.get(col).copied()
}
fn create_leaf(&self, symbol: SymbolId, position: usize, forest: &mut ParseForest) -> usize {
let node_id = forest.next_node_id;
forest.next_node_id += 1;
forest.nodes.insert(
node_id,
adze_glr_core::ForestNode {
id: node_id,
symbol,
span: (position, position + 1),
alternatives: vec![ForestAlternative { children: vec![] }],
error_meta: ErrorMeta::default(),
},
);
node_id
}
}
#[derive(Clone)]
pub struct ParseStack {
states: Vec<StateId>,
nodes: Vec<usize>,
}
impl ParseStack {
pub fn new(initial_state: StateId) -> Self {
Self {
states: vec![initial_state],
nodes: vec![],
}
}
pub fn current_state(&self) -> StateId {
*self.states.last().unwrap_or(&StateId(0))
}
fn pop(&mut self, n: usize) -> Vec<usize> {
self.states.truncate(self.states.len().saturating_sub(n));
self.nodes.split_off(self.nodes.len().saturating_sub(n))
}
}