mod item_relation;
mod phase0;
mod phase1;
mod phase2;
mod phase3;
mod phase4;
pub(crate) use self::{
phase0::Phase0, phase1::Phase1, phase2::Phase2, phase3::Phase3, phase4::Phase4,
};
#[cfg(test)]
mod tests {
use crate::{
input::{
Grammar, Node, Symbol,
Symbol::{Node as N, Token as T},
},
lr::{LRState, LRTable, LALR},
GotoIdx, StateIdx,
};
pub(super) use crate::test_common::{
nodes::{N1, N2, N3, N4, N5, N6, N7, N8, START},
tokens::{T1, T2, T3, T4, T5},
};
pub(super) fn get_state<'a, Kind>(
table: &'a LRTable<Kind>,
path_from_start: &[Symbol],
) -> Option<(StateIdx<Kind>, &'a LRState<Kind>)> {
let mut state_index = *table.starting_states.get(&START)?;
let mut state = table.get_state(state_index)?;
for symbol in path_from_start {
state_index = *state.transitions.get(symbol)?;
state = table.get_state(state_index)?;
}
Some((state_index, state))
}
pub(super) fn get_goto(
goto_data: &GotoIndicesData<LALR>,
state_index: StateIdx<LALR>,
node: Node,
) -> Option<GotoIdx> {
for ((&s, &index_node), g) in goto_data
.from_state
.iter()
.zip(&goto_data.symbol)
.zip(goto_data.get_all_goto_indices())
{
if s == state_index && index_node == node {
return Some(g);
}
}
None
}
macro_rules! get_gotos {
(in $table:expr;
$(
$($from_state:ident => $path_symbol:expr)? => $state_name:ident {
$($node:ident: $goto:ident),* $(,)?
};
)*
) => {
use std::collections::HashMap;
let (goto_data, _) = $crate::ielr::Phase0::compute_goto_idx_tables(&$table);
let mut len = 0;
let mut state_indices = HashMap::new();
$(
let (state_index, state) = get_gotos!(@if_empty $($from_state)? {
$crate::ielr::tests::get_state(&$table, &[]).unwrap()
} else {
$(
let state_index = $table
.get_state(state_indices[stringify!($from_state)])
.unwrap()
.transitions[&$path_symbol];
let state = $table.get_state(state_index).unwrap();
(state_index, state)
)?
});
state_indices.insert(stringify!($state_name), state_index);
$(
let $goto = if state.uses_precedence {
unreachable!("this macro cannot handle grammars with precedence annotations")
} else {
$crate::ielr::tests::get_goto(&goto_data, state_index, $node).unwrap()
};
len += 1;
)*
let all_nodes = [$($node),*];
assert!(
state
.all_items()
.iter()
.all(|item| item.index > 0 || all_nodes.contains(&item.prod_idx.lhs))
);
)*
assert_eq!([$($($goto,)*)*].into_iter().collect::<$crate::structures::Set<$crate::GotoIdx>>().len(), len);
};
(@if_empty { $($then:tt)* } else { $($otherwise:tt)* }) => {
{$($then)*}
};
(@if_empty $x:tt { $($then:tt)* } else { $($otherwise:tt)* }) => {
{$($otherwise)*}
};
}
pub(super) use get_gotos;
use super::phase0::GotoIndicesData;
pub(super) fn grammar_1() -> Grammar {
let mut grammar = Grammar::new();
for (lhs, rhs) in [
(START, vec![T(T1), N(N1), N(N2), N(N6)]),
(START, vec![T(T2), N(N4)]),
(N1, vec![T(T2)]),
(N2, vec![N(N3)]),
(N3, vec![]),
(N3, vec![T(T3)]),
(N4, vec![N(N5), N(N3)]),
(N5, vec![T(T4)]),
(N6, vec![T(T1), T(T2)]),
(N6, vec![T(T4)]),
] {
grammar.add_production(lhs, rhs).unwrap();
}
grammar
}
pub(super) fn grammar_2() -> Grammar {
let mut grammar = Grammar::new();
for (lhs, rhs) in [
(START, vec![T(T1), N(N1), N(N2), N(N6)]),
(N1, vec![N(N3)]),
(N2, vec![T(T2), N(N4), N(N5)]),
(N2, vec![T(T2), N(N6)]),
(N3, vec![]),
(N3, vec![N(N7)]),
(N4, vec![T(T1)]),
(N5, vec![]),
(N5, vec![T(T5)]),
(N6, vec![N(N7)]),
(N7, vec![N(N8), N(N3)]),
(N7, vec![T(T3)]),
(N8, vec![T(T1)]),
] {
grammar.add_production(lhs, rhs).unwrap();
}
grammar
}
pub(super) fn grammar_3() -> Grammar {
let mut grammar = Grammar::new();
for (lhs, rhs) in [
(START, vec![T(T1), T(T2), N(N1)]),
(START, vec![T(T1), T(T2), N(N2)]),
(N1, vec![T(T3)]),
(N2, vec![T(T3)]),
] {
grammar.add_production(lhs, rhs).unwrap();
}
grammar
}
}