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