aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe/src/syntax_bridge.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_mbe/src/syntax_bridge.rs')
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs242
1 files changed, 171 insertions, 71 deletions
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index 1de399fee..ea2cac069 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -2,25 +2,45 @@
2 2
3use ra_parser::{FragmentKind, ParseError, TreeSink}; 3use ra_parser::{FragmentKind, ParseError, TreeSink};
4use ra_syntax::{ 4use ra_syntax::{
5 ast, AstNode, AstToken, NodeOrToken, Parse, SmolStr, SyntaxKind, SyntaxKind::*, SyntaxNode, 5 ast, AstToken, NodeOrToken, Parse, SmolStr, SyntaxKind, SyntaxKind::*, SyntaxNode,
6 SyntaxTreeBuilder, TextRange, TextUnit, T, 6 SyntaxTreeBuilder, TextRange, TextUnit, T,
7}; 7};
8use rustc_hash::FxHashMap;
8use std::iter::successors; 9use std::iter::successors;
9use tt::buffer::{Cursor, TokenBuffer}; 10use tt::buffer::{Cursor, TokenBuffer};
10 11
11use crate::subtree_source::SubtreeTokenSource; 12use crate::subtree_source::SubtreeTokenSource;
12use crate::ExpandError; 13use crate::ExpandError;
13 14
15#[derive(Debug, PartialEq, Eq, Clone, Copy)]
16pub enum TokenTextRange {
17 Token(TextRange),
18 Delimiter(TextRange, TextRange),
19}
20
21impl TokenTextRange {
22 pub fn by_kind(self, kind: SyntaxKind) -> Option<TextRange> {
23 match self {
24 TokenTextRange::Token(it) => Some(it),
25 TokenTextRange::Delimiter(open, close) => match kind {
26 T!['{'] | T!['('] | T!['['] => Some(open),
27 T!['}'] | T![')'] | T![']'] => Some(close),
28 _ => None,
29 },
30 }
31 }
32}
33
14/// Maps `tt::TokenId` to the relative range of the original token. 34/// Maps `tt::TokenId` to the relative range of the original token.
15#[derive(Debug, PartialEq, Eq, Default)] 35#[derive(Debug, PartialEq, Eq, Default)]
16pub struct TokenMap { 36pub struct TokenMap {
17 /// Maps `tt::TokenId` to the *relative* source range. 37 /// Maps `tt::TokenId` to the *relative* source range.
18 entries: Vec<(tt::TokenId, TextRange)>, 38 entries: Vec<(tt::TokenId, TokenTextRange)>,
19} 39}
20 40
21/// Convert the syntax tree (what user has written) to a `TokenTree` (what macro 41/// Convert the syntax tree (what user has written) to a `TokenTree` (what macro
22/// will consume). 42/// will consume).
23pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap)> { 43pub fn ast_to_token_tree(ast: &impl ast::AstNode) -> Option<(tt::Subtree, TokenMap)> {
24 syntax_node_to_token_tree(ast.syntax()) 44 syntax_node_to_token_tree(ast.syntax())
25} 45}
26 46
@@ -51,7 +71,7 @@ pub fn token_tree_to_syntax_node(
51) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> { 71) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> {
52 let tmp; 72 let tmp;
53 let tokens = match tt { 73 let tokens = match tt {
54 tt::Subtree { delimiter: tt::Delimiter::None, token_trees } => token_trees.as_slice(), 74 tt::Subtree { delimiter: None, token_trees } => token_trees.as_slice(),
55 _ => { 75 _ => {
56 tmp = [tt.clone().into()]; 76 tmp = [tt.clone().into()];
57 &tmp[..] 77 &tmp[..]
@@ -71,17 +91,32 @@ pub fn token_tree_to_syntax_node(
71 91
72impl TokenMap { 92impl TokenMap {
73 pub fn token_by_range(&self, relative_range: TextRange) -> Option<tt::TokenId> { 93 pub fn token_by_range(&self, relative_range: TextRange) -> Option<tt::TokenId> {
74 let &(token_id, _) = self.entries.iter().find(|(_, range)| *range == relative_range)?; 94 let &(token_id, _) = self.entries.iter().find(|(_, range)| match range {
95 TokenTextRange::Token(it) => *it == relative_range,
96 TokenTextRange::Delimiter(open, close) => {
97 *open == relative_range || *close == relative_range
98 }
99 })?;
75 Some(token_id) 100 Some(token_id)
76 } 101 }
77 102
78 pub fn range_by_token(&self, token_id: tt::TokenId) -> Option<TextRange> { 103 pub fn range_by_token(&self, token_id: tt::TokenId) -> Option<TokenTextRange> {
79 let &(_, range) = self.entries.iter().find(|(tid, _)| *tid == token_id)?; 104 let &(_, range) = self.entries.iter().find(|(tid, _)| *tid == token_id)?;
80 Some(range) 105 Some(range)
81 } 106 }
82 107
83 fn insert(&mut self, token_id: tt::TokenId, relative_range: TextRange) { 108 fn insert(&mut self, token_id: tt::TokenId, relative_range: TextRange) {
84 self.entries.push((token_id, relative_range)); 109 self.entries.push((token_id, TokenTextRange::Token(relative_range)));
110 }
111
112 fn insert_delim(
113 &mut self,
114 token_id: tt::TokenId,
115 open_relative_range: TextRange,
116 close_relative_range: TextRange,
117 ) {
118 self.entries
119 .push((token_id, TokenTextRange::Delimiter(open_relative_range, close_relative_range)));
85 } 120 }
86} 121}
87 122
@@ -121,7 +156,10 @@ fn convert_doc_comment(token: &ra_syntax::SyntaxToken) -> Option<Vec<tt::TokenTr
121 token_trees.push(mk_punct('!')); 156 token_trees.push(mk_punct('!'));
122 } 157 }
123 token_trees.push(tt::TokenTree::from(tt::Subtree { 158 token_trees.push(tt::TokenTree::from(tt::Subtree {
124 delimiter: tt::Delimiter::Bracket, 159 delimiter: Some(tt::Delimiter {
160 kind: tt::DelimiterKind::Bracket,
161 id: tt::TokenId::unspecified(),
162 }),
125 token_trees: meta_tkns, 163 token_trees: meta_tkns,
126 })); 164 }));
127 165
@@ -136,11 +174,15 @@ fn convert_doc_comment(token: &ra_syntax::SyntaxToken) -> Option<Vec<tt::TokenTr
136 } 174 }
137 175
138 fn mk_punct(c: char) -> tt::TokenTree { 176 fn mk_punct(c: char) -> tt::TokenTree {
139 tt::TokenTree::from(tt::Leaf::from(tt::Punct { char: c, spacing: tt::Spacing::Alone })) 177 tt::TokenTree::from(tt::Leaf::from(tt::Punct {
178 char: c,
179 spacing: tt::Spacing::Alone,
180 id: tt::TokenId::unspecified(),
181 }))
140 } 182 }
141 183
142 fn mk_doc_literal(comment: &ast::Comment) -> tt::TokenTree { 184 fn mk_doc_literal(comment: &ast::Comment) -> tt::TokenTree {
143 let lit = tt::Literal { text: doc_comment_text(comment) }; 185 let lit = tt::Literal { text: doc_comment_text(comment), id: tt::TokenId::unspecified() };
144 186
145 tt::TokenTree::from(tt::Leaf::from(lit)) 187 tt::TokenTree::from(tt::Leaf::from(lit))
146 } 188 }
@@ -156,7 +198,7 @@ impl Convertor {
156 fn go(&mut self, tt: &SyntaxNode) -> Option<tt::Subtree> { 198 fn go(&mut self, tt: &SyntaxNode) -> Option<tt::Subtree> {
157 // This tree is empty 199 // This tree is empty
158 if tt.first_child_or_token().is_none() { 200 if tt.first_child_or_token().is_none() {
159 return Some(tt::Subtree { token_trees: vec![], delimiter: tt::Delimiter::None }); 201 return Some(tt::Subtree { token_trees: vec![], delimiter: None });
160 } 202 }
161 203
162 let first_child = tt.first_child_or_token()?; 204 let first_child = tt.first_child_or_token()?;
@@ -173,7 +215,7 @@ impl Convertor {
173 .last() 215 .last()
174 .unwrap(); 216 .unwrap();
175 if first_child.kind().is_trivia() { 217 if first_child.kind().is_trivia() {
176 return Some(tt::Subtree { token_trees: vec![], delimiter: tt::Delimiter::None }); 218 return Some(tt::Subtree { token_trees: vec![], delimiter: None });
177 } 219 }
178 220
179 let last_child = successors(Some(last_child), |it| { 221 let last_child = successors(Some(last_child), |it| {
@@ -186,12 +228,16 @@ impl Convertor {
186 .last() 228 .last()
187 .unwrap(); 229 .unwrap();
188 230
189 let (delimiter, skip_first) = match (first_child.kind(), last_child.kind()) { 231 let (delimiter_kind, skip_first) = match (first_child.kind(), last_child.kind()) {
190 (T!['('], T![')']) => (tt::Delimiter::Parenthesis, true), 232 (T!['('], T![')']) => (Some(tt::DelimiterKind::Parenthesis), true),
191 (T!['{'], T!['}']) => (tt::Delimiter::Brace, true), 233 (T!['{'], T!['}']) => (Some(tt::DelimiterKind::Brace), true),
192 (T!['['], T![']']) => (tt::Delimiter::Bracket, true), 234 (T!['['], T![']']) => (Some(tt::DelimiterKind::Bracket), true),
193 _ => (tt::Delimiter::None, false), 235 _ => (None, false),
194 }; 236 };
237 let delimiter = delimiter_kind.map(|kind| tt::Delimiter {
238 kind,
239 id: self.alloc_delim(first_child.text_range(), last_child.text_range()),
240 });
195 241
196 let mut token_trees = Vec::new(); 242 let mut token_trees = Vec::new();
197 let mut child_iter = tt.children_with_tokens().skip(skip_first as usize).peekable(); 243 let mut child_iter = tt.children_with_tokens().skip(skip_first as usize).peekable();
@@ -208,13 +254,8 @@ impl Convertor {
208 } else if token.kind().is_trivia() { 254 } else if token.kind().is_trivia() {
209 continue; 255 continue;
210 } else if token.kind().is_punct() { 256 } else if token.kind().is_punct() {
211 assert!( 257 // we need to pull apart joined punctuation tokens
212 token.text().len() == 1, 258 let last_spacing = match child_iter.peek() {
213 "Input ast::token punct must be single char."
214 );
215 let char = token.text().chars().next().unwrap();
216
217 let spacing = match child_iter.peek() {
218 Some(NodeOrToken::Token(token)) => { 259 Some(NodeOrToken::Token(token)) => {
219 if token.kind().is_punct() { 260 if token.kind().is_punct() {
220 tt::Spacing::Joint 261 tt::Spacing::Joint
@@ -224,30 +265,47 @@ impl Convertor {
224 } 265 }
225 _ => tt::Spacing::Alone, 266 _ => tt::Spacing::Alone,
226 }; 267 };
227 268 let spacing_iter = std::iter::repeat(tt::Spacing::Joint)
228 token_trees.push(tt::Leaf::from(tt::Punct { char, spacing }).into()); 269 .take(token.text().len() - 1)
270 .chain(std::iter::once(last_spacing));
271 for (char, spacing) in token.text().chars().zip(spacing_iter) {
272 token_trees.push(
273 tt::Leaf::from(tt::Punct {
274 char,
275 spacing,
276 id: self.alloc(token.text_range()),
277 })
278 .into(),
279 );
280 }
229 } else { 281 } else {
230 let child: tt::TokenTree = 282 macro_rules! make_leaf {
231 if token.kind() == T![true] || token.kind() == T![false] { 283 ($i:ident) => {
232 tt::Leaf::from(tt::Literal { text: token.text().clone() }).into() 284 tt::$i {
233 } else if token.kind().is_keyword() 285 id: self.alloc(token.text_range()),
234 || token.kind() == IDENT 286 text: token.text().clone(),
235 || token.kind() == LIFETIME 287 }
236 { 288 .into()
237 let id = self.alloc(token.text_range());
238 let text = token.text().clone();
239 tt::Leaf::from(tt::Ident { text, id }).into()
240 } else if token.kind().is_literal() {
241 tt::Leaf::from(tt::Literal { text: token.text().clone() }).into()
242 } else {
243 return None;
244 }; 289 };
245 token_trees.push(child); 290 }
291
292 let child: tt::Leaf = match token.kind() {
293 T![true] | T![false] => make_leaf!(Literal),
294 IDENT | LIFETIME => make_leaf!(Ident),
295 k if k.is_keyword() => make_leaf!(Ident),
296 k if k.is_literal() => make_leaf!(Literal),
297 _ => return None,
298 };
299 token_trees.push(child.into());
246 } 300 }
247 } 301 }
248 NodeOrToken::Node(node) => { 302 NodeOrToken::Node(node) => {
249 let child = self.go(&node)?.into(); 303 let child_subtree = self.go(&node)?;
250 token_trees.push(child); 304 if child_subtree.delimiter.is_none() && node.kind() != SyntaxKind::TOKEN_TREE {
305 token_trees.extend(child_subtree.token_trees);
306 } else {
307 token_trees.push(child_subtree.into());
308 }
251 } 309 }
252 }; 310 };
253 } 311 }
@@ -263,11 +321,26 @@ impl Convertor {
263 self.map.insert(token_id, relative_range); 321 self.map.insert(token_id, relative_range);
264 token_id 322 token_id
265 } 323 }
324
325 fn alloc_delim(
326 &mut self,
327 open_abs_range: TextRange,
328 close_abs_range: TextRange,
329 ) -> tt::TokenId {
330 let open_relative_range = open_abs_range - self.global_offset;
331 let close_relative_range = close_abs_range - self.global_offset;
332 let token_id = tt::TokenId(self.next_id);
333 self.next_id += 1;
334
335 self.map.insert_delim(token_id, open_relative_range, close_relative_range);
336 token_id
337 }
266} 338}
267 339
268struct TtTreeSink<'a> { 340struct TtTreeSink<'a> {
269 buf: String, 341 buf: String,
270 cursor: Cursor<'a>, 342 cursor: Cursor<'a>,
343 open_delims: FxHashMap<tt::TokenId, TextUnit>,
271 text_pos: TextUnit, 344 text_pos: TextUnit,
272 inner: SyntaxTreeBuilder, 345 inner: SyntaxTreeBuilder,
273 token_map: TokenMap, 346 token_map: TokenMap,
@@ -282,6 +355,7 @@ impl<'a> TtTreeSink<'a> {
282 TtTreeSink { 355 TtTreeSink {
283 buf: String::new(), 356 buf: String::new(),
284 cursor, 357 cursor,
358 open_delims: FxHashMap::default(),
285 text_pos: 0.into(), 359 text_pos: 0.into(),
286 inner: SyntaxTreeBuilder::default(), 360 inner: SyntaxTreeBuilder::default(),
287 roots: smallvec::SmallVec::new(), 361 roots: smallvec::SmallVec::new(),
@@ -294,16 +368,16 @@ impl<'a> TtTreeSink<'a> {
294 } 368 }
295} 369}
296 370
297fn delim_to_str(d: tt::Delimiter, closing: bool) -> SmolStr { 371fn delim_to_str(d: Option<tt::DelimiterKind>, closing: bool) -> SmolStr {
298 let texts = match d { 372 let texts = match d {
299 tt::Delimiter::Parenthesis => "()", 373 Some(tt::DelimiterKind::Parenthesis) => "()",
300 tt::Delimiter::Brace => "{}", 374 Some(tt::DelimiterKind::Brace) => "{}",
301 tt::Delimiter::Bracket => "[]", 375 Some(tt::DelimiterKind::Bracket) => "[]",
302 tt::Delimiter::None => "", 376 None => return "".into(),
303 }; 377 };
304 378
305 let idx = closing as usize; 379 let idx = closing as usize;
306 let text = if !texts.is_empty() { &texts[idx..texts.len() - (1 - idx)] } else { "" }; 380 let text = &texts[idx..texts.len() - (1 - idx)];
307 text.into() 381 text.into()
308} 382}
309 383
@@ -319,34 +393,49 @@ impl<'a> TreeSink for TtTreeSink<'a> {
319 break; 393 break;
320 } 394 }
321 395
322 match self.cursor.token_tree() { 396 let text: SmolStr = match self.cursor.token_tree() {
323 Some(tt::TokenTree::Leaf(leaf)) => { 397 Some(tt::TokenTree::Leaf(leaf)) => {
324 // Mark the range if needed 398 // Mark the range if needed
325 if let tt::Leaf::Ident(ident) = leaf { 399 let id = match leaf {
326 if kind == IDENT { 400 tt::Leaf::Ident(ident) => ident.id,
327 let range = 401 tt::Leaf::Punct(punct) => punct.id,
328 TextRange::offset_len(self.text_pos, TextUnit::of_str(&ident.text)); 402 tt::Leaf::Literal(lit) => lit.id,
329 self.token_map.insert(ident.id, range); 403 };
330 } 404 let text = SmolStr::new(format!("{}", leaf));
331 } 405 let range = TextRange::offset_len(self.text_pos, TextUnit::of_str(&text));
332 406 self.token_map.insert(id, range);
333 self.cursor = self.cursor.bump(); 407 self.cursor = self.cursor.bump();
334 self.buf += &format!("{}", leaf); 408 text
335 } 409 }
336 Some(tt::TokenTree::Subtree(subtree)) => { 410 Some(tt::TokenTree::Subtree(subtree)) => {
337 self.cursor = self.cursor.subtree().unwrap(); 411 self.cursor = self.cursor.subtree().unwrap();
338 self.buf += &delim_to_str(subtree.delimiter, false); 412 if let Some(id) = subtree.delimiter.map(|it| it.id) {
413 self.open_delims.insert(id, self.text_pos);
414 }
415 delim_to_str(subtree.delimiter_kind(), false)
339 } 416 }
340 None => { 417 None => {
341 if let Some(parent) = self.cursor.end() { 418 if let Some(parent) = self.cursor.end() {
342 self.cursor = self.cursor.bump(); 419 self.cursor = self.cursor.bump();
343 self.buf += &delim_to_str(parent.delimiter, true); 420 if let Some(id) = parent.delimiter.map(|it| it.id) {
421 if let Some(open_delim) = self.open_delims.get(&id) {
422 let open_range =
423 TextRange::offset_len(*open_delim, TextUnit::from_usize(1));
424 let close_range =
425 TextRange::offset_len(self.text_pos, TextUnit::from_usize(1));
426 self.token_map.insert_delim(id, open_range, close_range);
427 }
428 }
429 delim_to_str(parent.delimiter_kind(), true)
430 } else {
431 continue;
344 } 432 }
345 } 433 }
346 }; 434 };
435 self.buf += &text;
436 self.text_pos += TextUnit::of_str(&text);
347 } 437 }
348 438
349 self.text_pos += TextUnit::of_str(&self.buf);
350 let text = SmolStr::new(self.buf.as_str()); 439 let text = SmolStr::new(self.buf.as_str());
351 self.buf.clear(); 440 self.buf.clear();
352 self.inner.token(kind, text); 441 self.inner.token(kind, text);
@@ -387,13 +476,16 @@ impl<'a> TreeSink for TtTreeSink<'a> {
387#[cfg(test)] 476#[cfg(test)]
388mod tests { 477mod tests {
389 use super::*; 478 use super::*;
390 use crate::tests::{create_rules, expand}; 479 use crate::tests::parse_macro;
391 use ra_parser::TokenSource; 480 use ra_parser::TokenSource;
392 use ra_syntax::algo::{insert_children, InsertPosition}; 481 use ra_syntax::{
482 algo::{insert_children, InsertPosition},
483 ast::AstNode,
484 };
393 485
394 #[test] 486 #[test]
395 fn convert_tt_token_source() { 487 fn convert_tt_token_source() {
396 let rules = create_rules( 488 let expansion = parse_macro(
397 r#" 489 r#"
398 macro_rules! literals { 490 macro_rules! literals {
399 ($i:ident) => { 491 ($i:ident) => {
@@ -406,8 +498,8 @@ mod tests {
406 } 498 }
407 } 499 }
408 "#, 500 "#,
409 ); 501 )
410 let expansion = expand(&rules, "literals!(foo);"); 502 .expand_tt("literals!(foo);");
411 let tts = &[expansion.into()]; 503 let tts = &[expansion.into()];
412 let buffer = tt::buffer::TokenBuffer::new(tts); 504 let buffer = tt::buffer::TokenBuffer::new(tts);
413 let mut tt_src = SubtreeTokenSource::new(&buffer); 505 let mut tt_src = SubtreeTokenSource::new(&buffer);
@@ -435,7 +527,7 @@ mod tests {
435 527
436 #[test] 528 #[test]
437 fn stmts_token_trees_to_expr_is_err() { 529 fn stmts_token_trees_to_expr_is_err() {
438 let rules = create_rules( 530 let expansion = parse_macro(
439 r#" 531 r#"
440 macro_rules! stmts { 532 macro_rules! stmts {
441 () => { 533 () => {
@@ -446,8 +538,8 @@ mod tests {
446 } 538 }
447 } 539 }
448 "#, 540 "#,
449 ); 541 )
450 let expansion = expand(&rules, "stmts!();"); 542 .expand_tt("stmts!();");
451 assert!(token_tree_to_syntax_node(&expansion, FragmentKind::Expr).is_err()); 543 assert!(token_tree_to_syntax_node(&expansion, FragmentKind::Expr).is_err());
452 } 544 }
453 545
@@ -489,6 +581,14 @@ mod tests {
489 let token_tree = ast::TokenTree::cast(token_tree).unwrap(); 581 let token_tree = ast::TokenTree::cast(token_tree).unwrap();
490 let tt = ast_to_token_tree(&token_tree).unwrap().0; 582 let tt = ast_to_token_tree(&token_tree).unwrap().0;
491 583
492 assert_eq!(tt.delimiter, tt::Delimiter::Brace); 584 assert_eq!(tt.delimiter_kind(), Some(tt::DelimiterKind::Brace));
585 }
586
587 #[test]
588 fn test_token_tree_multi_char_punct() {
589 let source_file = ast::SourceFile::parse("struct Foo { a: x::Y }").ok().unwrap();
590 let struct_def = source_file.syntax().descendants().find_map(ast::StructDef::cast).unwrap();
591 let tt = ast_to_token_tree(&struct_def).unwrap().0;
592 token_tree_to_syntax_node(&tt, FragmentKind::Item).unwrap();
493 } 593 }
494} 594}