use crate::{AstKind, NodeId, Pattern, Span};
#[derive(Clone, Copy, Debug)]
pub struct Cursor<'p> {
pat: &'p Pattern,
id: NodeId,
}
impl<'p> Cursor<'p> {
pub(crate) const fn new(pat: &'p Pattern, id: NodeId) -> Self {
Self { pat, id }
}
#[must_use]
pub const fn id(self) -> NodeId {
self.id
}
#[must_use]
pub fn kind(self) -> &'p AstKind {
&self.pat.node(self.id).kind
}
#[must_use]
pub fn span(self) -> Span {
self.pat.node(self.id).span
}
#[must_use]
pub fn text(self) -> &'p str {
self.pat.text(self.span())
}
#[must_use]
pub fn parent(self) -> Option<Self> {
self.pat
.node(self.id)
.parent
.map(|id| Self::new(self.pat, id))
}
#[must_use]
pub fn children(self) -> Children<'p> {
Children {
pat: self.pat,
inner: self.kind().children().iter(),
}
}
#[must_use]
pub fn next_sibling(self) -> Option<Self> {
self.sibling(1)
}
#[must_use]
pub fn prev_sibling(self) -> Option<Self> {
self.sibling(-1)
}
fn sibling(self, delta: isize) -> Option<Self> {
let parent = self.parent()?;
let children = parent.kind().children();
let index = children
.iter()
.position(|id| *id == self.id)?
.checked_add_signed(delta)?;
let id = *children.get(index)?;
Some(Self::new(self.pat, id))
}
#[must_use]
pub fn ancestors(self) -> Ancestors<'p> {
Ancestors {
next: self.parent(),
}
}
#[must_use]
pub fn walk(self) -> Walk<'p> {
Walk { stack: vec![self] }
}
}
pub struct Children<'p> {
pat: &'p Pattern,
inner: std::slice::Iter<'p, NodeId>,
}
impl<'p> Iterator for Children<'p> {
type Item = Cursor<'p>;
fn next(&mut self) -> Option<Self::Item> {
self.inner
.next()
.copied()
.map(|id| Cursor::new(self.pat, id))
}
}
pub struct Ancestors<'p> {
next: Option<Cursor<'p>>,
}
impl<'p> Iterator for Ancestors<'p> {
type Item = Cursor<'p>;
fn next(&mut self) -> Option<Self::Item> {
let current = self.next?;
self.next = current.parent();
Some(current)
}
}
pub struct Walk<'p> {
stack: Vec<Cursor<'p>>,
}
impl<'p> Iterator for Walk<'p> {
type Item = Cursor<'p>;
fn next(&mut self) -> Option<Self::Item> {
let node = self.stack.pop()?;
self.stack.extend(node.children().rev());
Some(node)
}
}
impl DoubleEndedIterator for Children<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
self.inner
.next_back()
.copied()
.map(|id| Cursor::new(self.pat, id))
}
}