use collections::{Map, map};
use lr1::core::*;
use lr1::first::*;
use lr1::lookahead::*;
use lr1::example::*;
use grammar::repr::*;
use petgraph::{EdgeDirection, Graph};
use petgraph::graph::{Edges, NodeIndex};
use std::fmt::{Debug, Formatter, Error};
#[cfg(test)] mod test;
pub struct TraceGraph<'grammar> {
graph: Graph<TraceGraphNode<'grammar>, SymbolSets<'grammar>>,
indices: Map<TraceGraphNode<'grammar>, NodeIndex>,
}
#[derive(Copy, 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)
.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(|(t, &l)| t == to && l == 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<'grammar> Into<TraceGraphNode<'grammar>> for NonterminalString {
fn into(self) -> TraceGraphNode<'grammar> {
TraceGraphNode::Nonterminal(self)
}
}
impl<'grammar, L: Lookahead> Into<TraceGraphNode<'grammar>> for Item<'grammar, L> {
fn into(self) -> TraceGraphNode<'grammar> {
(&self).into()
}
}
impl<'a, 'grammar, L: Lookahead> Into<TraceGraphNode<'grammar>> for &'a Item<'grammar, L> {
fn into(self) -> TraceGraphNode<'grammar> {
TraceGraphNode::Item(self.to_lr0())
}
}
struct TraceGraphEdge<'grammar> {
from: TraceGraphNode<'grammar>,
to: TraceGraphNode<'grammar>,
label: (&'grammar [Symbol], Option<&'grammar Symbol>, &'grammar [Symbol]),
}
impl<'grammar> Debug for TraceGraphEdge<'grammar> {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
write!(fmt, "({:?} -{:?}-> {:?})", self.from, self.label, self.to)
}
}
impl<'grammar> Debug for TraceGraph<'grammar> {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
let mut s = fmt.debug_list();
for (&node, &index) in &self.indices {
for (target, label) in
self.graph.edges_directed(index, EdgeDirection::Outgoing)
{
s.entry(&TraceGraphEdge { from: node,
to: self.graph[target],
label: (label.prefix,
label.cursor,
label.suffix) });
}
}
s.finish()
}
}
pub struct PathEnumerator<'graph, 'grammar: 'graph> {
graph: &'graph TraceGraph<'grammar>,
stack: Vec<EnumeratorState<'graph, 'grammar>>,
}
struct EnumeratorState<'graph, 'grammar: 'graph> {
index: NodeIndex,
symbol_sets: SymbolSets<'grammar>,
edges: Edges<'graph, SymbolSets<'grammar>>,
}
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: graph,
stack: vec![],
};
let edges = enumerator.incoming_edges(start_state);
enumerator.stack.push(EnumeratorState {
index: start_state,
symbol_sets: SymbolSets::new(),
edges: 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>> {
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<(NodeIndex, &'graph SymbolSets<'grammar>)>)
-> bool {
if let Some((index, &symbol_sets)) = next {
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: index,
symbol_sets: symbol_sets,
edges: edges,
});
return true;
}
TraceGraphNode::Nonterminal(_) => {
if !self.stack.iter().any(|state| state.index == index) {
let edges = self.incoming_edges(index);
self.stack.push(EnumeratorState {
index: index,
symbol_sets: symbol_sets,
edges: 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)),
None => if self.stack[1].symbol_sets.prefix.is_empty() {
symbols.push(ExampleSymbol::Epsilon)
} else {
},
}
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(nonterminal) => nonterminal,
TraceGraphNode::Item(item) => item.production.nonterminal,
};
let reduction = Reduction {
start: cursors.0,
end: cursors.1,
nonterminal: nonterminal
};
cursors.0 += state.symbol_sets.prefix.len();
cursors.1 -= state.symbol_sets.suffix.len();
reduction
})
.collect();
reductions.reverse();
Example {
symbols: symbols,
cursor: cursor,
reductions: reductions
}
}
}
impl<'graph, 'grammar> Iterator for PathEnumerator<'graph, 'grammar> {
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: 'graph> {
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: first_sets,
lookahead: lookahead,
}
}
}
impl<'graph, 'grammar> Iterator for FilteredPathEnumerator<'graph, 'grammar> {
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
}
}