diff options
author | Edwin Cheng <[email protected]> | 2019-11-03 14:46:12 +0000 |
---|---|---|
committer | Edwin Cheng <[email protected]> | 2019-11-04 17:38:20 +0000 |
commit | 159da285e9d8594a2cc4436b5cee7874b07806c9 (patch) | |
tree | 15630e1158cfb7d7305cedd93c1a644b28f9b776 /crates/ra_mbe/src | |
parent | 9fd546bec23ac817a45da28889e76118969db91e (diff) |
Add macro_expansion_info in hir_expand
Diffstat (limited to 'crates/ra_mbe/src')
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_mbe/src/syntax_bridge.rs | 113 | ||||
-rw-r--r-- | crates/ra_mbe/src/tests.rs | 16 |
3 files changed, 103 insertions, 28 deletions
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index 15f000175..2926b29fd 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -32,7 +32,7 @@ pub enum ExpandError { | |||
32 | 32 | ||
33 | pub use crate::syntax_bridge::{ | 33 | pub use crate::syntax_bridge::{ |
34 | ast_to_token_tree, syntax_node_to_token_tree, token_tree_to_expr, token_tree_to_items, | 34 | ast_to_token_tree, syntax_node_to_token_tree, token_tree_to_expr, token_tree_to_items, |
35 | token_tree_to_macro_stmts, token_tree_to_pat, token_tree_to_ty, | 35 | token_tree_to_macro_stmts, token_tree_to_pat, token_tree_to_ty, TokenMap, |
36 | }; | 36 | }; |
37 | 37 | ||
38 | /// This struct contains AST for a single `macro_rules` definition. What might | 38 | /// This struct contains AST for a single `macro_rules` definition. What might |
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs index 8d9217518..5db6647e3 100644 --- a/crates/ra_mbe/src/syntax_bridge.rs +++ b/crates/ra_mbe/src/syntax_bridge.rs | |||
@@ -15,6 +15,7 @@ use crate::ExpandError; | |||
15 | use std::sync::atomic::{AtomicU32, Ordering}; | 15 | use std::sync::atomic::{AtomicU32, Ordering}; |
16 | 16 | ||
17 | /// Maps `tt::TokenId` to the relative range of the original token. | 17 | /// Maps `tt::TokenId` to the relative range of the original token. |
18 | #[derive(Debug, PartialEq, Eq)] | ||
18 | pub struct TokenMap { | 19 | pub struct TokenMap { |
19 | /// Maps `tt::TokenId` to the *relative* source range. | 20 | /// Maps `tt::TokenId` to the *relative* source range. |
20 | tokens: Vec<TextRange>, | 21 | tokens: Vec<TextRange>, |
@@ -34,6 +35,13 @@ impl std::default::Default for TokenMap { | |||
34 | } | 35 | } |
35 | } | 36 | } |
36 | 37 | ||
38 | /// Maps Relative range of the expanded syntax node to `tt::TokenId` | ||
39 | #[derive(Debug, PartialEq, Eq, Default)] | ||
40 | pub struct ExpandedRangeMap { | ||
41 | /// Maps `tt::TokenId` to the *relative* source range. | ||
42 | ranges: Vec<(TextRange, tt::TokenId)>, | ||
43 | } | ||
44 | |||
37 | /// Convert the syntax tree (what user has written) to a `TokenTree` (what macro | 45 | /// Convert the syntax tree (what user has written) to a `TokenTree` (what macro |
38 | /// will consume). | 46 | /// will consume). |
39 | pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap)> { | 47 | pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap)> { |
@@ -66,7 +74,7 @@ pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> Option<(tt::Subtree, Toke | |||
66 | fn fragment_to_syntax_node( | 74 | fn fragment_to_syntax_node( |
67 | tt: &tt::Subtree, | 75 | tt: &tt::Subtree, |
68 | fragment_kind: FragmentKind, | 76 | fragment_kind: FragmentKind, |
69 | ) -> Result<Parse<SyntaxNode>, ExpandError> { | 77 | ) -> Result<(Parse<SyntaxNode>, ExpandedRangeMap), ExpandError> { |
70 | let tmp; | 78 | let tmp; |
71 | let tokens = match tt { | 79 | let tokens = match tt { |
72 | tt::Subtree { delimiter: tt::Delimiter::None, token_trees } => token_trees.as_slice(), | 80 | tt::Subtree { delimiter: tt::Delimiter::None, token_trees } => token_trees.as_slice(), |
@@ -77,44 +85,55 @@ fn fragment_to_syntax_node( | |||
77 | }; | 85 | }; |
78 | let buffer = TokenBuffer::new(&tokens); | 86 | let buffer = TokenBuffer::new(&tokens); |
79 | let mut token_source = SubtreeTokenSource::new(&buffer); | 87 | let mut token_source = SubtreeTokenSource::new(&buffer); |
80 | let mut tree_sink = TtTreeSink::new(buffer.begin()); | 88 | let mut range_map = ExpandedRangeMap::default(); |
89 | let mut tree_sink = TtTreeSink::new(buffer.begin(), &mut range_map); | ||
81 | ra_parser::parse_fragment(&mut token_source, &mut tree_sink, fragment_kind); | 90 | ra_parser::parse_fragment(&mut token_source, &mut tree_sink, fragment_kind); |
82 | if tree_sink.roots.len() != 1 { | 91 | if tree_sink.roots.len() != 1 { |
83 | return Err(ExpandError::ConversionError); | 92 | return Err(ExpandError::ConversionError); |
84 | } | 93 | } |
85 | //FIXME: would be cool to report errors | 94 | //FIXME: would be cool to report errors |
86 | let parse = tree_sink.inner.finish(); | 95 | let parse = tree_sink.inner.finish(); |
87 | Ok(parse) | 96 | Ok((parse, range_map)) |
88 | } | 97 | } |
89 | 98 | ||
90 | /// Parses the token tree (result of macro expansion) to an expression | 99 | /// Parses the token tree (result of macro expansion) to an expression |
91 | pub fn token_tree_to_expr(tt: &tt::Subtree) -> Result<Parse<ast::Expr>, ExpandError> { | 100 | pub fn token_tree_to_expr( |
92 | let parse = fragment_to_syntax_node(tt, Expr)?; | 101 | tt: &tt::Subtree, |
93 | parse.cast().ok_or_else(|| crate::ExpandError::ConversionError) | 102 | ) -> Result<(Parse<ast::Expr>, ExpandedRangeMap), ExpandError> { |
103 | let (parse, map) = fragment_to_syntax_node(tt, Expr)?; | ||
104 | parse.cast().ok_or_else(|| crate::ExpandError::ConversionError).map(|p| (p, map)) | ||
94 | } | 105 | } |
95 | 106 | ||
96 | /// Parses the token tree (result of macro expansion) to a Pattern | 107 | /// Parses the token tree (result of macro expansion) to a Pattern |
97 | pub fn token_tree_to_pat(tt: &tt::Subtree) -> Result<Parse<ast::Pat>, ExpandError> { | 108 | pub fn token_tree_to_pat( |
98 | let parse = fragment_to_syntax_node(tt, Pattern)?; | 109 | tt: &tt::Subtree, |
99 | parse.cast().ok_or_else(|| crate::ExpandError::ConversionError) | 110 | ) -> Result<(Parse<ast::Pat>, ExpandedRangeMap), ExpandError> { |
111 | let (parse, map) = fragment_to_syntax_node(tt, Pattern)?; | ||
112 | parse.cast().ok_or_else(|| crate::ExpandError::ConversionError).map(|p| (p, map)) | ||
100 | } | 113 | } |
101 | 114 | ||
102 | /// Parses the token tree (result of macro expansion) to a Type | 115 | /// Parses the token tree (result of macro expansion) to a Type |
103 | pub fn token_tree_to_ty(tt: &tt::Subtree) -> Result<Parse<ast::TypeRef>, ExpandError> { | 116 | pub fn token_tree_to_ty( |
104 | let parse = fragment_to_syntax_node(tt, Type)?; | 117 | tt: &tt::Subtree, |
105 | parse.cast().ok_or_else(|| crate::ExpandError::ConversionError) | 118 | ) -> Result<(Parse<ast::TypeRef>, ExpandedRangeMap), ExpandError> { |
119 | let (parse, map) = fragment_to_syntax_node(tt, Type)?; | ||
120 | parse.cast().ok_or_else(|| crate::ExpandError::ConversionError).map(|p| (p, map)) | ||
106 | } | 121 | } |
107 | 122 | ||
108 | /// Parses the token tree (result of macro expansion) as a sequence of stmts | 123 | /// Parses the token tree (result of macro expansion) as a sequence of stmts |
109 | pub fn token_tree_to_macro_stmts(tt: &tt::Subtree) -> Result<Parse<ast::MacroStmts>, ExpandError> { | 124 | pub fn token_tree_to_macro_stmts( |
110 | let parse = fragment_to_syntax_node(tt, Statements)?; | 125 | tt: &tt::Subtree, |
111 | parse.cast().ok_or_else(|| crate::ExpandError::ConversionError) | 126 | ) -> Result<(Parse<ast::MacroStmts>, ExpandedRangeMap), ExpandError> { |
127 | let (parse, map) = fragment_to_syntax_node(tt, Statements)?; | ||
128 | parse.cast().ok_or_else(|| crate::ExpandError::ConversionError).map(|p| (p, map)) | ||
112 | } | 129 | } |
113 | 130 | ||
114 | /// Parses the token tree (result of macro expansion) as a sequence of items | 131 | /// Parses the token tree (result of macro expansion) as a sequence of items |
115 | pub fn token_tree_to_items(tt: &tt::Subtree) -> Result<Parse<ast::MacroItems>, ExpandError> { | 132 | pub fn token_tree_to_items( |
116 | let parse = fragment_to_syntax_node(tt, Items)?; | 133 | tt: &tt::Subtree, |
117 | parse.cast().ok_or_else(|| crate::ExpandError::ConversionError) | 134 | ) -> Result<(Parse<ast::MacroItems>, ExpandedRangeMap), ExpandError> { |
135 | let (parse, map) = fragment_to_syntax_node(tt, Items)?; | ||
136 | parse.cast().ok_or_else(|| crate::ExpandError::ConversionError).map(|p| (p, map)) | ||
118 | } | 137 | } |
119 | 138 | ||
120 | impl TokenMap { | 139 | impl TokenMap { |
@@ -133,6 +152,28 @@ impl TokenMap { | |||
133 | } | 152 | } |
134 | } | 153 | } |
135 | 154 | ||
155 | impl ExpandedRangeMap { | ||
156 | fn set(&mut self, relative_range: TextRange, token_id: &tt::TokenId) { | ||
157 | self.ranges.push((relative_range, token_id.clone())) | ||
158 | } | ||
159 | |||
160 | pub fn ranges(&self, to: &TokenMap) -> Vec<(TextRange, TextRange)> { | ||
161 | self.ranges | ||
162 | .iter() | ||
163 | .filter_map(|(r, tid)| { | ||
164 | if to.map_id == tid.map_id() { | ||
165 | return None; | ||
166 | } | ||
167 | if let Some(to_range) = to.relative_range_of(*tid) { | ||
168 | Some((*r, to_range)) | ||
169 | } else { | ||
170 | None | ||
171 | } | ||
172 | }) | ||
173 | .collect() | ||
174 | } | ||
175 | } | ||
176 | |||
136 | /// Returns the textual content of a doc comment block as a quoted string | 177 | /// Returns the textual content of a doc comment block as a quoted string |
137 | /// That is, strips leading `///` (or `/**`, etc) | 178 | /// That is, strips leading `///` (or `/**`, etc) |
138 | /// and strips the ending `*/` | 179 | /// and strips the ending `*/` |
@@ -279,6 +320,8 @@ struct TtTreeSink<'a> { | |||
279 | cursor: Cursor<'a>, | 320 | cursor: Cursor<'a>, |
280 | text_pos: TextUnit, | 321 | text_pos: TextUnit, |
281 | inner: SyntaxTreeBuilder, | 322 | inner: SyntaxTreeBuilder, |
323 | range_marker: Option<(TextRange, tt::TokenId)>, | ||
324 | range_map: &'a mut ExpandedRangeMap, | ||
282 | 325 | ||
283 | // Number of roots | 326 | // Number of roots |
284 | // Use for detect ill-form tree which is not single root | 327 | // Use for detect ill-form tree which is not single root |
@@ -286,13 +329,15 @@ struct TtTreeSink<'a> { | |||
286 | } | 329 | } |
287 | 330 | ||
288 | impl<'a> TtTreeSink<'a> { | 331 | impl<'a> TtTreeSink<'a> { |
289 | fn new(cursor: Cursor<'a>) -> Self { | 332 | fn new(cursor: Cursor<'a>, range_map: &'a mut ExpandedRangeMap) -> Self { |
290 | TtTreeSink { | 333 | TtTreeSink { |
291 | buf: String::new(), | 334 | buf: String::new(), |
292 | cursor, | 335 | cursor, |
293 | text_pos: 0.into(), | 336 | text_pos: 0.into(), |
294 | inner: SyntaxTreeBuilder::default(), | 337 | inner: SyntaxTreeBuilder::default(), |
295 | roots: smallvec::SmallVec::new(), | 338 | roots: smallvec::SmallVec::new(), |
339 | range_map, | ||
340 | range_marker: None, | ||
296 | } | 341 | } |
297 | } | 342 | } |
298 | } | 343 | } |
@@ -317,6 +362,8 @@ impl<'a> TreeSink for TtTreeSink<'a> { | |||
317 | return; | 362 | return; |
318 | } | 363 | } |
319 | 364 | ||
365 | let mut last_ident = None; | ||
366 | |||
320 | for _ in 0..n_tokens { | 367 | for _ in 0..n_tokens { |
321 | if self.cursor.eof() { | 368 | if self.cursor.eof() { |
322 | break; | 369 | break; |
@@ -326,6 +373,10 @@ impl<'a> TreeSink for TtTreeSink<'a> { | |||
326 | Some(tt::TokenTree::Leaf(leaf)) => { | 373 | Some(tt::TokenTree::Leaf(leaf)) => { |
327 | self.cursor = self.cursor.bump(); | 374 | self.cursor = self.cursor.bump(); |
328 | self.buf += &format!("{}", leaf); | 375 | self.buf += &format!("{}", leaf); |
376 | |||
377 | if let tt::Leaf::Ident(ident) = leaf { | ||
378 | last_ident = Some(ident); | ||
379 | } | ||
329 | } | 380 | } |
330 | Some(tt::TokenTree::Subtree(subtree)) => { | 381 | Some(tt::TokenTree::Subtree(subtree)) => { |
331 | self.cursor = self.cursor.subtree().unwrap(); | 382 | self.cursor = self.cursor.subtree().unwrap(); |
@@ -345,6 +396,14 @@ impl<'a> TreeSink for TtTreeSink<'a> { | |||
345 | self.buf.clear(); | 396 | self.buf.clear(); |
346 | self.inner.token(kind, text); | 397 | self.inner.token(kind, text); |
347 | 398 | ||
399 | // Mark the range if needed | ||
400 | if let Some((range, token_id)) = self.range_marker.as_mut() { | ||
401 | if let Some(ident) = last_ident { | ||
402 | *range = TextRange::offset_len(range.start(), TextUnit::of_str(&ident.text)); | ||
403 | *token_id = ident.id; | ||
404 | } | ||
405 | } | ||
406 | |||
348 | // Add whitespace between adjoint puncts | 407 | // Add whitespace between adjoint puncts |
349 | let next = self.cursor.bump(); | 408 | let next = self.cursor.bump(); |
350 | if let ( | 409 | if let ( |
@@ -354,6 +413,7 @@ impl<'a> TreeSink for TtTreeSink<'a> { | |||
354 | { | 413 | { |
355 | if curr.spacing == tt::Spacing::Alone { | 414 | if curr.spacing == tt::Spacing::Alone { |
356 | self.inner.token(WHITESPACE, " ".into()); | 415 | self.inner.token(WHITESPACE, " ".into()); |
416 | self.text_pos += TextUnit::of_char(' '); | ||
357 | } | 417 | } |
358 | } | 418 | } |
359 | } | 419 | } |
@@ -361,6 +421,15 @@ impl<'a> TreeSink for TtTreeSink<'a> { | |||
361 | fn start_node(&mut self, kind: SyntaxKind) { | 421 | fn start_node(&mut self, kind: SyntaxKind) { |
362 | self.inner.start_node(kind); | 422 | self.inner.start_node(kind); |
363 | 423 | ||
424 | self.range_marker = if kind == IDENT { | ||
425 | Some(( | ||
426 | TextRange::offset_len(self.text_pos, TextUnit::from_usize(0)), | ||
427 | tt::TokenId::unspecified(), | ||
428 | )) | ||
429 | } else { | ||
430 | None | ||
431 | }; | ||
432 | |||
364 | match self.roots.last_mut() { | 433 | match self.roots.last_mut() { |
365 | None | Some(0) => self.roots.push(1), | 434 | None | Some(0) => self.roots.push(1), |
366 | Some(ref mut n) => **n += 1, | 435 | Some(ref mut n) => **n += 1, |
@@ -370,6 +439,12 @@ impl<'a> TreeSink for TtTreeSink<'a> { | |||
370 | fn finish_node(&mut self) { | 439 | fn finish_node(&mut self) { |
371 | self.inner.finish_node(); | 440 | self.inner.finish_node(); |
372 | *self.roots.last_mut().unwrap() -= 1; | 441 | *self.roots.last_mut().unwrap() -= 1; |
442 | |||
443 | if let Some(range) = self.range_marker { | ||
444 | if range.1 != tt::TokenId::unspecified() { | ||
445 | self.range_map.set(range.0, &range.1) | ||
446 | } | ||
447 | } | ||
373 | } | 448 | } |
374 | 449 | ||
375 | fn error(&mut self, error: ParseError) { | 450 | fn error(&mut self, error: ParseError) { |
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs index a23e3afe3..a848ea334 100644 --- a/crates/ra_mbe/src/tests.rs +++ b/crates/ra_mbe/src/tests.rs | |||
@@ -126,7 +126,7 @@ fn test_expr_order() { | |||
126 | "#, | 126 | "#, |
127 | ); | 127 | ); |
128 | let expanded = expand(&rules, "foo! { 1 + 1}"); | 128 | let expanded = expand(&rules, "foo! { 1 + 1}"); |
129 | let tree = token_tree_to_items(&expanded).unwrap().tree(); | 129 | let tree = token_tree_to_items(&expanded).unwrap().0.tree(); |
130 | 130 | ||
131 | let dump = format!("{:#?}", tree.syntax()); | 131 | let dump = format!("{:#?}", tree.syntax()); |
132 | assert_eq_text!( | 132 | assert_eq_text!( |
@@ -383,7 +383,7 @@ fn test_expand_to_item_list() { | |||
383 | ", | 383 | ", |
384 | ); | 384 | ); |
385 | let expansion = expand(&rules, "structs!(Foo, Bar);"); | 385 | let expansion = expand(&rules, "structs!(Foo, Bar);"); |
386 | let tree = token_tree_to_items(&expansion).unwrap().tree(); | 386 | let tree = token_tree_to_items(&expansion).unwrap().0.tree(); |
387 | assert_eq!( | 387 | assert_eq!( |
388 | format!("{:#?}", tree.syntax()).trim(), | 388 | format!("{:#?}", tree.syntax()).trim(), |
389 | r#" | 389 | r#" |
@@ -501,7 +501,7 @@ fn test_tt_to_stmts() { | |||
501 | ); | 501 | ); |
502 | 502 | ||
503 | let expanded = expand(&rules, "foo!{}"); | 503 | let expanded = expand(&rules, "foo!{}"); |
504 | let stmts = token_tree_to_macro_stmts(&expanded).unwrap().tree(); | 504 | let stmts = token_tree_to_macro_stmts(&expanded).unwrap().0.tree(); |
505 | 505 | ||
506 | assert_eq!( | 506 | assert_eq!( |
507 | format!("{:#?}", stmts.syntax()).trim(), | 507 | format!("{:#?}", stmts.syntax()).trim(), |
@@ -946,7 +946,7 @@ fn test_vec() { | |||
946 | ); | 946 | ); |
947 | 947 | ||
948 | let expansion = expand(&rules, r#"vec![1u32,2];"#); | 948 | let expansion = expand(&rules, r#"vec![1u32,2];"#); |
949 | let tree = token_tree_to_expr(&expansion).unwrap().tree(); | 949 | let tree = token_tree_to_expr(&expansion).unwrap().0.tree(); |
950 | 950 | ||
951 | assert_eq!( | 951 | assert_eq!( |
952 | format!("{:#?}", tree.syntax()).trim(), | 952 | format!("{:#?}", tree.syntax()).trim(), |
@@ -1436,8 +1436,8 @@ pub(crate) fn assert_expansion( | |||
1436 | }; | 1436 | }; |
1437 | let (expanded_tree, expected_tree) = match kind { | 1437 | let (expanded_tree, expected_tree) = match kind { |
1438 | MacroKind::Items => { | 1438 | MacroKind::Items => { |
1439 | let expanded_tree = token_tree_to_items(&expanded).unwrap().tree(); | 1439 | let expanded_tree = token_tree_to_items(&expanded).unwrap().0.tree(); |
1440 | let expected_tree = token_tree_to_items(&expected).unwrap().tree(); | 1440 | let expected_tree = token_tree_to_items(&expected).unwrap().0.tree(); |
1441 | 1441 | ||
1442 | ( | 1442 | ( |
1443 | debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(), | 1443 | debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(), |
@@ -1446,8 +1446,8 @@ pub(crate) fn assert_expansion( | |||
1446 | } | 1446 | } |
1447 | 1447 | ||
1448 | MacroKind::Stmts => { | 1448 | MacroKind::Stmts => { |
1449 | let expanded_tree = token_tree_to_macro_stmts(&expanded).unwrap().tree(); | 1449 | let expanded_tree = token_tree_to_macro_stmts(&expanded).unwrap().0.tree(); |
1450 | let expected_tree = token_tree_to_macro_stmts(&expected).unwrap().tree(); | 1450 | let expected_tree = token_tree_to_macro_stmts(&expected).unwrap().0.tree(); |
1451 | 1451 | ||
1452 | ( | 1452 | ( |
1453 | debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(), | 1453 | debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(), |