aboutsummaryrefslogtreecommitdiff
path: root/crates/mbe/src/tt_iter.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/mbe/src/tt_iter.rs')
-rw-r--r--crates/mbe/src/tt_iter.rs77
1 files changed, 77 insertions, 0 deletions
diff --git a/crates/mbe/src/tt_iter.rs b/crates/mbe/src/tt_iter.rs
index 46c420718..a362d31fc 100644
--- a/crates/mbe/src/tt_iter.rs
+++ b/crates/mbe/src/tt_iter.rs
@@ -1,5 +1,20 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use crate::{subtree_source::SubtreeTokenSource, ExpandError, ExpandResult};
4
5use parser::TreeSink;
6use syntax::SyntaxKind;
7use tt::buffer::{Cursor, TokenBuffer};
8
9macro_rules! err {
10 () => {
11 ExpandError::BindingError(format!(""))
12 };
13 ($($tt:tt)*) => {
14 ExpandError::BindingError(format!($($tt)*))
15 };
16}
17
3#[derive(Debug, Clone)] 18#[derive(Debug, Clone)]
4pub(crate) struct TtIter<'a> { 19pub(crate) struct TtIter<'a> {
5 pub(crate) inner: std::slice::Iter<'a, tt::TokenTree>, 20 pub(crate) inner: std::slice::Iter<'a, tt::TokenTree>,
@@ -56,6 +71,68 @@ impl<'a> TtIter<'a> {
56 } 71 }
57 } 72 }
58 73
74 pub(crate) fn expect_fragment(
75 &mut self,
76 fragment_kind: parser::FragmentKind,
77 ) -> ExpandResult<Option<tt::TokenTree>> {
78 struct OffsetTokenSink<'a> {
79 cursor: Cursor<'a>,
80 error: bool,
81 }
82
83 impl<'a> TreeSink for OffsetTokenSink<'a> {
84 fn token(&mut self, kind: SyntaxKind, mut n_tokens: u8) {
85 if kind == SyntaxKind::LIFETIME_IDENT {
86 n_tokens = 2;
87 }
88 for _ in 0..n_tokens {
89 self.cursor = self.cursor.bump_subtree();
90 }
91 }
92 fn start_node(&mut self, _kind: SyntaxKind) {}
93 fn finish_node(&mut self) {}
94 fn error(&mut self, _error: parser::ParseError) {
95 self.error = true;
96 }
97 }
98
99 let buffer = TokenBuffer::from_tokens(&self.inner.as_slice());
100 let mut src = SubtreeTokenSource::new(&buffer);
101 let mut sink = OffsetTokenSink { cursor: buffer.begin(), error: false };
102
103 parser::parse_fragment(&mut src, &mut sink, fragment_kind);
104
105 let mut err = None;
106 if !sink.cursor.is_root() || sink.error {
107 err = Some(err!("expected {:?}", fragment_kind));
108 }
109
110 let mut curr = buffer.begin();
111 let mut res = vec![];
112
113 if sink.cursor.is_root() {
114 while curr != sink.cursor {
115 if let Some(token) = curr.token_tree() {
116 res.push(token);
117 }
118 curr = curr.bump();
119 }
120 }
121 self.inner = self.inner.as_slice()[res.len()..].iter();
122 if res.len() == 0 && err.is_none() {
123 err = Some(err!("no tokens consumed"));
124 }
125 let res = match res.len() {
126 1 => Some(res[0].cloned()),
127 0 => None,
128 _ => Some(tt::TokenTree::Subtree(tt::Subtree {
129 delimiter: None,
130 token_trees: res.into_iter().map(|it| it.cloned()).collect(),
131 })),
132 };
133 ExpandResult { value: res, err }
134 }
135
59 pub(crate) fn peek_n(&self, n: usize) -> Option<&tt::TokenTree> { 136 pub(crate) fn peek_n(&self, n: usize) -> Option<&tt::TokenTree> {
60 self.inner.as_slice().get(n) 137 self.inner.as_slice().get(n)
61 } 138 }