use std::num::NonZeroUsize;
use std::ops::{Add, Sub};
use crate::parse::{Item, ItemBody};
#[derive(Debug, Eq, PartialEq, Copy, Clone, PartialOrd)]
pub(crate) struct TreeIndex(NonZeroUsize);
impl TreeIndex {
fn new(i: usize) -> Self {
TreeIndex(NonZeroUsize::new(i).unwrap())
}
pub fn get(self) -> usize {
self.0.get()
}
}
impl Add<usize> for TreeIndex {
type Output = TreeIndex;
fn add(self, rhs: usize) -> Self {
let inner = self.0.get() + rhs;
TreeIndex::new(inner)
}
}
impl Sub<usize> for TreeIndex {
type Output = TreeIndex;
fn sub(self, rhs: usize) -> Self {
let inner = self.0.get().checked_sub(rhs).unwrap();
TreeIndex::new(inner)
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct Node<T> {
pub child: Option<TreeIndex>,
pub next: Option<TreeIndex>,
pub item: T,
}
#[derive(Clone)]
pub(crate) struct Tree<T> {
nodes: Vec<Node<T>>,
spine: Vec<TreeIndex>, cur: Option<TreeIndex>,
}
impl<T: Default> Tree<T> {
pub(crate) fn with_capacity(cap: usize) -> Tree<T> {
let mut nodes = Vec::with_capacity(cap);
nodes.push(Node {
child: None,
next: None,
item: <T as Default>::default(),
});
Tree {
nodes,
spine: Vec::new(),
cur: None,
}
}
pub(crate) fn cur(&self) -> Option<TreeIndex> {
self.cur
}
pub(crate) fn append(&mut self, item: T) -> TreeIndex {
let ix = self.create_node(item);
let this = Some(ix);
if let Some(ix) = self.cur {
self[ix].next = this;
} else if let Some(&parent) = self.spine.last() {
self[parent].child = this;
}
self.cur = this;
ix
}
pub(crate) fn create_node(&mut self, item: T) -> TreeIndex {
let this = self.nodes.len();
self.nodes.push(Node {
child: None,
next: None,
item,
});
TreeIndex::new(this)
}
pub(crate) fn push(&mut self) -> TreeIndex {
let cur_ix = self.cur.unwrap();
self.spine.push(cur_ix);
self.cur = self[cur_ix].child;
cur_ix
}
pub(crate) fn pop(&mut self) -> Option<TreeIndex> {
let ix = Some(self.spine.pop()?);
self.cur = ix;
ix
}
pub(crate) fn remove_node(&mut self) -> Option<TreeIndex> {
let ix = self.spine.pop()?;
self.cur = Some(ix);
self.nodes.pop()?;
self[ix].child = None;
Some(ix)
}
pub(crate) fn peek_up(&self) -> Option<TreeIndex> {
self.spine.last().copied()
}
pub(crate) fn peek_grandparent(&self) -> Option<TreeIndex> {
if self.spine.len() >= 2 {
Some(self.spine[self.spine.len() - 2])
} else {
None
}
}
pub(crate) fn is_empty(&self) -> bool {
self.nodes.len() <= 1
}
pub(crate) fn spine_len(&self) -> usize {
self.spine.len()
}
pub(crate) fn reset(&mut self) {
self.cur = if self.is_empty() {
None
} else {
Some(TreeIndex::new(1))
};
self.spine.clear();
}
pub(crate) fn walk_spine(&self) -> impl std::iter::DoubleEndedIterator<Item = &TreeIndex> {
self.spine.iter()
}
pub(crate) fn next_sibling(&mut self, cur_ix: TreeIndex) -> Option<TreeIndex> {
self.cur = self[cur_ix].next;
self.cur
}
pub(crate) fn truncate_to_parent(&mut self, child_ix: TreeIndex) {
let next = self[child_ix].next;
self[child_ix].next = None;
if let Some(cur) = self.cur {
self[cur].next = next;
} else if let Some(&parent) = self.spine.last() {
self[parent].child = next;
}
if next.is_some() {
self.cur = next;
} else {
self.pop();
}
}
}
impl Tree<Item> {
pub(crate) fn truncate_siblings(&mut self, end_byte_ix: usize) {
let parent_ix = self.peek_up().unwrap();
let mut next_child_ix = self[parent_ix].child;
let mut prev_child_ix = None;
while let Some(child_ix) = next_child_ix {
let child_end = self[child_ix].item.end;
if child_end < end_byte_ix {
prev_child_ix = Some(child_ix);
next_child_ix = self[child_ix].next;
continue;
} else if child_end == end_byte_ix {
self[child_ix].next = None;
self.cur = Some(child_ix);
} else if self[child_ix].item.start == end_byte_ix {
let is_previous_char_backslash_escape = match self[child_ix].item.body {
ItemBody::Text { backslash_escaped } => backslash_escaped,
_ => false,
};
if is_previous_char_backslash_escape {
let last_byte_ix = end_byte_ix - 1;
self[child_ix].item.start = last_byte_ix;
self[child_ix].item.end = end_byte_ix;
self.cur = Some(child_ix);
} else if let Some(prev_child_ix) = prev_child_ix {
self[prev_child_ix].next = None;
self.cur = Some(prev_child_ix);
} else {
self[parent_ix].child = None;
self.cur = None;
}
} else {
debug_assert!(self[child_ix].item.start < end_byte_ix);
debug_assert!(end_byte_ix < child_end);
self[child_ix].item.end = end_byte_ix;
self[child_ix].next = None;
self.cur = Some(child_ix);
}
break;
}
}
}
impl<T> std::fmt::Debug for Tree<T>
where
T: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn debug_tree<T>(
tree: &Tree<T>,
cur: TreeIndex,
indent: usize,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result
where
T: std::fmt::Debug,
{
for _ in 0..indent {
write!(f, " ")?;
}
writeln!(f, "{:?}", &tree[cur].item)?;
if let Some(child_ix) = tree[cur].child {
debug_tree(tree, child_ix, indent + 1, f)?;
}
if let Some(next_ix) = tree[cur].next {
debug_tree(tree, next_ix, indent, f)?;
}
Ok(())
}
if self.nodes.len() > 1 {
let cur = TreeIndex(NonZeroUsize::new(1).unwrap());
debug_tree(self, cur, 0, f)
} else {
write!(f, "Empty tree")
}
}
}
impl<T> std::ops::Index<TreeIndex> for Tree<T> {
type Output = Node<T>;
fn index(&self, ix: TreeIndex) -> &Self::Output {
self.nodes.index(ix.get())
}
}
impl<T> std::ops::IndexMut<TreeIndex> for Tree<T> {
fn index_mut(&mut self, ix: TreeIndex) -> &mut Node<T> {
self.nodes.index_mut(ix.get())
}
}