use crate::collections::{map, Multimap};
use crate::grammar::repr::*;
use crate::kernel_set;
use crate::lr1::core::*;
use crate::lr1::first;
use crate::lr1::lane_table::*;
use crate::lr1::lookahead::*;
use crate::tls::Tls;
use std::env;
#[cfg(test)]
mod test;
fn build_lr1_states_legacy<'grammar>(
grammar: &'grammar Grammar,
start: NonterminalString,
) -> LR1Result<'grammar> {
let eof = TokenSet::eof();
let mut lr1: LR<'grammar, TokenSet> = LR::new(grammar, start, eof);
lr1.set_permit_early_stop(true);
lr1.build_states()
}
type ConstructionFunction<'grammar> =
fn(&'grammar Grammar, NonterminalString) -> LR1Result<'grammar>;
pub fn use_lane_table() -> bool {
match env::var("LALRPOP_LANE_TABLE") {
Ok(ref s) => s != "disabled",
_ => true,
}
}
pub fn build_lr1_states<'grammar>(
grammar: &'grammar Grammar,
start: NonterminalString,
) -> LR1Result<'grammar> {
let (method_name, method_fn) = if use_lane_table() {
("lane", build_lane_table_states as ConstructionFunction)
} else {
("legacy", build_lr1_states_legacy as ConstructionFunction)
};
profile! {
&Tls::session(),
format!("LR(1) state construction ({})", method_name),
{
method_fn(grammar, start)
}
}
}
pub fn build_lr0_states<'grammar>(
grammar: &'grammar Grammar,
start: NonterminalString,
) -> Result<Vec<LR0State<'grammar>>, LR0TableConstructionError<'grammar>> {
let lr1 = LR::new(grammar, start, Nil);
lr1.build_states()
}
pub struct LR<'grammar, L: LookaheadBuild> {
grammar: &'grammar Grammar,
first_sets: first::FirstSets,
start_nt: NonterminalString,
start_lookahead: L,
permit_early_stop: bool,
}
impl<'grammar, L: LookaheadBuild> LR<'grammar, L> {
fn new(grammar: &'grammar Grammar, start_nt: NonterminalString, start_lookahead: L) -> Self {
LR {
grammar,
first_sets: first::FirstSets::new(grammar),
start_nt,
start_lookahead,
permit_early_stop: false,
}
}
fn set_permit_early_stop(&mut self, v: bool) {
self.permit_early_stop = v;
}
fn build_states(&self) -> Result<Vec<State<'grammar, L>>, TableConstructionError<'grammar, L>> {
let session = Tls::session();
let mut kernel_set = kernel_set::KernelSet::new();
let mut states = vec![];
let mut conflicts = vec![];
kernel_set.add_state(Kernel::start(self.items(
&self.start_nt,
0,
&self.start_lookahead,
)));
while let Some(Kernel { items: seed_items }) = kernel_set.next() {
let items = self.transitive_closure(seed_items);
let index = StateIndex(states.len());
if index.0 % 5000 == 0 && index.0 > 0 {
log!(session, Verbose, "{} states created so far.", index.0);
}
let mut this_state = State {
index,
items: items.clone(),
shifts: map(),
reductions: vec![],
gotos: map(),
};
let transitions: Multimap<Symbol, Multimap<LR0Item<'grammar>, L>> = items
.vec
.iter()
.filter_map(Item::shifted_item)
.map(
|(
symbol,
Item {
production,
index,
lookahead,
},
)| { (symbol, (Item::lr0(production, index), lookahead)) },
)
.collect();
for (symbol, shifted_items) in transitions.into_iter() {
let shifted_items: Vec<Item<'grammar, L>> = shifted_items
.into_iter()
.map(|(lr0_item, lookahead)| lr0_item.with_lookahead(lookahead))
.collect();
let next_state = kernel_set.add_state(Kernel::shifted(shifted_items));
match symbol {
Symbol::Terminal(s) => {
let prev = this_state.shifts.insert(s, next_state);
assert!(prev.is_none()); }
Symbol::Nonterminal(s) => {
let prev = this_state.gotos.insert(s, next_state);
assert!(prev.is_none());
}
}
}
for item in items.vec.iter().filter(|i| i.can_reduce()) {
this_state
.reductions
.push((item.lookahead.clone(), item.production));
}
conflicts.extend(L::conflicts(&this_state));
states.push(this_state);
if self.permit_early_stop && session.stop_after(conflicts.len()) {
log!(
session,
Verbose,
"{} conflicts encountered, stopping.",
conflicts.len()
);
break;
}
}
if !conflicts.is_empty() {
Err(TableConstructionError { states, conflicts })
} else {
Ok(states)
}
}
fn items(&self, id: &NonterminalString, index: usize, lookahead: &L) -> Vec<Item<'grammar, L>> {
self.grammar
.productions_for(id)
.iter()
.map(|production| {
debug_assert!(index <= production.symbols.len());
Item {
production,
index,
lookahead: lookahead.clone(),
}
})
.collect()
}
fn transitive_closure(&self, items: Vec<Item<'grammar, L>>) -> Items<'grammar, L> {
let mut stack: Vec<LR0Item<'grammar>> = items.iter().map(Item::to_lr0).collect();
let mut map: Multimap<LR0Item<'grammar>, L> = items
.into_iter()
.map(|item| (item.to_lr0(), item.lookahead))
.collect();
while let Some(item) = stack.pop() {
let lookahead = map.get(&item).unwrap().clone();
let shift_symbol = item.shift_symbol();
let (nt, remainder) = match shift_symbol {
None => continue, Some((Symbol::Terminal(_), _)) => {
continue; }
Some((Symbol::Nonterminal(nt), remainder)) => (nt, remainder),
};
for new_item in L::epsilon_moves(self, &nt, remainder, &lookahead) {
let new_item0 = new_item.to_lr0();
if map.push(new_item0, new_item.lookahead) {
stack.push(new_item0);
}
}
}
let final_items = map
.into_iter()
.map(|(lr0_item, lookahead)| lr0_item.with_lookahead(lookahead))
.collect();
Items { vec: final_items }
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
struct Kernel<'grammar, L: LookaheadBuild> {
items: Vec<Item<'grammar, L>>,
}
impl<'grammar, L: LookaheadBuild> Kernel<'grammar, L> {
pub fn start(items: Vec<Item<'grammar, L>>) -> Kernel<'grammar, L> {
debug_assert!(items.iter().all(|item| item.index == 0));
Kernel { items }
}
pub fn shifted(items: Vec<Item<'grammar, L>>) -> Kernel<'grammar, L> {
debug_assert!(items.iter().all(|item| item.index > 0));
Kernel { items }
}
}
impl<'grammar, L: LookaheadBuild> kernel_set::Kernel for Kernel<'grammar, L> {
type Index = StateIndex;
fn index(c: usize) -> StateIndex {
StateIndex(c)
}
}
pub trait LookaheadBuild: Lookahead {
fn epsilon_moves<'grammar>(
lr: &LR<'grammar, Self>,
nt: &NonterminalString,
remainder: &[Symbol],
lookahead: &Self,
) -> Vec<Item<'grammar, Self>>;
}
impl LookaheadBuild for Nil {
fn epsilon_moves<'grammar>(
lr: &LR<'grammar, Self>,
nt: &NonterminalString,
_remainder: &[Symbol],
lookahead: &Nil,
) -> Vec<LR0Item<'grammar>> {
lr.items(nt, 0, &lookahead)
}
}
impl LookaheadBuild for TokenSet {
fn epsilon_moves<'grammar>(
lr: &LR<'grammar, Self>,
nt: &NonterminalString,
remainder: &[Symbol],
lookahead: &Self,
) -> Vec<LR1Item<'grammar>> {
let first_set = lr.first_sets.first1(remainder, lookahead);
lr.items(nt, 0, &first_set)
}
}