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