diff options
Diffstat (limited to 'crates/ra_mbe/src/syntax_bridge.rs')
-rw-r--r-- | crates/ra_mbe/src/syntax_bridge.rs | 75 |
1 files changed, 35 insertions, 40 deletions
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs index 592fcf527..3f57ce3b5 100644 --- a/crates/ra_mbe/src/syntax_bridge.rs +++ b/crates/ra_mbe/src/syntax_bridge.rs | |||
@@ -1,9 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use ra_parser::{ | 3 | use ra_parser::{FragmentKind, ParseError, TreeSink}; |
4 | FragmentKind::{self, *}, | ||
5 | ParseError, TreeSink, | ||
6 | }; | ||
7 | use ra_syntax::{ | 4 | use ra_syntax::{ |
8 | ast, AstNode, AstToken, NodeOrToken, Parse, SmolStr, SyntaxKind, SyntaxKind::*, SyntaxNode, | 5 | ast, AstNode, AstToken, NodeOrToken, Parse, SmolStr, SyntaxKind, SyntaxKind::*, SyntaxNode, |
9 | SyntaxTreeBuilder, TextRange, TextUnit, T, | 6 | SyntaxTreeBuilder, TextRange, TextUnit, T, |
@@ -14,12 +11,18 @@ use crate::subtree_source::SubtreeTokenSource; | |||
14 | use crate::ExpandError; | 11 | use crate::ExpandError; |
15 | 12 | ||
16 | /// Maps `tt::TokenId` to the relative range of the original token. | 13 | /// Maps `tt::TokenId` to the relative range of the original token. |
17 | #[derive(Default)] | 14 | #[derive(Debug, PartialEq, Eq, Default)] |
18 | pub struct TokenMap { | 15 | pub struct TokenMap { |
19 | /// Maps `tt::TokenId` to the *relative* source range. | 16 | /// Maps `tt::TokenId` to the *relative* source range. |
20 | tokens: Vec<TextRange>, | 17 | tokens: Vec<TextRange>, |
21 | } | 18 | } |
22 | 19 | ||
20 | /// Maps relative range of the expanded syntax node to `tt::TokenId` | ||
21 | #[derive(Debug, PartialEq, Eq, Default)] | ||
22 | pub struct RevTokenMap { | ||
23 | pub ranges: Vec<(TextRange, tt::TokenId)>, | ||
24 | } | ||
25 | |||
23 | /// Convert the syntax tree (what user has written) to a `TokenTree` (what macro | 26 | /// Convert the syntax tree (what user has written) to a `TokenTree` (what macro |
24 | /// will consume). | 27 | /// will consume). |
25 | pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap)> { | 28 | pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap)> { |
@@ -49,10 +52,10 @@ pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> Option<(tt::Subtree, Toke | |||
49 | // * ImplItems(SmallVec<[ast::ImplItem; 1]>) | 52 | // * ImplItems(SmallVec<[ast::ImplItem; 1]>) |
50 | // * ForeignItems(SmallVec<[ast::ForeignItem; 1]> | 53 | // * ForeignItems(SmallVec<[ast::ForeignItem; 1]> |
51 | 54 | ||
52 | fn fragment_to_syntax_node( | 55 | pub fn token_tree_to_syntax_node( |
53 | tt: &tt::Subtree, | 56 | tt: &tt::Subtree, |
54 | fragment_kind: FragmentKind, | 57 | fragment_kind: FragmentKind, |
55 | ) -> Result<Parse<SyntaxNode>, ExpandError> { | 58 | ) -> Result<(Parse<SyntaxNode>, RevTokenMap), ExpandError> { |
56 | let tmp; | 59 | let tmp; |
57 | let tokens = match tt { | 60 | let tokens = match tt { |
58 | tt::Subtree { delimiter: tt::Delimiter::None, token_trees } => token_trees.as_slice(), | 61 | tt::Subtree { delimiter: tt::Delimiter::None, token_trees } => token_trees.as_slice(), |
@@ -69,38 +72,8 @@ fn fragment_to_syntax_node( | |||
69 | return Err(ExpandError::ConversionError); | 72 | return Err(ExpandError::ConversionError); |
70 | } | 73 | } |
71 | //FIXME: would be cool to report errors | 74 | //FIXME: would be cool to report errors |
72 | let parse = tree_sink.inner.finish(); | 75 | let (parse, range_map) = tree_sink.finish(); |
73 | Ok(parse) | 76 | Ok((parse, range_map)) |
74 | } | ||
75 | |||
76 | /// Parses the token tree (result of macro expansion) to an expression | ||
77 | pub fn token_tree_to_expr(tt: &tt::Subtree) -> Result<Parse<ast::Expr>, ExpandError> { | ||
78 | let parse = fragment_to_syntax_node(tt, Expr)?; | ||
79 | parse.cast().ok_or_else(|| crate::ExpandError::ConversionError) | ||
80 | } | ||
81 | |||
82 | /// Parses the token tree (result of macro expansion) to a Pattern | ||
83 | pub fn token_tree_to_pat(tt: &tt::Subtree) -> Result<Parse<ast::Pat>, ExpandError> { | ||
84 | let parse = fragment_to_syntax_node(tt, Pattern)?; | ||
85 | parse.cast().ok_or_else(|| crate::ExpandError::ConversionError) | ||
86 | } | ||
87 | |||
88 | /// Parses the token tree (result of macro expansion) to a Type | ||
89 | pub fn token_tree_to_ty(tt: &tt::Subtree) -> Result<Parse<ast::TypeRef>, ExpandError> { | ||
90 | let parse = fragment_to_syntax_node(tt, Type)?; | ||
91 | parse.cast().ok_or_else(|| crate::ExpandError::ConversionError) | ||
92 | } | ||
93 | |||
94 | /// Parses the token tree (result of macro expansion) as a sequence of stmts | ||
95 | pub fn token_tree_to_macro_stmts(tt: &tt::Subtree) -> Result<Parse<ast::MacroStmts>, ExpandError> { | ||
96 | let parse = fragment_to_syntax_node(tt, Statements)?; | ||
97 | parse.cast().ok_or_else(|| crate::ExpandError::ConversionError) | ||
98 | } | ||
99 | |||
100 | /// Parses the token tree (result of macro expansion) as a sequence of items | ||
101 | pub fn token_tree_to_items(tt: &tt::Subtree) -> Result<Parse<ast::MacroItems>, ExpandError> { | ||
102 | let parse = fragment_to_syntax_node(tt, Items)?; | ||
103 | parse.cast().ok_or_else(|| crate::ExpandError::ConversionError) | ||
104 | } | 77 | } |
105 | 78 | ||
106 | impl TokenMap { | 79 | impl TokenMap { |
@@ -116,6 +89,12 @@ impl TokenMap { | |||
116 | } | 89 | } |
117 | } | 90 | } |
118 | 91 | ||
92 | impl RevTokenMap { | ||
93 | fn add(&mut self, relative_range: TextRange, token_id: tt::TokenId) { | ||
94 | self.ranges.push((relative_range, token_id.clone())) | ||
95 | } | ||
96 | } | ||
97 | |||
119 | /// Returns the textual content of a doc comment block as a quoted string | 98 | /// Returns the textual content of a doc comment block as a quoted string |
120 | /// That is, strips leading `///` (or `/**`, etc) | 99 | /// That is, strips leading `///` (or `/**`, etc) |
121 | /// and strips the ending `*/` | 100 | /// and strips the ending `*/` |
@@ -262,6 +241,7 @@ struct TtTreeSink<'a> { | |||
262 | cursor: Cursor<'a>, | 241 | cursor: Cursor<'a>, |
263 | text_pos: TextUnit, | 242 | text_pos: TextUnit, |
264 | inner: SyntaxTreeBuilder, | 243 | inner: SyntaxTreeBuilder, |
244 | range_map: RevTokenMap, | ||
265 | 245 | ||
266 | // Number of roots | 246 | // Number of roots |
267 | // Use for detect ill-form tree which is not single root | 247 | // Use for detect ill-form tree which is not single root |
@@ -276,8 +256,13 @@ impl<'a> TtTreeSink<'a> { | |||
276 | text_pos: 0.into(), | 256 | text_pos: 0.into(), |
277 | inner: SyntaxTreeBuilder::default(), | 257 | inner: SyntaxTreeBuilder::default(), |
278 | roots: smallvec::SmallVec::new(), | 258 | roots: smallvec::SmallVec::new(), |
259 | range_map: RevTokenMap::default(), | ||
279 | } | 260 | } |
280 | } | 261 | } |
262 | |||
263 | fn finish(self) -> (Parse<SyntaxNode>, RevTokenMap) { | ||
264 | (self.inner.finish(), self.range_map) | ||
265 | } | ||
281 | } | 266 | } |
282 | 267 | ||
283 | fn delim_to_str(d: tt::Delimiter, closing: bool) -> SmolStr { | 268 | fn delim_to_str(d: tt::Delimiter, closing: bool) -> SmolStr { |
@@ -307,6 +292,15 @@ impl<'a> TreeSink for TtTreeSink<'a> { | |||
307 | 292 | ||
308 | match self.cursor.token_tree() { | 293 | match self.cursor.token_tree() { |
309 | Some(tt::TokenTree::Leaf(leaf)) => { | 294 | Some(tt::TokenTree::Leaf(leaf)) => { |
295 | // Mark the range if needed | ||
296 | if let tt::Leaf::Ident(ident) = leaf { | ||
297 | if kind == IDENT { | ||
298 | let range = | ||
299 | TextRange::offset_len(self.text_pos, TextUnit::of_str(&ident.text)); | ||
300 | self.range_map.add(range, ident.id); | ||
301 | } | ||
302 | } | ||
303 | |||
310 | self.cursor = self.cursor.bump(); | 304 | self.cursor = self.cursor.bump(); |
311 | self.buf += &format!("{}", leaf); | 305 | self.buf += &format!("{}", leaf); |
312 | } | 306 | } |
@@ -337,6 +331,7 @@ impl<'a> TreeSink for TtTreeSink<'a> { | |||
337 | { | 331 | { |
338 | if curr.spacing == tt::Spacing::Alone { | 332 | if curr.spacing == tt::Spacing::Alone { |
339 | self.inner.token(WHITESPACE, " ".into()); | 333 | self.inner.token(WHITESPACE, " ".into()); |
334 | self.text_pos += TextUnit::of_char(' '); | ||
340 | } | 335 | } |
341 | } | 336 | } |
342 | } | 337 | } |
@@ -423,6 +418,6 @@ mod tests { | |||
423 | "#, | 418 | "#, |
424 | ); | 419 | ); |
425 | let expansion = expand(&rules, "stmts!();"); | 420 | let expansion = expand(&rules, "stmts!();"); |
426 | assert!(token_tree_to_expr(&expansion).is_err()); | 421 | assert!(token_tree_to_syntax_node(&expansion, FragmentKind::Expr).is_err()); |
427 | } | 422 | } |
428 | } | 423 | } |