use crate::collections::{Map, map};
use crate::grammar::repr::*;
use crate::lr1::core::*;
use crate::lr1::example::*;
use crate::lr1::first::*;
use crate::lr1::lookahead::*;
use petgraph::graph::{EdgeReference, Edges, NodeIndex};
use petgraph::prelude::*;
use petgraph::{Directed, EdgeDirection, Graph};
use std::fmt::{Debug, Error, Formatter};
#[cfg(test)]
mod test;
pub struct TraceGraph<'grammar> {
graph: Graph<TraceGraphNode<'grammar>, SymbolSets<'grammar>>,
indices: Map<TraceGraphNode<'grammar>, NodeIndex>,
}
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub enum TraceGraphNode<'grammar> {
Nonterminal(NonterminalString),
Item(Lr0Item<'grammar>),
}
impl<'grammar> TraceGraph<'grammar> {
pub fn new() -> Self {
TraceGraph {
graph: Graph::new(),
indices: map(),
}
}
pub fn add_node<T>(&mut self, node: T) -> NodeIndex
where
T: Into<TraceGraphNode<'grammar>>,
{
let node = node.into();
let graph = &mut self.graph;
*self
.indices
.entry(node.clone())
.or_insert_with(|| graph.add_node(node))
}
pub fn add_edge<F, T>(&mut self, from: F, to: T, labels: SymbolSets<'grammar>)
where
F: Into<TraceGraphNode<'grammar>>,
T: Into<TraceGraphNode<'grammar>>,
{
let from = self.add_node(from.into());
let to = self.add_node(to.into());
if !self
.graph
.edges_directed(from, EdgeDirection::Outgoing)
.any(|edge| edge.target() == to && *edge.weight() == labels)
{
self.graph.add_edge(from, to, labels);
}
}
pub fn lr0_examples<'graph>(
&'graph self,
lr0_item: Lr0Item<'grammar>,
) -> PathEnumerator<'graph, 'grammar> {
PathEnumerator::new(self, lr0_item)
}
pub fn lr1_examples<'trace>(
&'trace self,
first_sets: &'trace FirstSets,
item: &Lr1Item<'grammar>,
) -> FilteredPathEnumerator<'trace, 'grammar> {
FilteredPathEnumerator::new(first_sets, self, item.to_lr0(), item.lookahead.clone())
}
}
impl From<NonterminalString> for TraceGraphNode<'_> {
fn from(val: NonterminalString) -> Self {
TraceGraphNode::Nonterminal(val)
}
}
impl<'grammar, L: Lookahead> From<Item<'grammar, L>> for TraceGraphNode<'grammar> {
fn from(val: Item<'grammar, L>) -> Self {
(&val).into()
}
}
impl<'a, 'grammar, L: Lookahead> From<&'a Item<'grammar, L>> for TraceGraphNode<'grammar> {
fn from(val: &'a Item<'grammar, L>) -> Self {
TraceGraphNode::Item(val.to_lr0())
}
}
struct TraceGraphEdge<'grammar> {
from: TraceGraphNode<'grammar>,
to: TraceGraphNode<'grammar>,
label: (
&'grammar [Symbol],
Option<&'grammar Symbol>,
&'grammar [Symbol],
),
}
impl Debug for TraceGraphEdge<'_> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> {
write!(fmt, "({:?} -{:?}-> {:?})", self.from, self.label, self.to)
}
}
impl Debug for TraceGraph<'_> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> {
let mut s = fmt.debug_list();
for (node, &index) in &self.indices {
for edge in self.graph.edges_directed(index, EdgeDirection::Outgoing) {
let label = edge.weight();
s.entry(&TraceGraphEdge {
from: node.clone(),
to: self.graph[edge.target()].clone(),
label: (label.prefix, label.cursor, label.suffix),
});
}
}
s.finish()
}
}
pub struct PathEnumerator<'graph, 'grammar> {
graph: &'graph TraceGraph<'grammar>,
stack: Vec<EnumeratorState<'graph, 'grammar>>,
}
struct EnumeratorState<'graph, 'grammar> {
index: NodeIndex,
symbol_sets: SymbolSets<'grammar>,
edges: Edges<'graph, SymbolSets<'grammar>, Directed>,
}
impl<'graph, 'grammar> PathEnumerator<'graph, 'grammar> {
fn new(graph: &'graph TraceGraph<'grammar>, lr0_item: Lr0Item<'grammar>) -> Self {
let start_state = graph.indices[&TraceGraphNode::Item(lr0_item)];
let mut enumerator = PathEnumerator {
graph,
stack: vec![],
};
let edges = enumerator.incoming_edges(start_state);
enumerator.stack.push(EnumeratorState {
index: start_state,
symbol_sets: SymbolSets::new(),
edges,
});
enumerator.find_next_trace();
enumerator
}
pub fn advance(&mut self) -> bool {
match self.stack.pop() {
Some(top_state) => {
assert!(match self.graph.graph[top_state.index] {
TraceGraphNode::Item(_) => true,
TraceGraphNode::Nonterminal(_) => false,
});
self.find_next_trace()
}
None => false,
}
}
fn incoming_edges(&self, index: NodeIndex) -> Edges<'graph, SymbolSets<'grammar>, Directed> {
self.graph
.graph
.edges_directed(index, EdgeDirection::Incoming)
}
fn find_next_trace(&mut self) -> bool {
if !self.stack.is_empty() {
let next_edge = {
let top_of_stack = self.stack.last_mut().unwrap();
top_of_stack.edges.next()
};
self.push_next_child_if_any(next_edge)
} else {
false
}
}
fn push_next_child_if_any(
&mut self,
next: Option<EdgeReference<'graph, SymbolSets<'grammar>>>,
) -> bool {
if let Some(edge) = next {
let index = edge.source();
let symbol_sets = *edge.weight();
self.push_next_child(index, symbol_sets)
} else {
self.stack.pop();
self.find_next_trace()
}
}
fn push_next_child(&mut self, index: NodeIndex, symbol_sets: SymbolSets<'grammar>) -> bool {
match self.graph.graph[index] {
TraceGraphNode::Item(_) => {
let edges = self.incoming_edges(index);
self.stack.push(EnumeratorState {
index,
symbol_sets,
edges,
});
true
}
TraceGraphNode::Nonterminal(_) => {
if !self.stack.iter().any(|state| state.index == index) {
let edges = self.incoming_edges(index);
self.stack.push(EnumeratorState {
index,
symbol_sets,
edges,
});
}
self.find_next_trace()
}
}
}
pub fn found_trace(&self) -> bool {
!self.stack.is_empty()
}
pub fn first0(&self, first_sets: &FirstSets) -> TokenSet {
assert!(self.found_trace());
first_sets.first0(
self.stack[1]
.symbol_sets
.cursor
.into_iter()
.chain(self.stack.iter().flat_map(|s| s.symbol_sets.suffix)),
)
}
pub fn example(&self) -> Example {
assert!(self.found_trace());
let mut symbols = vec![];
symbols.extend(
self.stack
.iter()
.rev()
.flat_map(|s| s.symbol_sets.prefix)
.cloned()
.map(ExampleSymbol::Symbol),
);
let cursor = symbols.len();
match self.stack[1].symbol_sets.cursor {
Some(s) => symbols.push(ExampleSymbol::Symbol(s.clone())),
None => {
if self.stack[1].symbol_sets.prefix.is_empty() {
symbols.push(ExampleSymbol::Epsilon)
}
}
}
symbols.extend(
self.stack
.iter()
.flat_map(|s| s.symbol_sets.suffix)
.cloned()
.map(ExampleSymbol::Symbol),
);
let mut cursors = (0, symbols.len());
let mut reductions: Vec<_> = self.stack[1..]
.iter()
.rev()
.map(|state| {
let nonterminal = match self.graph.graph[state.index] {
TraceGraphNode::Nonterminal(ref nonterminal) => nonterminal.clone(),
TraceGraphNode::Item(ref item) => item.production.nonterminal.clone(),
};
let reduction = Reduction {
start: cursors.0,
end: cursors.1,
nonterminal,
};
cursors.0 += state.symbol_sets.prefix.len();
cursors.1 -= state.symbol_sets.suffix.len();
reduction
})
.collect();
reductions.reverse();
Example {
symbols,
cursor,
reductions,
}
}
}
impl Iterator for PathEnumerator<'_, '_> {
type Item = Example;
fn next(&mut self) -> Option<Example> {
if self.found_trace() {
let example = self.example();
self.advance();
Some(example)
} else {
None
}
}
}
pub struct FilteredPathEnumerator<'graph, 'grammar> {
base: PathEnumerator<'graph, 'grammar>,
first_sets: &'graph FirstSets,
lookahead: TokenSet,
}
impl<'graph, 'grammar> FilteredPathEnumerator<'graph, 'grammar> {
fn new(
first_sets: &'graph FirstSets,
graph: &'graph TraceGraph<'grammar>,
lr0_item: Lr0Item<'grammar>,
lookahead: TokenSet,
) -> Self {
FilteredPathEnumerator {
base: PathEnumerator::new(graph, lr0_item),
first_sets,
lookahead,
}
}
}
impl Iterator for FilteredPathEnumerator<'_, '_> {
type Item = Example;
fn next(&mut self) -> Option<Example> {
while self.base.found_trace() {
let firsts = self.base.first0(self.first_sets);
if firsts.is_intersecting(&self.lookahead) {
let example = self.base.example();
self.base.advance();
return Some(example);
}
self.base.advance();
}
None
}
}