use crate::engine::{Violation, ViolationKind};
use crate::job::Job;
use crate::node::{Node, NodeId};
use crate::outcome::Outcome;
use crate::span::Span;
use crate::status::{Status, StatusCounts};
pub(crate) enum Applied {
Expanded,
Done,
Failed(Option<Violation>),
}
pub struct ParseTree<C> {
rev: u64,
nodes: Vec<Node<C>>,
root: NodeId,
}
impl<C> ParseTree<C> {
pub fn new(source_rev: u64, root_span: Span, root_ctx: C) -> Self {
Self {
rev: source_rev,
nodes: vec![Node::new_root(root_span, root_ctx)],
root: NodeId(0),
}
}
pub fn from_source(source: &str, source_rev: u64, root_ctx: C) -> Self {
Self::new(source_rev, Span::new(0, source.len(), source_rev), root_ctx)
}
pub fn node_at(&self, offset: usize) -> Option<NodeId> {
let mut current = self.root;
if !self.span(current).contains_offset(offset) {
return None;
}
loop {
let next = self
.children(current)
.iter()
.find(|child| self.span(**child).contains_offset(offset));
match next {
Some(&child) => current = child,
None => return Some(current),
}
}
}
pub fn source_rev(&self) -> u64 {
self.rev
}
pub fn root(&self) -> NodeId {
self.root
}
pub fn len(&self) -> usize {
self.nodes.iter().filter(|node| node.alive).count()
}
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
pub fn is_root_only(&self) -> bool {
self.nodes.len() == 1
}
pub fn span(&self, id: NodeId) -> Span {
self.nodes[id.0].span
}
pub fn ctx(&self, id: NodeId) -> &C {
&self.nodes[id.0].ctx
}
pub fn status(&self, id: NodeId) -> Status {
self.nodes[id.0].status
}
pub fn depth(&self, id: NodeId) -> usize {
self.nodes[id.0].depth
}
pub fn attempts(&self, id: NodeId) -> usize {
self.nodes[id.0].attempts
}
pub fn parent(&self, id: NodeId) -> Option<NodeId> {
self.nodes[id.0].parent
}
pub fn children(&self, id: NodeId) -> &[NodeId] {
&self.nodes[id.0].children
}
pub fn nodes(&self) -> impl Iterator<Item = NodeId> + '_ {
self.nodes
.iter()
.enumerate()
.filter(|(_, node)| node.alive)
.map(|(index, _)| NodeId(index))
}
pub fn text<'a>(&self, source: &'a str, id: NodeId) -> &'a str {
&source[self.span(id).to_range()]
}
pub fn edit(&mut self, edit: crate::session::Edit) {
let new_rev = self.rev + 1;
self.rev = new_rev;
for node in &mut self.nodes {
if !node.alive {
continue;
}
let touched = edit.touches(&node.span);
node.span = crate::session::map_span(node.span, &edit, new_rev);
if touched {
node.status = Status::Unparsed;
node.depth -= node.attempts;
node.attempts = 0;
}
}
}
pub fn status_counts(&self) -> StatusCounts {
let mut counts = StatusCounts::default();
for node in &self.nodes {
if !node.alive {
continue;
}
match node.status {
Status::Unparsed => counts.unparsed += 1,
Status::Expanded => counts.expanded += 1,
Status::Done => counts.done += 1,
Status::Failed => counts.failed += 1,
}
}
counts
}
pub fn is_pending(&self, id: NodeId, max_rounds: usize) -> bool {
let node = &self.nodes[id.0];
node.alive
&& (node.status.is_unparsed() || (node.status.is_failed() && node.depth < max_rounds))
}
pub fn is_settled(&self, id: NodeId, max_rounds: usize) -> bool {
!self.is_pending(id, max_rounds)
&& self
.children(id)
.iter()
.all(|child| self.is_settled(*child, max_rounds))
}
pub fn pending(&self, max_rounds: usize) -> Vec<NodeId> {
self.nodes()
.filter(|id| self.is_pending(*id, max_rounds))
.collect()
}
pub(crate) fn ready_jobs(&self, round: usize) -> Vec<Job<C>>
where
C: Clone,
{
self.nodes
.iter()
.enumerate()
.filter(|(_, node)| {
node.alive
&& node.depth == round
&& matches!(node.status, Status::Unparsed | Status::Failed)
})
.map(|(index, node)| Job {
node: NodeId(index),
span: node.span,
ctx: node.ctx.clone(),
pass_index: round,
})
.collect()
}
pub(crate) fn apply(
&mut self,
id: NodeId,
outcome: Outcome<C>,
round: usize,
enforce_shrink: bool,
pass: Option<&'static str>,
) -> Applied
where
C: PartialEq,
{
let parent_span = self.nodes[id.0].span;
match outcome {
Outcome::Done => {
self.detach_children(id);
self.set_status(id, Status::Done);
Applied::Done
}
Outcome::Failed => {
self.detach_children(id);
self.mark_failed(id, round);
Applied::Failed(None)
}
Outcome::Expand(children) => {
if children.is_empty() {
self.detach_children(id);
self.set_status(id, Status::Done);
return Applied::Done;
}
let mut violation = None;
for (child, _) in children.iter() {
let kind = if child.rev != parent_span.rev {
Some(ViolationKind::WrongRevision)
} else if !parent_span.contains(child) {
Some(ViolationKind::OutsideParent)
} else if enforce_shrink && child.len() >= parent_span.len() {
Some(ViolationKind::NotSmaller)
} else {
None
};
if let Some(kind) = kind {
violation = Some(Violation {
node: id,
round,
pass,
span: *child,
kind,
});
break;
}
}
if let Some(violation) = violation {
self.detach_children(id);
self.mark_failed(id, round);
return Applied::Failed(Some(violation));
}
let next_depth = round + 1;
let old_children = std::mem::take(&mut self.nodes[id.0].children);
let mut reused = vec![None; children.len()];
let mut orphans = old_children;
for (slot, (span, ctx)) in children.iter().enumerate() {
if let Some(position) = orphans.iter().position(|child| {
let node = &self.nodes[child.0];
node.alive && node.span == *span && node.ctx == *ctx
}) {
reused[slot] = Some(orphans.remove(position));
}
}
for orphan in &orphans {
self.detach_recursive(*orphan);
}
let mut child_ids = Vec::with_capacity(children.len());
for (slot, (span, ctx)) in children.into_iter().enumerate() {
if let Some(kept) = reused[slot] {
child_ids.push(kept);
continue;
}
let child_index = self.nodes.len();
child_ids.push(NodeId(child_index));
self.nodes.push(Node {
span,
ctx,
status: Status::Unparsed,
depth: next_depth,
parent: Some(id),
children: Vec::new(),
attempts: 0,
alive: true,
});
}
let node = &mut self.nodes[id.0];
node.status = Status::Expanded;
node.children = child_ids;
Applied::Expanded
}
}
}
fn detach_children(&mut self, id: NodeId) {
let children = std::mem::take(&mut self.nodes[id.0].children);
for child in children {
self.detach_recursive(child);
}
}
fn detach_recursive(&mut self, id: NodeId) {
self.nodes[id.0].alive = false;
let children = std::mem::take(&mut self.nodes[id.0].children);
for child in children {
self.detach_recursive(child);
}
}
fn set_status(&mut self, id: NodeId, status: Status) {
self.nodes[id.0].status = status;
}
fn mark_failed(&mut self, id: NodeId, round: usize) {
let node = &mut self.nodes[id.0];
node.status = Status::Failed;
node.depth = round + 1;
node.attempts += 1;
}
}
impl<C> std::fmt::Debug for ParseTree<C> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ParseTree")
.field("rev", &self.rev)
.field("nodes", &self.nodes.len())
.finish()
}
}