]> git.lizzy.rs Git - rust.git/blob - crates/mbe/src/syntax_bridge.rs
Merge #11117
[rust.git] / crates / mbe / src / syntax_bridge.rs
1 //! Conversions between [`SyntaxNode`] and [`tt::TokenTree`].
2
3 use rustc_hash::{FxHashMap, FxHashSet};
4 use syntax::{
5     ast::{self, make::tokens::doc_comment},
6     AstToken, Parse, PreorderWithTokens, SmolStr, SyntaxElement, SyntaxKind,
7     SyntaxKind::*,
8     SyntaxNode, SyntaxToken, SyntaxTreeBuilder, TextRange, TextSize, WalkEvent, T,
9 };
10 use tt::buffer::{Cursor, TokenBuffer};
11
12 use crate::{
13     to_parser_input::to_parser_input, tt_iter::TtIter, ExpandError, ParserEntryPoint, TokenMap,
14 };
15
16 /// Convert the syntax node to a `TokenTree` (what macro
17 /// will consume).
18 pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> (tt::Subtree, TokenMap) {
19     syntax_node_to_token_tree_censored(node, &Default::default())
20 }
21
22 /// Convert the syntax node to a `TokenTree` (what macro will consume)
23 /// with the censored range excluded.
24 pub fn syntax_node_to_token_tree_censored(
25     node: &SyntaxNode,
26     censor: &FxHashSet<SyntaxNode>,
27 ) -> (tt::Subtree, TokenMap) {
28     let global_offset = node.text_range().start();
29     let mut c = Convertor::new(node, global_offset, censor);
30     let subtree = convert_tokens(&mut c);
31     c.id_alloc.map.shrink_to_fit();
32     (subtree, c.id_alloc.map)
33 }
34
35 // The following items are what `rustc` macro can be parsed into :
36 // link: https://github.com/rust-lang/rust/blob/9ebf47851a357faa4cd97f4b1dc7835f6376e639/src/libsyntax/ext/expand.rs#L141
37 // * Expr(P<ast::Expr>)                     -> token_tree_to_expr
38 // * Pat(P<ast::Pat>)                       -> token_tree_to_pat
39 // * Ty(P<ast::Ty>)                         -> token_tree_to_ty
40 // * Stmts(SmallVec<[ast::Stmt; 1]>)        -> token_tree_to_stmts
41 // * Items(SmallVec<[P<ast::Item>; 1]>)     -> token_tree_to_items
42 //
43 // * TraitItems(SmallVec<[ast::TraitItem; 1]>)
44 // * AssocItems(SmallVec<[ast::AssocItem; 1]>)
45 // * ForeignItems(SmallVec<[ast::ForeignItem; 1]>
46
47 pub fn token_tree_to_syntax_node(
48     tt: &tt::Subtree,
49     entry_point: ParserEntryPoint,
50 ) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> {
51     let buffer = match tt {
52         tt::Subtree { delimiter: None, token_trees } => {
53             TokenBuffer::from_tokens(token_trees.as_slice())
54         }
55         _ => TokenBuffer::from_subtree(tt),
56     };
57     let parser_input = to_parser_input(&buffer);
58     let parser_output = parser::parse(&parser_input, entry_point);
59     let mut tree_sink = TtTreeSink::new(buffer.begin());
60     for event in parser_output.iter() {
61         match event {
62             parser::Step::Token { kind, n_input_tokens: n_raw_tokens } => {
63                 tree_sink.token(kind, n_raw_tokens)
64             }
65             parser::Step::Enter { kind } => tree_sink.start_node(kind),
66             parser::Step::Exit => tree_sink.finish_node(),
67             parser::Step::Error { msg } => tree_sink.error(msg.to_string()),
68         }
69     }
70     if tree_sink.roots.len() != 1 {
71         return Err(ExpandError::ConversionError);
72     }
73     //FIXME: would be cool to report errors
74     let (parse, range_map) = tree_sink.finish();
75     Ok((parse, range_map))
76 }
77
78 /// Convert a string to a `TokenTree`
79 pub fn parse_to_token_tree(text: &str) -> Option<(tt::Subtree, TokenMap)> {
80     let lexed = parser::LexedStr::new(text);
81     if lexed.errors().next().is_some() {
82         return None;
83     }
84
85     let mut conv = RawConvertor {
86         lexed: lexed,
87         pos: 0,
88         id_alloc: TokenIdAlloc {
89             map: Default::default(),
90             global_offset: TextSize::default(),
91             next_id: 0,
92         },
93     };
94
95     let subtree = convert_tokens(&mut conv);
96     Some((subtree, conv.id_alloc.map))
97 }
98
99 /// Split token tree with separate expr: $($e:expr)SEP*
100 pub fn parse_exprs_with_sep(tt: &tt::Subtree, sep: char) -> Vec<tt::Subtree> {
101     if tt.token_trees.is_empty() {
102         return Vec::new();
103     }
104
105     let mut iter = TtIter::new(tt);
106     let mut res = Vec::new();
107
108     while iter.peek_n(0).is_some() {
109         let expanded = iter.expect_fragment(ParserEntryPoint::Expr);
110
111         res.push(match expanded.value {
112             None => break,
113             Some(tt @ tt::TokenTree::Leaf(_)) => {
114                 tt::Subtree { delimiter: None, token_trees: vec![tt] }
115             }
116             Some(tt::TokenTree::Subtree(tt)) => tt,
117         });
118
119         let mut fork = iter.clone();
120         if fork.expect_char(sep).is_err() {
121             break;
122         }
123         iter = fork;
124     }
125
126     if iter.peek_n(0).is_some() {
127         res.push(tt::Subtree { delimiter: None, token_trees: iter.into_iter().cloned().collect() });
128     }
129
130     res
131 }
132
133 fn convert_tokens<C: TokenConvertor>(conv: &mut C) -> tt::Subtree {
134     struct StackEntry {
135         subtree: tt::Subtree,
136         idx: usize,
137         open_range: TextRange,
138     }
139
140     let entry = StackEntry {
141         subtree: tt::Subtree { delimiter: None, ..Default::default() },
142         // never used (delimiter is `None`)
143         idx: !0,
144         open_range: TextRange::empty(TextSize::of('.')),
145     };
146     let mut stack = vec![entry];
147
148     loop {
149         let entry = stack.last_mut().unwrap();
150         let result = &mut entry.subtree.token_trees;
151         let (token, range) = match conv.bump() {
152             None => break,
153             Some(it) => it,
154         };
155
156         let k: SyntaxKind = token.kind(&conv);
157         if k == COMMENT {
158             if let Some(tokens) = conv.convert_doc_comment(&token) {
159                 // FIXME: There has to be a better way to do this
160                 // Add the comments token id to the converted doc string
161                 let id = conv.id_alloc().alloc(range);
162                 result.extend(tokens.into_iter().map(|mut tt| {
163                     if let tt::TokenTree::Subtree(sub) = &mut tt {
164                         if let tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) = &mut sub.token_trees[2]
165                         {
166                             lit.id = id
167                         }
168                     }
169                     tt
170                 }));
171             }
172             continue;
173         }
174
175         result.push(if k.is_punct() && k != UNDERSCORE {
176             assert_eq!(range.len(), TextSize::of('.'));
177
178             if let Some(delim) = entry.subtree.delimiter {
179                 let expected = match delim.kind {
180                     tt::DelimiterKind::Parenthesis => T![')'],
181                     tt::DelimiterKind::Brace => T!['}'],
182                     tt::DelimiterKind::Bracket => T![']'],
183                 };
184
185                 if k == expected {
186                     let entry = stack.pop().unwrap();
187                     conv.id_alloc().close_delim(entry.idx, Some(range));
188                     stack.last_mut().unwrap().subtree.token_trees.push(entry.subtree.into());
189                     continue;
190                 }
191             }
192
193             let delim = match k {
194                 T!['('] => Some(tt::DelimiterKind::Parenthesis),
195                 T!['{'] => Some(tt::DelimiterKind::Brace),
196                 T!['['] => Some(tt::DelimiterKind::Bracket),
197                 _ => None,
198             };
199
200             if let Some(kind) = delim {
201                 let mut subtree = tt::Subtree::default();
202                 let (id, idx) = conv.id_alloc().open_delim(range);
203                 subtree.delimiter = Some(tt::Delimiter { id, kind });
204                 stack.push(StackEntry { subtree, idx, open_range: range });
205                 continue;
206             } else {
207                 let spacing = match conv.peek() {
208                     Some(next)
209                         if next.kind(&conv).is_trivia()
210                             || next.kind(&conv) == T!['[']
211                             || next.kind(&conv) == T!['{']
212                             || next.kind(&conv) == T!['('] =>
213                     {
214                         tt::Spacing::Alone
215                     }
216                     Some(next) if next.kind(&conv).is_punct() && next.kind(&conv) != UNDERSCORE => {
217                         tt::Spacing::Joint
218                     }
219                     _ => tt::Spacing::Alone,
220                 };
221                 let char = match token.to_char(&conv) {
222                     Some(c) => c,
223                     None => {
224                         panic!("Token from lexer must be single char: token = {:#?}", token);
225                     }
226                 };
227                 tt::Leaf::from(tt::Punct { char, spacing, id: conv.id_alloc().alloc(range) }).into()
228             }
229         } else {
230             macro_rules! make_leaf {
231                 ($i:ident) => {
232                     tt::$i { id: conv.id_alloc().alloc(range), text: token.to_text(conv) }.into()
233                 };
234             }
235             let leaf: tt::Leaf = match k {
236                 T![true] | T![false] => make_leaf!(Ident),
237                 IDENT => make_leaf!(Ident),
238                 UNDERSCORE => make_leaf!(Ident),
239                 k if k.is_keyword() => make_leaf!(Ident),
240                 k if k.is_literal() => make_leaf!(Literal),
241                 LIFETIME_IDENT => {
242                     let char_unit = TextSize::of('\'');
243                     let r = TextRange::at(range.start(), char_unit);
244                     let apostrophe = tt::Leaf::from(tt::Punct {
245                         char: '\'',
246                         spacing: tt::Spacing::Joint,
247                         id: conv.id_alloc().alloc(r),
248                     });
249                     result.push(apostrophe.into());
250
251                     let r = TextRange::at(range.start() + char_unit, range.len() - char_unit);
252                     let ident = tt::Leaf::from(tt::Ident {
253                         text: SmolStr::new(&token.to_text(conv)[1..]),
254                         id: conv.id_alloc().alloc(r),
255                     });
256                     result.push(ident.into());
257                     continue;
258                 }
259                 _ => continue,
260             };
261
262             leaf.into()
263         });
264     }
265
266     // If we get here, we've consumed all input tokens.
267     // We might have more than one subtree in the stack, if the delimiters are improperly balanced.
268     // Merge them so we're left with one.
269     while stack.len() > 1 {
270         let entry = stack.pop().unwrap();
271         let parent = stack.last_mut().unwrap();
272
273         conv.id_alloc().close_delim(entry.idx, None);
274         let leaf: tt::Leaf = tt::Punct {
275             id: conv.id_alloc().alloc(entry.open_range),
276             char: match entry.subtree.delimiter.unwrap().kind {
277                 tt::DelimiterKind::Parenthesis => '(',
278                 tt::DelimiterKind::Brace => '{',
279                 tt::DelimiterKind::Bracket => '[',
280             },
281             spacing: tt::Spacing::Alone,
282         }
283         .into();
284         parent.subtree.token_trees.push(leaf.into());
285         parent.subtree.token_trees.extend(entry.subtree.token_trees);
286     }
287
288     let subtree = stack.pop().unwrap().subtree;
289     if subtree.token_trees.len() == 1 {
290         if let tt::TokenTree::Subtree(first) = &subtree.token_trees[0] {
291             return first.clone();
292         }
293     }
294     subtree
295 }
296
297 /// Returns the textual content of a doc comment block as a quoted string
298 /// That is, strips leading `///` (or `/**`, etc)
299 /// and strips the ending `*/`
300 /// And then quote the string, which is needed to convert to `tt::Literal`
301 fn doc_comment_text(comment: &ast::Comment) -> SmolStr {
302     let prefix_len = comment.prefix().len();
303     let mut text = &comment.text()[prefix_len..];
304
305     // Remove ending "*/"
306     if comment.kind().shape == ast::CommentShape::Block {
307         text = &text[0..text.len() - 2];
308     }
309
310     // Quote the string
311     // Note that `tt::Literal` expect an escaped string
312     let text = format!("\"{}\"", text.escape_debug());
313     text.into()
314 }
315
316 fn convert_doc_comment(token: &syntax::SyntaxToken) -> Option<Vec<tt::TokenTree>> {
317     cov_mark::hit!(test_meta_doc_comments);
318     let comment = ast::Comment::cast(token.clone())?;
319     let doc = comment.kind().doc?;
320
321     // Make `doc="\" Comments\""
322     let meta_tkns = vec![mk_ident("doc"), mk_punct('='), mk_doc_literal(&comment)];
323
324     // Make `#![]`
325     let mut token_trees = vec![mk_punct('#')];
326     if let ast::CommentPlacement::Inner = doc {
327         token_trees.push(mk_punct('!'));
328     }
329     token_trees.push(tt::TokenTree::from(tt::Subtree {
330         delimiter: Some(tt::Delimiter {
331             kind: tt::DelimiterKind::Bracket,
332             id: tt::TokenId::unspecified(),
333         }),
334         token_trees: meta_tkns,
335     }));
336
337     return Some(token_trees);
338
339     // Helper functions
340     fn mk_ident(s: &str) -> tt::TokenTree {
341         tt::TokenTree::from(tt::Leaf::from(tt::Ident {
342             text: s.into(),
343             id: tt::TokenId::unspecified(),
344         }))
345     }
346
347     fn mk_punct(c: char) -> tt::TokenTree {
348         tt::TokenTree::from(tt::Leaf::from(tt::Punct {
349             char: c,
350             spacing: tt::Spacing::Alone,
351             id: tt::TokenId::unspecified(),
352         }))
353     }
354
355     fn mk_doc_literal(comment: &ast::Comment) -> tt::TokenTree {
356         let lit = tt::Literal { text: doc_comment_text(comment), id: tt::TokenId::unspecified() };
357
358         tt::TokenTree::from(tt::Leaf::from(lit))
359     }
360 }
361
362 struct TokenIdAlloc {
363     map: TokenMap,
364     global_offset: TextSize,
365     next_id: u32,
366 }
367
368 impl TokenIdAlloc {
369     fn alloc(&mut self, absolute_range: TextRange) -> tt::TokenId {
370         let relative_range = absolute_range - self.global_offset;
371         let token_id = tt::TokenId(self.next_id);
372         self.next_id += 1;
373         self.map.insert(token_id, relative_range);
374         token_id
375     }
376
377     fn open_delim(&mut self, open_abs_range: TextRange) -> (tt::TokenId, usize) {
378         let token_id = tt::TokenId(self.next_id);
379         self.next_id += 1;
380         let idx = self.map.insert_delim(
381             token_id,
382             open_abs_range - self.global_offset,
383             open_abs_range - self.global_offset,
384         );
385         (token_id, idx)
386     }
387
388     fn close_delim(&mut self, idx: usize, close_abs_range: Option<TextRange>) {
389         match close_abs_range {
390             None => {
391                 self.map.remove_delim(idx);
392             }
393             Some(close) => {
394                 self.map.update_close_delim(idx, close - self.global_offset);
395             }
396         }
397     }
398 }
399
400 /// A Raw Token (straightly from lexer) convertor
401 struct RawConvertor<'a> {
402     lexed: parser::LexedStr<'a>,
403     pos: usize,
404     id_alloc: TokenIdAlloc,
405 }
406
407 trait SrcToken<Ctx>: std::fmt::Debug {
408     fn kind(&self, ctx: &Ctx) -> SyntaxKind;
409
410     fn to_char(&self, ctx: &Ctx) -> Option<char>;
411
412     fn to_text(&self, ctx: &Ctx) -> SmolStr;
413 }
414
415 trait TokenConvertor: Sized {
416     type Token: SrcToken<Self>;
417
418     fn convert_doc_comment(&self, token: &Self::Token) -> Option<Vec<tt::TokenTree>>;
419
420     fn bump(&mut self) -> Option<(Self::Token, TextRange)>;
421
422     fn peek(&self) -> Option<Self::Token>;
423
424     fn id_alloc(&mut self) -> &mut TokenIdAlloc;
425 }
426
427 impl<'a> SrcToken<RawConvertor<'a>> for usize {
428     fn kind(&self, ctx: &RawConvertor<'a>) -> SyntaxKind {
429         ctx.lexed.kind(*self)
430     }
431
432     fn to_char(&self, ctx: &RawConvertor<'a>) -> Option<char> {
433         ctx.lexed.text(*self).chars().next()
434     }
435
436     fn to_text(&self, ctx: &RawConvertor<'_>) -> SmolStr {
437         ctx.lexed.text(*self).into()
438     }
439 }
440
441 impl<'a> TokenConvertor for RawConvertor<'a> {
442     type Token = usize;
443
444     fn convert_doc_comment(&self, token: &usize) -> Option<Vec<tt::TokenTree>> {
445         let text = self.lexed.text(*token);
446         convert_doc_comment(&doc_comment(text))
447     }
448
449     fn bump(&mut self) -> Option<(Self::Token, TextRange)> {
450         if self.pos == self.lexed.len() {
451             return None;
452         }
453         let token = self.pos;
454         self.pos += 1;
455         let range = self.lexed.text_range(token);
456         let range = TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap());
457
458         Some((token, range))
459     }
460
461     fn peek(&self) -> Option<Self::Token> {
462         if self.pos == self.lexed.len() {
463             return None;
464         }
465         Some(self.pos)
466     }
467
468     fn id_alloc(&mut self) -> &mut TokenIdAlloc {
469         &mut self.id_alloc
470     }
471 }
472
473 struct Convertor<'c> {
474     id_alloc: TokenIdAlloc,
475     current: Option<SyntaxToken>,
476     preorder: PreorderWithTokens,
477     censor: &'c FxHashSet<SyntaxNode>,
478     range: TextRange,
479     punct_offset: Option<(SyntaxToken, TextSize)>,
480 }
481
482 impl<'c> Convertor<'c> {
483     fn new(
484         node: &SyntaxNode,
485         global_offset: TextSize,
486         censor: &'c FxHashSet<SyntaxNode>,
487     ) -> Convertor<'c> {
488         let range = node.text_range();
489         let mut preorder = node.preorder_with_tokens();
490         let first = Self::next_token(&mut preorder, censor);
491         Convertor {
492             id_alloc: { TokenIdAlloc { map: TokenMap::default(), global_offset, next_id: 0 } },
493             current: first,
494             preorder,
495             range,
496             censor,
497             punct_offset: None,
498         }
499     }
500
501     fn next_token(
502         preorder: &mut PreorderWithTokens,
503         censor: &FxHashSet<SyntaxNode>,
504     ) -> Option<SyntaxToken> {
505         while let Some(ev) = preorder.next() {
506             let ele = match ev {
507                 WalkEvent::Enter(ele) => ele,
508                 _ => continue,
509             };
510             match ele {
511                 SyntaxElement::Token(t) => return Some(t),
512                 SyntaxElement::Node(node) if censor.contains(&node) => preorder.skip_subtree(),
513                 SyntaxElement::Node(_) => (),
514             }
515         }
516         None
517     }
518 }
519
520 #[derive(Debug)]
521 enum SynToken {
522     Ordinary(SyntaxToken),
523     Punch(SyntaxToken, TextSize),
524 }
525
526 impl SynToken {
527     fn token(&self) -> &SyntaxToken {
528         match self {
529             SynToken::Ordinary(it) => it,
530             SynToken::Punch(it, _) => it,
531         }
532     }
533 }
534
535 impl<'a> SrcToken<Convertor<'a>> for SynToken {
536     fn kind(&self, _ctx: &Convertor<'a>) -> SyntaxKind {
537         self.token().kind()
538     }
539     fn to_char(&self, _ctx: &Convertor<'a>) -> Option<char> {
540         match self {
541             SynToken::Ordinary(_) => None,
542             SynToken::Punch(it, i) => it.text().chars().nth((*i).into()),
543         }
544     }
545     fn to_text(&self, _ctx: &Convertor<'a>) -> SmolStr {
546         self.token().text().into()
547     }
548 }
549
550 impl TokenConvertor for Convertor<'_> {
551     type Token = SynToken;
552     fn convert_doc_comment(&self, token: &Self::Token) -> Option<Vec<tt::TokenTree>> {
553         convert_doc_comment(token.token())
554     }
555
556     fn bump(&mut self) -> Option<(Self::Token, TextRange)> {
557         if let Some((punct, offset)) = self.punct_offset.clone() {
558             if usize::from(offset) + 1 < punct.text().len() {
559                 let offset = offset + TextSize::of('.');
560                 let range = punct.text_range();
561                 self.punct_offset = Some((punct.clone(), offset));
562                 let range = TextRange::at(range.start() + offset, TextSize::of('.'));
563                 return Some((SynToken::Punch(punct, offset), range));
564             }
565         }
566
567         let curr = self.current.clone()?;
568         if !&self.range.contains_range(curr.text_range()) {
569             return None;
570         }
571         self.current = Self::next_token(&mut self.preorder, self.censor);
572         let token = if curr.kind().is_punct() {
573             let range = curr.text_range();
574             let range = TextRange::at(range.start(), TextSize::of('.'));
575             self.punct_offset = Some((curr.clone(), 0.into()));
576             (SynToken::Punch(curr, 0.into()), range)
577         } else {
578             self.punct_offset = None;
579             let range = curr.text_range();
580             (SynToken::Ordinary(curr), range)
581         };
582
583         Some(token)
584     }
585
586     fn peek(&self) -> Option<Self::Token> {
587         if let Some((punct, mut offset)) = self.punct_offset.clone() {
588             offset += TextSize::of('.');
589             if usize::from(offset) < punct.text().len() {
590                 return Some(SynToken::Punch(punct, offset));
591             }
592         }
593
594         let curr = self.current.clone()?;
595         if !self.range.contains_range(curr.text_range()) {
596             return None;
597         }
598
599         let token = if curr.kind().is_punct() {
600             SynToken::Punch(curr, 0.into())
601         } else {
602             SynToken::Ordinary(curr)
603         };
604         Some(token)
605     }
606
607     fn id_alloc(&mut self) -> &mut TokenIdAlloc {
608         &mut self.id_alloc
609     }
610 }
611
612 struct TtTreeSink<'a> {
613     buf: String,
614     cursor: Cursor<'a>,
615     open_delims: FxHashMap<tt::TokenId, TextSize>,
616     text_pos: TextSize,
617     inner: SyntaxTreeBuilder,
618     token_map: TokenMap,
619
620     // Number of roots
621     // Use for detect ill-form tree which is not single root
622     roots: smallvec::SmallVec<[usize; 1]>,
623 }
624
625 impl<'a> TtTreeSink<'a> {
626     fn new(cursor: Cursor<'a>) -> Self {
627         TtTreeSink {
628             buf: String::new(),
629             cursor,
630             open_delims: FxHashMap::default(),
631             text_pos: 0.into(),
632             inner: SyntaxTreeBuilder::default(),
633             roots: smallvec::SmallVec::new(),
634             token_map: TokenMap::default(),
635         }
636     }
637
638     fn finish(mut self) -> (Parse<SyntaxNode>, TokenMap) {
639         self.token_map.shrink_to_fit();
640         (self.inner.finish(), self.token_map)
641     }
642 }
643
644 fn delim_to_str(d: tt::DelimiterKind, closing: bool) -> &'static str {
645     let texts = match d {
646         tt::DelimiterKind::Parenthesis => "()",
647         tt::DelimiterKind::Brace => "{}",
648         tt::DelimiterKind::Bracket => "[]",
649     };
650
651     let idx = closing as usize;
652     &texts[idx..texts.len() - (1 - idx)]
653 }
654
655 impl<'a> TtTreeSink<'a> {
656     fn token(&mut self, kind: SyntaxKind, mut n_tokens: u8) {
657         if kind == LIFETIME_IDENT {
658             n_tokens = 2;
659         }
660
661         let mut last = self.cursor;
662         for _ in 0..n_tokens {
663             let tmp_str: SmolStr;
664             if self.cursor.eof() {
665                 break;
666             }
667             last = self.cursor;
668             let text: &str = loop {
669                 break match self.cursor.token_tree() {
670                     Some(tt::buffer::TokenTreeRef::Leaf(leaf, _)) => {
671                         // Mark the range if needed
672                         let (text, id) = match leaf {
673                             tt::Leaf::Ident(ident) => (&ident.text, ident.id),
674                             tt::Leaf::Punct(punct) => {
675                                 assert!(punct.char.is_ascii());
676                                 let char = &(punct.char as u8);
677                                 tmp_str = SmolStr::new_inline(
678                                     std::str::from_utf8(std::slice::from_ref(char)).unwrap(),
679                                 );
680                                 (&tmp_str, punct.id)
681                             }
682                             tt::Leaf::Literal(lit) => (&lit.text, lit.id),
683                         };
684                         let range = TextRange::at(self.text_pos, TextSize::of(text.as_str()));
685                         self.token_map.insert(id, range);
686                         self.cursor = self.cursor.bump();
687                         text
688                     }
689                     Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => {
690                         self.cursor = self.cursor.subtree().unwrap();
691                         match subtree.delimiter {
692                             Some(d) => {
693                                 self.open_delims.insert(d.id, self.text_pos);
694                                 delim_to_str(d.kind, false)
695                             }
696                             None => continue,
697                         }
698                     }
699                     None => {
700                         let parent = self.cursor.end().unwrap();
701                         self.cursor = self.cursor.bump();
702                         match parent.delimiter {
703                             Some(d) => {
704                                 if let Some(open_delim) = self.open_delims.get(&d.id) {
705                                     let open_range = TextRange::at(*open_delim, TextSize::of('('));
706                                     let close_range =
707                                         TextRange::at(self.text_pos, TextSize::of('('));
708                                     self.token_map.insert_delim(d.id, open_range, close_range);
709                                 }
710                                 delim_to_str(d.kind, true)
711                             }
712                             None => continue,
713                         }
714                     }
715                 };
716             };
717             self.buf += text;
718             self.text_pos += TextSize::of(text);
719         }
720
721         self.inner.token(kind, self.buf.as_str());
722         self.buf.clear();
723         // Add whitespace between adjoint puncts
724         let next = last.bump();
725         if let (
726             Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(curr), _)),
727             Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(_), _)),
728         ) = (last.token_tree(), next.token_tree())
729         {
730             // Note: We always assume the semi-colon would be the last token in
731             // other parts of RA such that we don't add whitespace here.
732             if curr.spacing == tt::Spacing::Alone && curr.char != ';' {
733                 self.inner.token(WHITESPACE, " ");
734                 self.text_pos += TextSize::of(' ');
735             }
736         }
737     }
738
739     fn start_node(&mut self, kind: SyntaxKind) {
740         self.inner.start_node(kind);
741
742         match self.roots.last_mut() {
743             None | Some(0) => self.roots.push(1),
744             Some(ref mut n) => **n += 1,
745         };
746     }
747
748     fn finish_node(&mut self) {
749         self.inner.finish_node();
750         *self.roots.last_mut().unwrap() -= 1;
751     }
752
753     fn error(&mut self, error: String) {
754         self.inner.error(error, self.text_pos)
755     }
756 }