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.rs75
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
3use ra_parser::{ 3use ra_parser::{FragmentKind, ParseError, TreeSink};
4 FragmentKind::{self, *},
5 ParseError, TreeSink,
6};
7use ra_syntax::{ 4use 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;
14use crate::ExpandError; 11use 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)]
18pub struct TokenMap { 15pub 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)]
22pub 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).
25pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap)> { 28pub 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
52fn fragment_to_syntax_node( 55pub 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
77pub 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
83pub 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
89pub 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
95pub 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
101pub 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
106impl TokenMap { 79impl TokenMap {
@@ -116,6 +89,12 @@ impl TokenMap {
116 } 89 }
117} 90}
118 91
92impl 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
283fn delim_to_str(d: tt::Delimiter, closing: bool) -> SmolStr { 268fn 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}