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