use std::{
cell::RefCell,
collections::{HashSet, VecDeque},
fmt::Debug,
rc::Rc,
};
use petgraph::{graph::Edges, prelude::*};
use crate::{
context::Context, input::Input, lexer::Token, lr::builder::LRBuilder, parser::State,
position::SourceSpan, Position,
};
pub struct GssGraph<'i, I: Input + ?Sized, S, P, TK: Copy>(
#[allow(clippy::type_complexity)] Graph<GssHead<'i, I, S, TK>, Rc<Parent<'i, I, P, TK>>>,
);
impl<I, S, P, TK> Default for GssGraph<'_, I, S, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
fn default() -> Self {
Self(Default::default())
}
}
impl<'i, I, S, P, TK> GssGraph<'i, I, S, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
pub fn new() -> Self {
Self::default()
}
#[inline]
pub fn add_head(&mut self, head: GssHead<'i, I, S, TK>) -> NodeIndex {
self.0.add_node(head)
}
#[inline]
pub fn head(&self, head: NodeIndex) -> &GssHead<'i, I, S, TK> {
self.0.node_weight(head).expect("Invalid Gss head index!")
}
#[inline]
pub fn head_mut(&mut self, head: NodeIndex) -> &mut GssHead<'i, I, S, TK> {
self.0
.node_weight_mut(head)
.expect("Invalid Gss head index!")
}
#[inline]
pub fn parent(&self, index: EdgeIndex) -> Rc<Parent<'i, I, P, TK>> {
self.0.edge_weight(index).unwrap().clone()
}
#[inline]
pub fn add_parent(
&mut self,
start: NodeIndex,
end: NodeIndex,
parent: Rc<Parent<'i, I, P, TK>>,
) -> EdgeIndex {
self.0.add_edge(start, end, parent)
}
pub fn add_solution(
&mut self,
start: NodeIndex,
end: NodeIndex,
solution: Rc<SPPFTree<'i, I, P, TK>>,
) -> Option<EdgeIndex> {
if let Some(edge) = self.edge_between(start, end) {
self.parent(edge).possibilities.borrow_mut().push(solution);
None
} else {
Some(self.add_parent(start, end, Rc::new(Parent::new(end, start, vec![solution]))))
}
}
#[inline]
pub fn backedges(&self, head: NodeIndex) -> Edges<'_, Rc<Parent<'i, I, P, TK>>, Directed> {
self.0.edges_directed(head, Direction::Outgoing)
}
#[inline]
pub fn start(&self, edge: EdgeIndex) -> NodeIndex {
self.0
.edge_endpoints(edge)
.expect("Invalid Gss edge index!")
.0
}
#[inline]
pub fn end(&self, edge: EdgeIndex) -> NodeIndex {
self.0
.edge_endpoints(edge)
.expect("Invalid Gss edge index!")
.1
}
#[inline]
pub fn edge_between(&self, start: NodeIndex, end: NodeIndex) -> Option<EdgeIndex> {
self.0.find_edge(start, end)
}
}
#[derive(Debug)]
pub struct GssHead<'i, I, S, TK>
where
I: Input + ?Sized,
{
state: S,
pub frontier: usize,
position: Position,
span: SourceSpan,
layout_ahead: Option<&'i I>,
token_ahead: Option<Token<'i, I, TK>>,
}
impl<I, S, TK> Clone for GssHead<'_, I, S, TK>
where
I: Input + ?Sized,
S: State,
TK: Copy,
{
fn clone(&self) -> Self {
Self {
state: self.state,
frontier: self.frontier,
position: self.position,
span: self.span,
layout_ahead: self.layout_ahead,
token_ahead: self.token_ahead().cloned(),
}
}
}
impl<I: Input + ?Sized, S: Default, TK> Default for GssHead<'_, I, S, TK> {
fn default() -> Self {
Self {
state: Default::default(),
frontier: Default::default(),
position: I::start_position(),
span: SourceSpan {
start: I::start_position(),
end: I::start_position(),
},
layout_ahead: Default::default(),
token_ahead: Default::default(),
}
}
}
impl<'i, I, S, TK> GssHead<'i, I, S, TK>
where
I: Input + ?Sized,
S: State,
TK: Copy,
{
#[allow(clippy::too_many_arguments)]
pub fn new(
state: S,
frontier: usize,
position: Position,
span: SourceSpan,
layout_ahead: Option<&'i I>,
token_ahead: Option<Token<'i, I, TK>>,
) -> Self {
Self {
state,
frontier,
position,
span,
layout_ahead,
token_ahead,
}
}
pub fn with_tok_state(&self, token_ahead: Token<'i, I, TK>, state: S) -> Self {
Self {
state,
token_ahead: Some(token_ahead),
..*self
}
}
pub fn with_tok(&self, token_ahead: Token<'i, I, TK>) -> Self {
Self {
token_ahead: Some(token_ahead),
..*self
}
}
}
impl<'i, S, I, TK> Context<'i, I, S, TK> for GssHead<'i, I, S, TK>
where
I: Input + ?Sized,
S: State,
{
#[inline]
fn state(&self) -> S {
self.state
}
#[inline]
fn set_state(&mut self, state: S) {
self.state = state
}
#[inline]
fn position(&self) -> Position {
self.position
}
#[inline]
fn set_position(&mut self, position: Position) {
self.position = position
}
#[inline]
fn span(&self) -> SourceSpan {
self.span
}
#[inline]
fn set_span(&mut self, span: SourceSpan) {
self.span = span
}
#[inline]
fn token_ahead(&self) -> Option<&Token<'i, I, TK>> {
self.token_ahead.as_ref()
}
#[inline]
fn set_token_ahead(&mut self, token: Token<'i, I, TK>) {
self.token_ahead = Some(token)
}
#[inline]
fn layout_ahead(&self) -> Option<&'i I> {
self.layout_ahead
}
#[inline]
fn set_layout_ahead(&mut self, layout: Option<&'i I>) {
self.layout_ahead = layout
}
}
#[derive(Debug, Default)]
pub enum SPPFTree<'i, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
Term {
token: Token<'i, I, TK>,
data: TreeData<'i, I>,
},
NonTerm {
prod: P,
data: TreeData<'i, I>,
children: RefCell<VecDeque<Rc<Parent<'i, I, P, TK>>>>,
},
#[default]
Empty,
}
impl<'i, I, P, TK> SPPFTree<'i, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
fn solutions(&self) -> usize {
match self {
SPPFTree::Term { .. } => 1,
SPPFTree::NonTerm { children, .. } => {
children.borrow().iter().map(|p| p.solutions()).product()
}
SPPFTree::Empty => 0,
}
}
#[allow(clippy::mutable_key_type)]
fn ambiguities(&self, visited: &mut HashSet<Rc<Parent<'i, I, P, TK>>>) -> usize {
match self {
SPPFTree::Term { .. } | SPPFTree::Empty => 0,
SPPFTree::NonTerm { children, .. } => children
.borrow()
.iter()
.map(|p| {
if visited.contains(p) {
0
} else {
visited.insert(Rc::clone(p));
p.ambiguities(visited)
}
})
.sum(),
}
}
}
impl<'i, I, S, P, TK> Context<'i, I, S, TK> for SPPFTree<'i, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
S: State,
{
fn state(&self) -> S {
panic!("state() called on SPPFTree")
}
fn set_state(&mut self, _state: S) {}
fn position(&self) -> Position {
panic!("position() called on SPPFTree")
}
fn set_position(&mut self, _position: Position) {}
fn span(&self) -> SourceSpan {
match self {
SPPFTree::Term { data, .. } | SPPFTree::NonTerm { data, .. } => data.span,
_ => panic!("Called span() on empty tree!"),
}
}
fn set_span(&mut self, _span: SourceSpan) {}
fn token_ahead(&self) -> Option<&Token<'i, I, TK>> {
None
}
fn set_token_ahead(&mut self, _token: Token<'i, I, TK>) {}
fn layout_ahead(&self) -> Option<&'i I> {
match self {
SPPFTree::Term { data, .. } | SPPFTree::NonTerm { data, .. } => data.layout,
_ => panic!("Called layout_ahead() on empty tree!"),
}
}
fn set_layout_ahead(&mut self, _layout: Option<&'i I>) {}
}
impl<I, P, TK> Clone for SPPFTree<'_, I, P, TK>
where
I: Input + ?Sized,
P: Clone,
TK: Copy,
{
fn clone(&self) -> Self {
match self {
Self::Term { token, data } => Self::Term {
token: token.clone(),
data: data.clone(),
},
Self::NonTerm {
prod,
data,
children,
} => Self::NonTerm {
prod: prod.clone(),
data: data.clone(),
children: children.clone(),
},
Self::Empty => Self::Empty,
}
}
}
#[derive(Debug)]
pub struct TreeData<'i, I>
where
I: Input + ?Sized,
{
pub span: SourceSpan,
pub layout: Option<&'i I>,
}
impl<I> Clone for TreeData<'_, I>
where
I: Input + ?Sized,
{
fn clone(&self) -> Self {
Self {
span: self.span,
layout: self.layout,
}
}
}
#[derive(Debug)]
pub struct Parent<'i, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
pub root_node: NodeIndex,
pub head_node: NodeIndex,
pub possibilities: RefCell<Vec<Rc<SPPFTree<'i, I, P, TK>>>>,
}
impl<I, P, TK> PartialEq for Parent<'_, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
fn eq(&self, other: &Self) -> bool {
self.root_node == other.root_node && self.head_node == other.head_node
}
}
impl<I, P, TK> Eq for Parent<'_, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
}
impl<I, P, TK> std::hash::Hash for Parent<'_, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.root_node.hash(state);
self.head_node.hash(state);
}
}
impl<'i, I, P, TK> Parent<'i, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
pub fn new(
root_node: NodeIndex,
head_node: NodeIndex,
possibilities: Vec<Rc<SPPFTree<'i, I, P, TK>>>,
) -> Self {
Self {
root_node,
head_node,
possibilities: RefCell::new(possibilities),
}
}
pub fn solutions(&self) -> usize {
self.possibilities
.borrow()
.iter()
.map(|n| n.solutions())
.sum()
}
#[allow(clippy::mutable_key_type)]
pub fn ambiguities(&self, visited: &mut HashSet<Rc<Parent<'i, I, P, TK>>>) -> usize {
let ambiguity: usize = if self.possibilities.borrow().len() > 1 {
1
} else {
0
};
ambiguity
+ self
.possibilities
.borrow()
.iter()
.map(|n| n.ambiguities(visited))
.sum::<usize>()
}
}
pub struct Tree<'i, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
idx: usize,
root: Rc<SPPFTree<'i, I, P, TK>>,
}
impl<I, P, TK> Debug for Tree<'_, I, P, TK>
where
I: Input + ?Sized + Debug,
TK: Copy,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &*self.root {
SPPFTree::Term { token, .. } => write!(f, "{:#?}", token.value),
SPPFTree::NonTerm { .. } => write!(f, "{:#?}", self.children()),
SPPFTree::Empty => write!(f, "EMPTY"),
}
}
}
impl<'i, I, P, TK> Tree<'i, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
pub fn new(root: Rc<SPPFTree<'i, I, P, TK>>, idx: usize) -> Self {
Self { root, idx }
}
pub fn children(&self) -> Vec<Tree<'i, I, P, TK>> {
match *self.root {
SPPFTree::Term { .. } | SPPFTree::Empty => vec![],
SPPFTree::NonTerm { ref children, .. } => {
let mut tree_idx = self.idx;
let weights = children
.borrow()
.iter()
.map(|c| c.solutions())
.collect::<Vec<_>>();
children
.borrow()
.iter()
.enumerate()
.map(|(idx, child)| {
let factor: usize = weights[(idx + 1)..].iter().product();
let tree_idx_residual = tree_idx / factor;
tree_idx %= factor;
let (root, new_tree_idx) =
Self::find_tree_root(&child.possibilities.borrow(), tree_idx_residual)
.expect("Tree index must be valid.");
Tree::new(root, new_tree_idx)
})
.collect()
}
}
}
pub fn build<B: LRBuilder<'i, I, GssHead<'i, I, S, TK>, S, P, TK>, S>(
&self,
builder: &mut B,
) -> B::Output
where
S: State,
P: Copy,
{
let mut context = GssHead::default();
self.build_inner(&mut context, builder);
builder.get_result()
}
fn build_inner<B: LRBuilder<'i, I, C, S, P, TK>, C, S>(&self, context: &mut C, builder: &mut B)
where
C: Context<'i, I, S, TK> + Default,
S: State,
P: Copy,
{
match &*self.root {
SPPFTree::Term { token, .. } => {
context.set_span(Context::<I, S, TK>::span(&*self.root));
builder.shift_action(context, token.clone())
}
SPPFTree::NonTerm { prod, .. } => {
let children = self.children();
children.iter().for_each(|c| {
c.build_inner(context, builder);
});
context.set_span(Context::<I, S, TK>::span(&*self.root));
builder.reduce_action(context, *prod, children.len())
}
SPPFTree::Empty => (),
}
}
#[allow(clippy::type_complexity)]
fn find_tree_root(
roots: &[Rc<SPPFTree<'i, I, P, TK>>],
tree_idx: usize,
) -> Option<(Rc<SPPFTree<'i, I, P, TK>>, usize)> {
if roots.is_empty() {
return None;
}
let mut tree_idx = tree_idx;
let mut root_idx = 0;
let mut solutions = roots[root_idx].solutions();
while solutions <= tree_idx {
root_idx += 1;
if root_idx >= roots.len() {
return None;
}
tree_idx -= solutions;
solutions = roots[root_idx].solutions();
}
Some((Rc::clone(&roots[root_idx]), tree_idx))
}
}
#[derive(Debug)]
pub struct Forest<'i, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
results: Vec<Rc<SPPFTree<'i, I, P, TK>>>,
}
impl<'i, I, P, TK> Forest<'i, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
pub fn new(results: Vec<Rc<SPPFTree<'i, I, P, TK>>>) -> Self {
Forest { results }
}
#[inline]
pub fn get_first_tree(&self) -> Option<Tree<'i, I, P, TK>> {
self.get_tree(0)
}
pub fn get_tree(&self, idx: usize) -> Option<Tree<'i, I, P, TK>> {
Tree::find_tree_root(&self.results, idx).map(|(root, idx)| Tree::new(root, idx))
}
#[inline]
pub fn is_empty(&self) -> bool {
self.results.is_empty()
}
#[inline]
pub fn solutions(&self) -> usize {
self.results.iter().map(|n| n.solutions()).sum()
}
#[inline]
pub fn ambiguities(&self) -> usize {
#[allow(clippy::mutable_key_type)]
let mut visited: HashSet<Rc<Parent<'i, I, P, TK>>> = HashSet::new();
self.results
.iter()
.map(|n| n.ambiguities(&mut visited))
.sum::<usize>()
+ if self.results.len() > 1 { 1 } else { 0 }
}
}
pub struct ForestIntoIter<'i, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
forest: Forest<'i, I, P, TK>,
tree_idx: usize,
}
impl<'i, I, P, TK> IntoIterator for Forest<'i, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
type Item = Tree<'i, I, P, TK>;
type IntoIter = ForestIntoIter<'i, I, P, TK>;
fn into_iter(self) -> Self::IntoIter {
ForestIntoIter {
forest: self,
tree_idx: 0,
}
}
}
impl<'i, I, P, TK> Iterator for ForestIntoIter<'i, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
type Item = Tree<'i, I, P, TK>;
fn next(&mut self) -> Option<Self::Item> {
let tree = self.forest.get_tree(self.tree_idx);
if tree.is_some() {
self.tree_idx += 1;
}
tree
}
}
impl<'i, I, P, TK> Forest<'i, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
pub fn iter<'f>(&'f self) -> ForestIterator<'i, 'f, I, P, TK> {
ForestIterator {
forest: self,
tree_idx: 0,
}
}
}
pub struct ForestIterator<'i, 'f, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
forest: &'f Forest<'i, I, P, TK>,
tree_idx: usize,
}
impl<'i, I, P, TK> Iterator for ForestIterator<'i, '_, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
type Item = Tree<'i, I, P, TK>;
fn next(&mut self) -> Option<Self::Item> {
let tree = self.forest.get_tree(self.tree_idx);
if tree.is_some() {
self.tree_idx += 1;
}
tree
}
}
impl<'i, 'f, I, P, TK> IntoIterator for &'f Forest<'i, I, P, TK>
where
I: Input + ?Sized,
TK: Copy,
{
type Item = Tree<'i, I, P, TK>;
type IntoIter = ForestIterator<'i, 'f, I, P, TK>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}