Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/tt/src/iter.rs')
-rw-r--r--crates/tt/src/iter.rs117
1 files changed, 93 insertions, 24 deletions
diff --git a/crates/tt/src/iter.rs b/crates/tt/src/iter.rs
index 4d7fe0b5a0..1d88218810 100644
--- a/crates/tt/src/iter.rs
+++ b/crates/tt/src/iter.rs
@@ -1,51 +1,64 @@
//! A "Parser" structure for token trees. We use this when parsing a declarative
//! macro definition into a list of patterns and templates.
+use std::fmt;
+
use arrayvec::ArrayVec;
use intern::sym;
-use crate::{Ident, Leaf, Punct, Spacing, Subtree, TokenTree};
+use crate::{Ident, Leaf, Punct, Spacing, Subtree, TokenTree, TokenTreesView};
-#[derive(Debug, Clone)]
+#[derive(Clone)]
pub struct TtIter<'a, S> {
inner: std::slice::Iter<'a, TokenTree<S>>,
}
-impl<'a, S: Copy> TtIter<'a, S> {
- pub fn new(subtree: &'a Subtree<S>) -> TtIter<'a, S> {
- TtIter { inner: subtree.token_trees.iter() }
+impl<S: Copy + fmt::Debug> fmt::Debug for TtIter<'_, S> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("TtIter").field("remaining", &self.remaining()).finish()
}
+}
- pub fn new_iter(iter: std::slice::Iter<'a, TokenTree<S>>) -> TtIter<'a, S> {
- TtIter { inner: iter }
+#[derive(Clone, Copy)]
+pub struct TtIterSavepoint<'a, S>(&'a [TokenTree<S>]);
+
+impl<'a, S: Copy> TtIterSavepoint<'a, S> {
+ pub fn remaining(self) -> TokenTreesView<'a, S> {
+ TokenTreesView::new(self.0)
+ }
+}
+
+impl<'a, S: Copy> TtIter<'a, S> {
+ pub(crate) fn new(tt: &'a [TokenTree<S>]) -> TtIter<'a, S> {
+ TtIter { inner: tt.iter() }
}
pub fn expect_char(&mut self, char: char) -> Result<(), ()> {
match self.next() {
- Some(&TokenTree::Leaf(Leaf::Punct(Punct { char: c, .. }))) if c == char => Ok(()),
+ Some(TtElement::Leaf(&Leaf::Punct(Punct { char: c, .. }))) if c == char => Ok(()),
_ => Err(()),
}
}
pub fn expect_any_char(&mut self, chars: &[char]) -> Result<(), ()> {
match self.next() {
- Some(TokenTree::Leaf(Leaf::Punct(Punct { char: c, .. }))) if chars.contains(c) => {
+ Some(TtElement::Leaf(Leaf::Punct(Punct { char: c, .. }))) if chars.contains(c) => {
Ok(())
}
_ => Err(()),
}
}
- pub fn expect_subtree(&mut self) -> Result<&'a Subtree<S>, ()> {
+ pub fn expect_subtree(&mut self) -> Result<(&'a Subtree<S>, TtIter<'a, S>), ()> {
match self.next() {
- Some(TokenTree::Subtree(it)) => Ok(it),
+ Some(TtElement::Subtree(subtree, iter)) => Ok((subtree, iter)),
_ => Err(()),
}
}
pub fn expect_leaf(&mut self) -> Result<&'a Leaf<S>, ()> {
match self.next() {
- Some(TokenTree::Leaf(it)) => Ok(it),
+ Some(TtElement::Leaf(it)) => Ok(it),
_ => Err(()),
}
}
@@ -99,7 +112,7 @@ impl<'a, S: Copy> TtIter<'a, S> {
/// This method currently may return a single quotation, which is part of lifetime ident and
/// conceptually not a punct in the context of mbe. Callers should handle this.
pub fn expect_glued_punct(&mut self) -> Result<ArrayVec<Punct<S>, 3>, ()> {
- let TokenTree::Leaf(Leaf::Punct(first)) = self.next().ok_or(())?.clone() else {
+ let TtElement::Leaf(&Leaf::Punct(first)) = self.next().ok_or(())? else {
return Err(());
};
@@ -147,28 +160,84 @@ impl<'a, S: Copy> TtIter<'a, S> {
}
Ok(res)
}
- pub fn peek_n(&self, n: usize) -> Option<&'a TokenTree<S>> {
+
+ /// This method won't check for subtrees, so the nth token tree may not be the nth sibling of the current tree.
+ fn peek_n(&self, n: usize) -> Option<&'a TokenTree<S>> {
self.inner.as_slice().get(n)
}
+ pub fn peek(&self) -> Option<TtElement<'a, S>> {
+ match self.inner.as_slice().first()? {
+ TokenTree::Leaf(leaf) => Some(TtElement::Leaf(leaf)),
+ TokenTree::Subtree(subtree) => {
+ let nested_iter =
+ TtIter { inner: self.inner.as_slice()[1..][..subtree.usize_len()].iter() };
+ Some(TtElement::Subtree(subtree, nested_iter))
+ }
+ }
+ }
+
+ /// Equivalent to `peek().is_none()`, but a bit faster.
+ pub fn is_empty(&self) -> bool {
+ self.inner.len() == 0
+ }
+
pub fn next_span(&self) -> Option<S> {
Some(self.inner.as_slice().first()?.first_span())
}
- pub fn as_slice(&self) -> &'a [TokenTree<S>] {
- self.inner.as_slice()
+ pub fn remaining(&self) -> TokenTreesView<'a, S> {
+ TokenTreesView::new(self.inner.as_slice())
}
-}
-impl<'a, S> Iterator for TtIter<'a, S> {
- type Item = &'a TokenTree<S>;
- fn next(&mut self) -> Option<Self::Item> {
- self.inner.next()
+ /// **Warning**: This advances `skip` **flat** token trees, subtrees account for children+1!
+ pub fn flat_advance(&mut self, skip: usize) {
+ self.inner = self.inner.as_slice()[skip..].iter();
+ }
+
+ pub fn savepoint(&self) -> TtIterSavepoint<'a, S> {
+ TtIterSavepoint(self.inner.as_slice())
+ }
+
+ pub fn from_savepoint(&self, savepoint: TtIterSavepoint<'a, S>) -> TokenTreesView<'a, S> {
+ let len = (self.inner.as_slice().as_ptr() as usize - savepoint.0.as_ptr() as usize)
+ / size_of::<TokenTree<S>>();
+ TokenTreesView::new(&savepoint.0[..len])
}
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.inner.size_hint()
+ pub fn next_as_view(&mut self) -> Option<TokenTreesView<'a, S>> {
+ let savepoint = self.savepoint();
+ self.next()?;
+ Some(self.from_savepoint(savepoint))
}
}
-impl<S> std::iter::ExactSizeIterator for TtIter<'_, S> {}
+pub enum TtElement<'a, S> {
+ Leaf(&'a Leaf<S>),
+ Subtree(&'a Subtree<S>, TtIter<'a, S>),
+}
+
+impl<S: Copy> TtElement<'_, S> {
+ #[inline]
+ pub fn first_span(&self) -> S {
+ match self {
+ TtElement::Leaf(it) => *it.span(),
+ TtElement::Subtree(it, _) => it.delimiter.open,
+ }
+ }
+}
+
+impl<'a, S> Iterator for TtIter<'a, S> {
+ type Item = TtElement<'a, S>;
+ fn next(&mut self) -> Option<Self::Item> {
+ match self.inner.next()? {
+ TokenTree::Leaf(leaf) => Some(TtElement::Leaf(leaf)),
+ TokenTree::Subtree(subtree) => {
+ let nested_iter =
+ TtIter { inner: self.inner.as_slice()[..subtree.usize_len()].iter() };
+ self.inner = self.inner.as_slice()[subtree.usize_len()..].iter();
+ Some(TtElement::Subtree(subtree, nested_iter))
+ }
+ }
+ }
+}