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