diff options
author | Seivan Heidari <[email protected]> | 2019-12-23 14:35:31 +0000 |
---|---|---|
committer | Seivan Heidari <[email protected]> | 2019-12-23 14:35:31 +0000 |
commit | b21d9337d9200e2cfdc90b386591c72c302dc03e (patch) | |
tree | f81f5c08f821115cee26fa4d3ceaae88c7807fd5 /crates/ra_mbe/src | |
parent | 18a0937585b836ec5ed054b9ae48e0156ab6d9ef (diff) | |
parent | ce07a2daa9e53aa86a769f8641b14c2878444fbc (diff) |
Merge branch 'master' into feature/themes
Diffstat (limited to 'crates/ra_mbe/src')
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 25 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_expander/matcher.rs | 8 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_expander/transcriber.rs | 17 | ||||
-rw-r--r-- | crates/ra_mbe/src/subtree_source.rs | 14 | ||||
-rw-r--r-- | crates/ra_mbe/src/syntax_bridge.rs | 242 | ||||
-rw-r--r-- | crates/ra_mbe/src/tests.rs | 684 |
6 files changed, 529 insertions, 461 deletions
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index bbddebe67..2c6ae5658 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -67,7 +67,15 @@ impl Shift { | |||
67 | .token_trees | 67 | .token_trees |
68 | .iter() | 68 | .iter() |
69 | .filter_map(|tt| match tt { | 69 | .filter_map(|tt| match tt { |
70 | tt::TokenTree::Subtree(subtree) => max_id(subtree), | 70 | tt::TokenTree::Subtree(subtree) => { |
71 | let tree_id = max_id(subtree); | ||
72 | match subtree.delimiter { | ||
73 | Some(it) if it.id != tt::TokenId::unspecified() => { | ||
74 | Some(tree_id.map_or(it.id.0, |t| t.max(it.id.0))) | ||
75 | } | ||
76 | _ => tree_id, | ||
77 | } | ||
78 | } | ||
71 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) | 79 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) |
72 | if ident.id != tt::TokenId::unspecified() => | 80 | if ident.id != tt::TokenId::unspecified() => |
73 | { | 81 | { |
@@ -85,9 +93,15 @@ impl Shift { | |||
85 | match t { | 93 | match t { |
86 | tt::TokenTree::Leaf(leaf) => match leaf { | 94 | tt::TokenTree::Leaf(leaf) => match leaf { |
87 | tt::Leaf::Ident(ident) => ident.id = self.shift(ident.id), | 95 | tt::Leaf::Ident(ident) => ident.id = self.shift(ident.id), |
88 | _ => (), | 96 | tt::Leaf::Punct(punct) => punct.id = self.shift(punct.id), |
97 | tt::Leaf::Literal(lit) => lit.id = self.shift(lit.id), | ||
89 | }, | 98 | }, |
90 | tt::TokenTree::Subtree(tt) => self.shift_all(tt), | 99 | tt::TokenTree::Subtree(tt) => { |
100 | if let Some(it) = tt.delimiter.as_mut() { | ||
101 | it.id = self.shift(it.id); | ||
102 | }; | ||
103 | self.shift_all(tt) | ||
104 | } | ||
91 | } | 105 | } |
92 | } | 106 | } |
93 | } | 107 | } |
@@ -104,6 +118,7 @@ impl Shift { | |||
104 | } | 118 | } |
105 | } | 119 | } |
106 | 120 | ||
121 | #[derive(Debug, Eq, PartialEq)] | ||
107 | pub enum Origin { | 122 | pub enum Origin { |
108 | Def, | 123 | Def, |
109 | Call, | 124 | Call, |
@@ -159,14 +174,14 @@ impl Rule { | |||
159 | .expect_subtree() | 174 | .expect_subtree() |
160 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))? | 175 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))? |
161 | .clone(); | 176 | .clone(); |
162 | lhs.delimiter = tt::Delimiter::None; | 177 | lhs.delimiter = None; |
163 | src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?; | 178 | src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?; |
164 | src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?; | 179 | src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?; |
165 | let mut rhs = src | 180 | let mut rhs = src |
166 | .expect_subtree() | 181 | .expect_subtree() |
167 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))? | 182 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))? |
168 | .clone(); | 183 | .clone(); |
169 | rhs.delimiter = tt::Delimiter::None; | 184 | rhs.delimiter = None; |
170 | Ok(crate::Rule { lhs, rhs }) | 185 | Ok(crate::Rule { lhs, rhs }) |
171 | } | 186 | } |
172 | } | 187 | } |
diff --git a/crates/ra_mbe/src/mbe_expander/matcher.rs b/crates/ra_mbe/src/mbe_expander/matcher.rs index 33b9d483d..e36b5a412 100644 --- a/crates/ra_mbe/src/mbe_expander/matcher.rs +++ b/crates/ra_mbe/src/mbe_expander/matcher.rs | |||
@@ -16,7 +16,7 @@ impl Bindings { | |||
16 | fn push_optional(&mut self, name: &SmolStr) { | 16 | fn push_optional(&mut self, name: &SmolStr) { |
17 | // FIXME: Do we have a better way to represent an empty token ? | 17 | // FIXME: Do we have a better way to represent an empty token ? |
18 | // Insert an empty subtree for empty token | 18 | // Insert an empty subtree for empty token |
19 | let tt = tt::Subtree { delimiter: tt::Delimiter::None, token_trees: vec![] }.into(); | 19 | let tt = tt::Subtree::default().into(); |
20 | self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt))); | 20 | self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt))); |
21 | } | 21 | } |
22 | 22 | ||
@@ -65,7 +65,7 @@ macro_rules! bail { | |||
65 | } | 65 | } |
66 | 66 | ||
67 | pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Bindings, ExpandError> { | 67 | pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Bindings, ExpandError> { |
68 | assert!(pattern.delimiter == tt::Delimiter::None); | 68 | assert!(pattern.delimiter == None); |
69 | 69 | ||
70 | let mut res = Bindings::default(); | 70 | let mut res = Bindings::default(); |
71 | let mut src = TtIter::new(src); | 71 | let mut src = TtIter::new(src); |
@@ -106,7 +106,7 @@ fn match_subtree( | |||
106 | } | 106 | } |
107 | Op::TokenTree(tt::TokenTree::Subtree(lhs)) => { | 107 | Op::TokenTree(tt::TokenTree::Subtree(lhs)) => { |
108 | let rhs = src.expect_subtree().map_err(|()| err!("expected subtree"))?; | 108 | let rhs = src.expect_subtree().map_err(|()| err!("expected subtree"))?; |
109 | if lhs.delimiter != rhs.delimiter { | 109 | if lhs.delimiter_kind() != rhs.delimiter_kind() { |
110 | bail!("mismatched delimiter") | 110 | bail!("mismatched delimiter") |
111 | } | 111 | } |
112 | let mut src = TtIter::new(rhs); | 112 | let mut src = TtIter::new(rhs); |
@@ -210,7 +210,7 @@ impl<'a> TtIter<'a> { | |||
210 | 0 => Err(()), | 210 | 0 => Err(()), |
211 | 1 => Ok(res[0].clone()), | 211 | 1 => Ok(res[0].clone()), |
212 | _ => Ok(tt::TokenTree::Subtree(tt::Subtree { | 212 | _ => Ok(tt::TokenTree::Subtree(tt::Subtree { |
213 | delimiter: tt::Delimiter::None, | 213 | delimiter: None, |
214 | token_trees: res.into_iter().cloned().collect(), | 214 | token_trees: res.into_iter().cloned().collect(), |
215 | })), | 215 | })), |
216 | } | 216 | } |
diff --git a/crates/ra_mbe/src/mbe_expander/transcriber.rs b/crates/ra_mbe/src/mbe_expander/transcriber.rs index ed094d5bb..eda66cd50 100644 --- a/crates/ra_mbe/src/mbe_expander/transcriber.rs +++ b/crates/ra_mbe/src/mbe_expander/transcriber.rs | |||
@@ -50,7 +50,7 @@ pub(super) fn transcribe( | |||
50 | template: &tt::Subtree, | 50 | template: &tt::Subtree, |
51 | bindings: &Bindings, | 51 | bindings: &Bindings, |
52 | ) -> Result<tt::Subtree, ExpandError> { | 52 | ) -> Result<tt::Subtree, ExpandError> { |
53 | assert!(template.delimiter == tt::Delimiter::None); | 53 | assert!(template.delimiter == None); |
54 | let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new(), var_expanded: false }; | 54 | let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new(), var_expanded: false }; |
55 | expand_subtree(&mut ctx, template) | 55 | expand_subtree(&mut ctx, template) |
56 | } | 56 | } |
@@ -106,9 +106,14 @@ fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> Result<Fragment, ExpandError> | |||
106 | // ``` | 106 | // ``` |
107 | // We just treat it a normal tokens | 107 | // We just treat it a normal tokens |
108 | let tt = tt::Subtree { | 108 | let tt = tt::Subtree { |
109 | delimiter: tt::Delimiter::None, | 109 | delimiter: None, |
110 | token_trees: vec![ | 110 | token_trees: vec![ |
111 | tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone }).into(), | 111 | tt::Leaf::from(tt::Punct { |
112 | char: '$', | ||
113 | spacing: tt::Spacing::Alone, | ||
114 | id: tt::TokenId::unspecified(), | ||
115 | }) | ||
116 | .into(), | ||
112 | tt::Leaf::from(tt::Ident { text: v.clone(), id: tt::TokenId::unspecified() }) | 117 | tt::Leaf::from(tt::Ident { text: v.clone(), id: tt::TokenId::unspecified() }) |
113 | .into(), | 118 | .into(), |
114 | ], | 119 | ], |
@@ -147,7 +152,7 @@ fn expand_repeat( | |||
147 | ctx.var_expanded = false; | 152 | ctx.var_expanded = false; |
148 | 153 | ||
149 | while let Ok(mut t) = expand_subtree(ctx, template) { | 154 | while let Ok(mut t) = expand_subtree(ctx, template) { |
150 | t.delimiter = tt::Delimiter::None; | 155 | t.delimiter = None; |
151 | // if no var expanded in the child, we count it as a fail | 156 | // if no var expanded in the child, we count it as a fail |
152 | if !ctx.var_expanded { | 157 | if !ctx.var_expanded { |
153 | break; | 158 | break; |
@@ -212,7 +217,7 @@ fn expand_repeat( | |||
212 | 217 | ||
213 | // Check if it is a single token subtree without any delimiter | 218 | // Check if it is a single token subtree without any delimiter |
214 | // e.g {Delimiter:None> ['>'] /Delimiter:None>} | 219 | // e.g {Delimiter:None> ['>'] /Delimiter:None>} |
215 | let tt = tt::Subtree { delimiter: tt::Delimiter::None, token_trees: buf }.into(); | 220 | let tt = tt::Subtree { delimiter: None, token_trees: buf }.into(); |
216 | Ok(Fragment::Tokens(tt)) | 221 | Ok(Fragment::Tokens(tt)) |
217 | } | 222 | } |
218 | 223 | ||
@@ -225,7 +230,7 @@ fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) { | |||
225 | 230 | ||
226 | fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) { | 231 | fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) { |
227 | match tt.delimiter { | 232 | match tt.delimiter { |
228 | tt::Delimiter::None => buf.extend(tt.token_trees), | 233 | None => buf.extend(tt.token_trees), |
229 | _ => buf.push(tt.into()), | 234 | _ => buf.push(tt.into()), |
230 | } | 235 | } |
231 | } | 236 | } |
diff --git a/crates/ra_mbe/src/subtree_source.rs b/crates/ra_mbe/src/subtree_source.rs index 7ef45f6dc..b841c39d3 100644 --- a/crates/ra_mbe/src/subtree_source.rs +++ b/crates/ra_mbe/src/subtree_source.rs | |||
@@ -70,11 +70,11 @@ impl<'a> SubtreeTokenSource<'a> { | |||
70 | } | 70 | } |
71 | Some(tt::TokenTree::Subtree(subtree)) => { | 71 | Some(tt::TokenTree::Subtree(subtree)) => { |
72 | self.cached_cursor.set(cursor.subtree().unwrap()); | 72 | self.cached_cursor.set(cursor.subtree().unwrap()); |
73 | cached.push(Some(convert_delim(subtree.delimiter, false))); | 73 | cached.push(Some(convert_delim(subtree.delimiter_kind(), false))); |
74 | } | 74 | } |
75 | None => { | 75 | None => { |
76 | if let Some(subtree) = cursor.end() { | 76 | if let Some(subtree) = cursor.end() { |
77 | cached.push(Some(convert_delim(subtree.delimiter, true))); | 77 | cached.push(Some(convert_delim(subtree.delimiter_kind(), true))); |
78 | self.cached_cursor.set(cursor.bump()); | 78 | self.cached_cursor.set(cursor.bump()); |
79 | } | 79 | } |
80 | } | 80 | } |
@@ -114,12 +114,12 @@ impl<'a> TokenSource for SubtreeTokenSource<'a> { | |||
114 | } | 114 | } |
115 | } | 115 | } |
116 | 116 | ||
117 | fn convert_delim(d: tt::Delimiter, closing: bool) -> TtToken { | 117 | fn convert_delim(d: Option<tt::DelimiterKind>, closing: bool) -> TtToken { |
118 | let (kinds, texts) = match d { | 118 | let (kinds, texts) = match d { |
119 | tt::Delimiter::Parenthesis => ([T!['('], T![')']], "()"), | 119 | Some(tt::DelimiterKind::Parenthesis) => ([T!['('], T![')']], "()"), |
120 | tt::Delimiter::Brace => ([T!['{'], T!['}']], "{}"), | 120 | Some(tt::DelimiterKind::Brace) => ([T!['{'], T!['}']], "{}"), |
121 | tt::Delimiter::Bracket => ([T!['['], T![']']], "[]"), | 121 | Some(tt::DelimiterKind::Bracket) => ([T!['['], T![']']], "[]"), |
122 | tt::Delimiter::None => ([L_DOLLAR, R_DOLLAR], ""), | 122 | None => ([L_DOLLAR, R_DOLLAR], ""), |
123 | }; | 123 | }; |
124 | 124 | ||
125 | let idx = closing as usize; | 125 | let idx = closing as usize; |
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 | ||
3 | use ra_parser::{FragmentKind, ParseError, TreeSink}; | 3 | use ra_parser::{FragmentKind, ParseError, TreeSink}; |
4 | use ra_syntax::{ | 4 | use 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 | }; |
8 | use rustc_hash::FxHashMap; | ||
8 | use std::iter::successors; | 9 | use std::iter::successors; |
9 | use tt::buffer::{Cursor, TokenBuffer}; | 10 | use tt::buffer::{Cursor, TokenBuffer}; |
10 | 11 | ||
11 | use crate::subtree_source::SubtreeTokenSource; | 12 | use crate::subtree_source::SubtreeTokenSource; |
12 | use crate::ExpandError; | 13 | use crate::ExpandError; |
13 | 14 | ||
15 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
16 | pub enum TokenTextRange { | ||
17 | Token(TextRange), | ||
18 | Delimiter(TextRange, TextRange), | ||
19 | } | ||
20 | |||
21 | impl 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)] |
16 | pub struct TokenMap { | 36 | pub 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). |
23 | pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap)> { | 43 | pub 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 | ||
72 | impl TokenMap { | 92 | impl 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 | ||
268 | struct TtTreeSink<'a> { | 340 | struct 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 | ||
297 | fn delim_to_str(d: tt::Delimiter, closing: bool) -> SmolStr { | 371 | fn 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)] |
388 | mod tests { | 477 | mod 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 | } |
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs index 0109a4d98..e640d115b 100644 --- a/crates/ra_mbe/src/tests.rs +++ b/crates/ra_mbe/src/tests.rs | |||
@@ -1,5 +1,7 @@ | |||
1 | use std::fmt::Write; | ||
2 | |||
1 | use ra_parser::FragmentKind; | 3 | use ra_parser::FragmentKind; |
2 | use ra_syntax::{ast, AstNode, NodeOrToken, WalkEvent}; | 4 | use ra_syntax::{ast, AstNode, NodeOrToken, SyntaxKind::IDENT, SyntaxNode, WalkEvent, T}; |
3 | use test_utils::assert_eq_text; | 5 | use test_utils::assert_eq_text; |
4 | 6 | ||
5 | use super::*; | 7 | use super::*; |
@@ -61,13 +63,14 @@ mod rule_parsing { | |||
61 | 63 | ||
62 | #[test] | 64 | #[test] |
63 | fn test_token_id_shift() { | 65 | fn test_token_id_shift() { |
64 | let macro_definition = r#" | 66 | let expansion = parse_macro( |
67 | r#" | ||
65 | macro_rules! foobar { | 68 | macro_rules! foobar { |
66 | ($e:ident) => { foo bar $e } | 69 | ($e:ident) => { foo bar $e } |
67 | } | 70 | } |
68 | "#; | 71 | "#, |
69 | let rules = create_rules(macro_definition); | 72 | ) |
70 | let expansion = expand(&rules, "foobar!(baz);"); | 73 | .expand_tt("foobar!(baz);"); |
71 | 74 | ||
72 | fn get_id(t: &tt::TokenTree) -> Option<u32> { | 75 | fn get_id(t: &tt::TokenTree) -> Option<u32> { |
73 | if let tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = t { | 76 | if let tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = t { |
@@ -77,18 +80,47 @@ macro_rules! foobar { | |||
77 | } | 80 | } |
78 | 81 | ||
79 | assert_eq!(expansion.token_trees.len(), 3); | 82 | assert_eq!(expansion.token_trees.len(), 3); |
80 | // ($e:ident) => { foo bar $e } | 83 | // {($e:ident) => { foo bar $e }} |
81 | // 0 1 2 3 4 | 84 | // 012345 67 8 9 T 12 |
82 | assert_eq!(get_id(&expansion.token_trees[0]), Some(2)); | 85 | assert_eq!(get_id(&expansion.token_trees[0]), Some(9)); |
83 | assert_eq!(get_id(&expansion.token_trees[1]), Some(3)); | 86 | assert_eq!(get_id(&expansion.token_trees[1]), Some(10)); |
84 | 87 | ||
85 | // So baz should be 5 | 88 | // The input args of macro call include parentheses: |
86 | assert_eq!(get_id(&expansion.token_trees[2]), Some(5)); | 89 | // (baz) |
90 | // So baz should be 12+1+1 | ||
91 | assert_eq!(get_id(&expansion.token_trees[2]), Some(14)); | ||
92 | } | ||
93 | |||
94 | #[test] | ||
95 | fn test_token_map() { | ||
96 | let expanded = parse_macro( | ||
97 | r#" | ||
98 | macro_rules! foobar { | ||
99 | ($e:ident) => { fn $e() {} } | ||
100 | } | ||
101 | "#, | ||
102 | ) | ||
103 | .expand_tt("foobar!(baz);"); | ||
104 | |||
105 | let (node, token_map) = token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap(); | ||
106 | let content = node.syntax_node().to_string(); | ||
107 | |||
108 | let get_text = |id, kind| -> String { | ||
109 | content[token_map.range_by_token(id).unwrap().by_kind(kind).unwrap()].to_string() | ||
110 | }; | ||
111 | |||
112 | assert_eq!(expanded.token_trees.len(), 4); | ||
113 | // {($e:ident) => { fn $e() {} }} | ||
114 | // 012345 67 8 9 T12 3 | ||
115 | |||
116 | assert_eq!(get_text(tt::TokenId(9), IDENT), "fn"); | ||
117 | assert_eq!(get_text(tt::TokenId(12), T!['(']), "("); | ||
118 | assert_eq!(get_text(tt::TokenId(13), T!['{']), "{"); | ||
87 | } | 119 | } |
88 | 120 | ||
89 | #[test] | 121 | #[test] |
90 | fn test_convert_tt() { | 122 | fn test_convert_tt() { |
91 | let macro_definition = r#" | 123 | parse_macro(r#" |
92 | macro_rules! impl_froms { | 124 | macro_rules! impl_froms { |
93 | ($e:ident: $($v:ident),*) => { | 125 | ($e:ident: $($v:ident),*) => { |
94 | $( | 126 | $( |
@@ -100,24 +132,17 @@ macro_rules! impl_froms { | |||
100 | )* | 132 | )* |
101 | } | 133 | } |
102 | } | 134 | } |
103 | "#; | 135 | "#) |
104 | 136 | .assert_expand_tt( | |
105 | let macro_invocation = r#" | 137 | "impl_froms!(TokenTree: Leaf, Subtree);", |
106 | impl_froms!(TokenTree: Leaf, Subtree); | 138 | "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \ |
107 | "#; | 139 | impl From <Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree ::Subtree (it)}}" |
108 | 140 | ); | |
109 | let rules = create_rules(macro_definition); | ||
110 | let expansion = expand(&rules, macro_invocation); | ||
111 | assert_eq!( | ||
112 | expansion.to_string(), | ||
113 | "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \ | ||
114 | impl From <Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree ::Subtree (it)}}" | ||
115 | ) | ||
116 | } | 141 | } |
117 | 142 | ||
118 | #[test] | 143 | #[test] |
119 | fn test_expr_order() { | 144 | fn test_expr_order() { |
120 | let rules = create_rules( | 145 | let expanded = parse_macro( |
121 | r#" | 146 | r#" |
122 | macro_rules! foo { | 147 | macro_rules! foo { |
123 | ($ i:expr) => { | 148 | ($ i:expr) => { |
@@ -125,11 +150,10 @@ fn test_expr_order() { | |||
125 | } | 150 | } |
126 | } | 151 | } |
127 | "#, | 152 | "#, |
128 | ); | 153 | ) |
129 | let expanded = expand(&rules, "foo! { 1 + 1}"); | 154 | .expand_items("foo! { 1 + 1}"); |
130 | let tree = token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap().0.syntax_node(); | ||
131 | 155 | ||
132 | let dump = format!("{:#?}", tree); | 156 | let dump = format!("{:#?}", expanded); |
133 | assert_eq_text!( | 157 | assert_eq_text!( |
134 | dump.trim(), | 158 | dump.trim(), |
135 | r#"MACRO_ITEMS@[0; 15) | 159 | r#"MACRO_ITEMS@[0; 15) |
@@ -161,7 +185,7 @@ fn test_expr_order() { | |||
161 | 185 | ||
162 | #[test] | 186 | #[test] |
163 | fn test_fail_match_pattern_by_first_token() { | 187 | fn test_fail_match_pattern_by_first_token() { |
164 | let rules = create_rules( | 188 | parse_macro( |
165 | r#" | 189 | r#" |
166 | macro_rules! foo { | 190 | macro_rules! foo { |
167 | ($ i:ident) => ( | 191 | ($ i:ident) => ( |
@@ -175,16 +199,15 @@ fn test_fail_match_pattern_by_first_token() { | |||
175 | ) | 199 | ) |
176 | } | 200 | } |
177 | "#, | 201 | "#, |
178 | ); | 202 | ) |
179 | 203 | .assert_expand_items("foo! { foo }", "mod foo {}") | |
180 | assert_expansion(MacroKind::Items, &rules, "foo! { foo }", "mod foo {}"); | 204 | .assert_expand_items("foo! { = bar }", "fn bar () {}") |
181 | assert_expansion(MacroKind::Items, &rules, "foo! { = bar }", "fn bar () {}"); | 205 | .assert_expand_items("foo! { + Baz }", "struct Baz ;"); |
182 | assert_expansion(MacroKind::Items, &rules, "foo! { + Baz }", "struct Baz ;"); | ||
183 | } | 206 | } |
184 | 207 | ||
185 | #[test] | 208 | #[test] |
186 | fn test_fail_match_pattern_by_last_token() { | 209 | fn test_fail_match_pattern_by_last_token() { |
187 | let rules = create_rules( | 210 | parse_macro( |
188 | r#" | 211 | r#" |
189 | macro_rules! foo { | 212 | macro_rules! foo { |
190 | ($ i:ident) => ( | 213 | ($ i:ident) => ( |
@@ -198,16 +221,15 @@ fn test_fail_match_pattern_by_last_token() { | |||
198 | ) | 221 | ) |
199 | } | 222 | } |
200 | "#, | 223 | "#, |
201 | ); | 224 | ) |
202 | 225 | .assert_expand_items("foo! { foo }", "mod foo {}") | |
203 | assert_expansion(MacroKind::Items, &rules, "foo! { foo }", "mod foo {}"); | 226 | .assert_expand_items("foo! { bar = }", "fn bar () {}") |
204 | assert_expansion(MacroKind::Items, &rules, "foo! { bar = }", "fn bar () {}"); | 227 | .assert_expand_items("foo! { Baz + }", "struct Baz ;"); |
205 | assert_expansion(MacroKind::Items, &rules, "foo! { Baz + }", "struct Baz ;"); | ||
206 | } | 228 | } |
207 | 229 | ||
208 | #[test] | 230 | #[test] |
209 | fn test_fail_match_pattern_by_word_token() { | 231 | fn test_fail_match_pattern_by_word_token() { |
210 | let rules = create_rules( | 232 | parse_macro( |
211 | r#" | 233 | r#" |
212 | macro_rules! foo { | 234 | macro_rules! foo { |
213 | ($ i:ident) => ( | 235 | ($ i:ident) => ( |
@@ -221,16 +243,15 @@ fn test_fail_match_pattern_by_word_token() { | |||
221 | ) | 243 | ) |
222 | } | 244 | } |
223 | "#, | 245 | "#, |
224 | ); | 246 | ) |
225 | 247 | .assert_expand_items("foo! { foo }", "mod foo {}") | |
226 | assert_expansion(MacroKind::Items, &rules, "foo! { foo }", "mod foo {}"); | 248 | .assert_expand_items("foo! { spam bar }", "fn bar () {}") |
227 | assert_expansion(MacroKind::Items, &rules, "foo! { spam bar }", "fn bar () {}"); | 249 | .assert_expand_items("foo! { eggs Baz }", "struct Baz ;"); |
228 | assert_expansion(MacroKind::Items, &rules, "foo! { eggs Baz }", "struct Baz ;"); | ||
229 | } | 250 | } |
230 | 251 | ||
231 | #[test] | 252 | #[test] |
232 | fn test_match_group_pattern_by_separator_token() { | 253 | fn test_match_group_pattern_by_separator_token() { |
233 | let rules = create_rules( | 254 | parse_macro( |
234 | r#" | 255 | r#" |
235 | macro_rules! foo { | 256 | macro_rules! foo { |
236 | ($ ($ i:ident),*) => ($ ( | 257 | ($ ($ i:ident),*) => ($ ( |
@@ -245,16 +266,15 @@ fn test_match_group_pattern_by_separator_token() { | |||
245 | ) | 266 | ) |
246 | } | 267 | } |
247 | "#, | 268 | "#, |
248 | ); | 269 | ) |
249 | 270 | .assert_expand_items("foo! { foo, bar }", "mod foo {} mod bar {}") | |
250 | assert_expansion(MacroKind::Items, &rules, "foo! { foo, bar }", "mod foo {} mod bar {}"); | 271 | .assert_expand_items("foo! { foo# bar }", "fn foo () {} fn bar () {}") |
251 | assert_expansion(MacroKind::Items, &rules, "foo! { foo# bar }", "fn foo () {} fn bar () {}"); | 272 | .assert_expand_items("foo! { Foo,# Bar }", "struct Foo ; struct Bar ;"); |
252 | assert_expansion(MacroKind::Items, &rules, "foo! { Foo,# Bar }", "struct Foo ; struct Bar ;"); | ||
253 | } | 273 | } |
254 | 274 | ||
255 | #[test] | 275 | #[test] |
256 | fn test_match_group_pattern_with_multiple_defs() { | 276 | fn test_match_group_pattern_with_multiple_defs() { |
257 | let rules = create_rules( | 277 | parse_macro( |
258 | r#" | 278 | r#" |
259 | macro_rules! foo { | 279 | macro_rules! foo { |
260 | ($ ($ i:ident),*) => ( struct Bar { $ ( | 280 | ($ ($ i:ident),*) => ( struct Bar { $ ( |
@@ -262,19 +282,13 @@ fn test_match_group_pattern_with_multiple_defs() { | |||
262 | )*} ); | 282 | )*} ); |
263 | } | 283 | } |
264 | "#, | 284 | "#, |
265 | ); | 285 | ) |
266 | 286 | .assert_expand_items("foo! { foo, bar }", "struct Bar {fn foo {} fn bar {}}"); | |
267 | assert_expansion( | ||
268 | MacroKind::Items, | ||
269 | &rules, | ||
270 | "foo! { foo, bar }", | ||
271 | "struct Bar {fn foo {} fn bar {}}", | ||
272 | ); | ||
273 | } | 287 | } |
274 | 288 | ||
275 | #[test] | 289 | #[test] |
276 | fn test_match_group_pattern_with_multiple_statement() { | 290 | fn test_match_group_pattern_with_multiple_statement() { |
277 | let rules = create_rules( | 291 | parse_macro( |
278 | r#" | 292 | r#" |
279 | macro_rules! foo { | 293 | macro_rules! foo { |
280 | ($ ($ i:ident),*) => ( fn baz { $ ( | 294 | ($ ($ i:ident),*) => ( fn baz { $ ( |
@@ -282,14 +296,13 @@ fn test_match_group_pattern_with_multiple_statement() { | |||
282 | )*} ); | 296 | )*} ); |
283 | } | 297 | } |
284 | "#, | 298 | "#, |
285 | ); | 299 | ) |
286 | 300 | .assert_expand_items("foo! { foo, bar }", "fn baz {foo () ; bar () ;}"); | |
287 | assert_expansion(MacroKind::Items, &rules, "foo! { foo, bar }", "fn baz {foo () ; bar () ;}"); | ||
288 | } | 301 | } |
289 | 302 | ||
290 | #[test] | 303 | #[test] |
291 | fn test_match_group_pattern_with_multiple_statement_without_semi() { | 304 | fn test_match_group_pattern_with_multiple_statement_without_semi() { |
292 | let rules = create_rules( | 305 | parse_macro( |
293 | r#" | 306 | r#" |
294 | macro_rules! foo { | 307 | macro_rules! foo { |
295 | ($ ($ i:ident),*) => ( fn baz { $ ( | 308 | ($ ($ i:ident),*) => ( fn baz { $ ( |
@@ -297,14 +310,13 @@ fn test_match_group_pattern_with_multiple_statement_without_semi() { | |||
297 | );*} ); | 310 | );*} ); |
298 | } | 311 | } |
299 | "#, | 312 | "#, |
300 | ); | 313 | ) |
301 | 314 | .assert_expand_items("foo! { foo, bar }", "fn baz {foo () ;bar ()}"); | |
302 | assert_expansion(MacroKind::Items, &rules, "foo! { foo, bar }", "fn baz {foo () ;bar ()}"); | ||
303 | } | 315 | } |
304 | 316 | ||
305 | #[test] | 317 | #[test] |
306 | fn test_match_group_empty_fixed_token() { | 318 | fn test_match_group_empty_fixed_token() { |
307 | let rules = create_rules( | 319 | parse_macro( |
308 | r#" | 320 | r#" |
309 | macro_rules! foo { | 321 | macro_rules! foo { |
310 | ($ ($ i:ident)* #abc) => ( fn baz { $ ( | 322 | ($ ($ i:ident)* #abc) => ( fn baz { $ ( |
@@ -312,69 +324,59 @@ fn test_match_group_empty_fixed_token() { | |||
312 | )*} ); | 324 | )*} ); |
313 | } | 325 | } |
314 | "#, | 326 | "#, |
315 | ); | 327 | ) |
316 | 328 | .assert_expand_items("foo! {#abc}", "fn baz {}"); | |
317 | assert_expansion(MacroKind::Items, &rules, "foo! {#abc}", "fn baz {}"); | ||
318 | } | 329 | } |
319 | 330 | ||
320 | #[test] | 331 | #[test] |
321 | fn test_match_group_in_subtree() { | 332 | fn test_match_group_in_subtree() { |
322 | let rules = create_rules( | 333 | parse_macro( |
323 | r#" | 334 | r#" |
324 | macro_rules! foo { | 335 | macro_rules! foo { |
325 | (fn $name:ident {$($i:ident)*} ) => ( fn $name() { $ ( | 336 | (fn $name:ident {$($i:ident)*} ) => ( fn $name() { $ ( |
326 | $ i (); | 337 | $ i (); |
327 | )*} ); | 338 | )*} ); |
328 | }"#, | 339 | }"#, |
329 | ); | 340 | ) |
330 | 341 | .assert_expand_items("foo! {fn baz {a b} }", "fn baz () {a () ; b () ;}"); | |
331 | assert_expansion(MacroKind::Items, &rules, "foo! {fn baz {a b} }", "fn baz () {a () ; b () ;}"); | ||
332 | } | 342 | } |
333 | 343 | ||
334 | #[test] | 344 | #[test] |
335 | fn test_match_group_with_multichar_sep() { | 345 | fn test_match_group_with_multichar_sep() { |
336 | let rules = create_rules( | 346 | parse_macro( |
337 | r#" | 347 | r#" |
338 | macro_rules! foo { | 348 | macro_rules! foo { |
339 | (fn $name:ident {$($i:literal)*} ) => ( fn $name() -> bool { $($i)&&*} ); | 349 | (fn $name:ident {$($i:literal)*} ) => ( fn $name() -> bool { $($i)&&*} ); |
340 | }"#, | 350 | }"#, |
341 | ); | 351 | ) |
342 | 352 | .assert_expand_items("foo! (fn baz {true true} );", "fn baz () -> bool {true &&true}"); | |
343 | assert_expansion( | ||
344 | MacroKind::Items, | ||
345 | &rules, | ||
346 | "foo! (fn baz {true true} );", | ||
347 | "fn baz () -> bool {true &&true}", | ||
348 | ); | ||
349 | } | 353 | } |
350 | 354 | ||
351 | #[test] | 355 | #[test] |
352 | fn test_match_group_zero_match() { | 356 | fn test_match_group_zero_match() { |
353 | let rules = create_rules( | 357 | parse_macro( |
354 | r#" | 358 | r#" |
355 | macro_rules! foo { | 359 | macro_rules! foo { |
356 | ( $($i:ident)* ) => (); | 360 | ( $($i:ident)* ) => (); |
357 | }"#, | 361 | }"#, |
358 | ); | 362 | ) |
359 | 363 | .assert_expand_items("foo! ();", ""); | |
360 | assert_expansion(MacroKind::Items, &rules, "foo! ();", ""); | ||
361 | } | 364 | } |
362 | 365 | ||
363 | #[test] | 366 | #[test] |
364 | fn test_match_group_in_group() { | 367 | fn test_match_group_in_group() { |
365 | let rules = create_rules( | 368 | parse_macro( |
366 | r#" | 369 | r#" |
367 | macro_rules! foo { | 370 | macro_rules! foo { |
368 | { $( ( $($i:ident)* ) )* } => ( $( ( $($i)* ) )* ); | 371 | { $( ( $($i:ident)* ) )* } => ( $( ( $($i)* ) )* ); |
369 | }"#, | 372 | }"#, |
370 | ); | 373 | ) |
371 | 374 | .assert_expand_items("foo! ( (a b) );", "(a b)"); | |
372 | assert_expansion(MacroKind::Items, &rules, "foo! ( (a b) );", "(a b)"); | ||
373 | } | 375 | } |
374 | 376 | ||
375 | #[test] | 377 | #[test] |
376 | fn test_expand_to_item_list() { | 378 | fn test_expand_to_item_list() { |
377 | let rules = create_rules( | 379 | let tree = parse_macro( |
378 | " | 380 | " |
379 | macro_rules! structs { | 381 | macro_rules! structs { |
380 | ($($i:ident),*) => { | 382 | ($($i:ident),*) => { |
@@ -382,9 +384,8 @@ fn test_expand_to_item_list() { | |||
382 | } | 384 | } |
383 | } | 385 | } |
384 | ", | 386 | ", |
385 | ); | 387 | ) |
386 | let expansion = expand(&rules, "structs!(Foo, Bar);"); | 388 | .expand_items("structs!(Foo, Bar);"); |
387 | let tree = token_tree_to_syntax_node(&expansion, FragmentKind::Items).unwrap().0.syntax_node(); | ||
388 | assert_eq!( | 389 | assert_eq!( |
389 | format!("{:#?}", tree).trim(), | 390 | format!("{:#?}", tree).trim(), |
390 | r#" | 391 | r#" |
@@ -441,7 +442,7 @@ fn test_expand_literals_to_token_tree() { | |||
441 | unreachable!("It is not a literal"); | 442 | unreachable!("It is not a literal"); |
442 | } | 443 | } |
443 | 444 | ||
444 | let rules = create_rules( | 445 | let expansion = parse_macro( |
445 | r#" | 446 | r#" |
446 | macro_rules! literals { | 447 | macro_rules! literals { |
447 | ($i:ident) => { | 448 | ($i:ident) => { |
@@ -454,8 +455,8 @@ fn test_expand_literals_to_token_tree() { | |||
454 | } | 455 | } |
455 | } | 456 | } |
456 | "#, | 457 | "#, |
457 | ); | 458 | ) |
458 | let expansion = expand(&rules, "literals!(foo);"); | 459 | .expand_tt("literals!(foo);"); |
459 | let stm_tokens = &to_subtree(&expansion.token_trees[0]).token_trees; | 460 | let stm_tokens = &to_subtree(&expansion.token_trees[0]).token_trees; |
460 | 461 | ||
461 | // [let] [a] [=] ['c'] [;] | 462 | // [let] [a] [=] ['c'] [;] |
@@ -470,7 +471,7 @@ fn test_expand_literals_to_token_tree() { | |||
470 | 471 | ||
471 | #[test] | 472 | #[test] |
472 | fn test_two_idents() { | 473 | fn test_two_idents() { |
473 | let rules = create_rules( | 474 | parse_macro( |
474 | r#" | 475 | r#" |
475 | macro_rules! foo { | 476 | macro_rules! foo { |
476 | ($ i:ident, $ j:ident) => { | 477 | ($ i:ident, $ j:ident) => { |
@@ -478,18 +479,13 @@ fn test_two_idents() { | |||
478 | } | 479 | } |
479 | } | 480 | } |
480 | "#, | 481 | "#, |
481 | ); | 482 | ) |
482 | assert_expansion( | 483 | .assert_expand_items("foo! { foo, bar }", "fn foo () {let a = foo ; let b = bar ;}"); |
483 | MacroKind::Items, | ||
484 | &rules, | ||
485 | "foo! { foo, bar }", | ||
486 | "fn foo () {let a = foo ; let b = bar ;}", | ||
487 | ); | ||
488 | } | 484 | } |
489 | 485 | ||
490 | #[test] | 486 | #[test] |
491 | fn test_tt_to_stmts() { | 487 | fn test_tt_to_stmts() { |
492 | let rules = create_rules( | 488 | let stmts = parse_macro( |
493 | r#" | 489 | r#" |
494 | macro_rules! foo { | 490 | macro_rules! foo { |
495 | () => { | 491 | () => { |
@@ -499,11 +495,8 @@ fn test_tt_to_stmts() { | |||
499 | } | 495 | } |
500 | } | 496 | } |
501 | "#, | 497 | "#, |
502 | ); | 498 | ) |
503 | 499 | .expand_statements("foo!{}"); | |
504 | let expanded = expand(&rules, "foo!{}"); | ||
505 | let stmts = | ||
506 | token_tree_to_syntax_node(&expanded, FragmentKind::Statements).unwrap().0.syntax_node(); | ||
507 | 500 | ||
508 | assert_eq!( | 501 | assert_eq!( |
509 | format!("{:#?}", stmts).trim(), | 502 | format!("{:#?}", stmts).trim(), |
@@ -543,7 +536,7 @@ fn test_tt_to_stmts() { | |||
543 | 536 | ||
544 | #[test] | 537 | #[test] |
545 | fn test_match_literal() { | 538 | fn test_match_literal() { |
546 | let rules = create_rules( | 539 | parse_macro( |
547 | r#" | 540 | r#" |
548 | macro_rules! foo { | 541 | macro_rules! foo { |
549 | ('(') => { | 542 | ('(') => { |
@@ -551,8 +544,8 @@ fn test_match_literal() { | |||
551 | } | 544 | } |
552 | } | 545 | } |
553 | "#, | 546 | "#, |
554 | ); | 547 | ) |
555 | assert_expansion(MacroKind::Items, &rules, "foo! ['('];", "fn foo () {}"); | 548 | .assert_expand_items("foo! ['('];", "fn foo () {}"); |
556 | } | 549 | } |
557 | 550 | ||
558 | // The following tests are port from intellij-rust directly | 551 | // The following tests are port from intellij-rust directly |
@@ -560,7 +553,7 @@ fn test_match_literal() { | |||
560 | 553 | ||
561 | #[test] | 554 | #[test] |
562 | fn test_path() { | 555 | fn test_path() { |
563 | let rules = create_rules( | 556 | parse_macro( |
564 | r#" | 557 | r#" |
565 | macro_rules! foo { | 558 | macro_rules! foo { |
566 | ($ i:path) => { | 559 | ($ i:path) => { |
@@ -568,11 +561,9 @@ fn test_path() { | |||
568 | } | 561 | } |
569 | } | 562 | } |
570 | "#, | 563 | "#, |
571 | ); | 564 | ) |
572 | assert_expansion(MacroKind::Items, &rules, "foo! { foo }", "fn foo () {let a = foo ;}"); | 565 | .assert_expand_items("foo! { foo }", "fn foo () {let a = foo ;}") |
573 | assert_expansion( | 566 | .assert_expand_items( |
574 | MacroKind::Items, | ||
575 | &rules, | ||
576 | "foo! { bar::<u8>::baz::<u8> }", | 567 | "foo! { bar::<u8>::baz::<u8> }", |
577 | "fn foo () {let a = bar ::< u8 >:: baz ::< u8 > ;}", | 568 | "fn foo () {let a = bar ::< u8 >:: baz ::< u8 > ;}", |
578 | ); | 569 | ); |
@@ -580,7 +571,7 @@ fn test_path() { | |||
580 | 571 | ||
581 | #[test] | 572 | #[test] |
582 | fn test_two_paths() { | 573 | fn test_two_paths() { |
583 | let rules = create_rules( | 574 | parse_macro( |
584 | r#" | 575 | r#" |
585 | macro_rules! foo { | 576 | macro_rules! foo { |
586 | ($ i:path, $ j:path) => { | 577 | ($ i:path, $ j:path) => { |
@@ -588,18 +579,13 @@ fn test_two_paths() { | |||
588 | } | 579 | } |
589 | } | 580 | } |
590 | "#, | 581 | "#, |
591 | ); | 582 | ) |
592 | assert_expansion( | 583 | .assert_expand_items("foo! { foo, bar }", "fn foo () {let a = foo ; let b = bar ;}"); |
593 | MacroKind::Items, | ||
594 | &rules, | ||
595 | "foo! { foo, bar }", | ||
596 | "fn foo () {let a = foo ; let b = bar ;}", | ||
597 | ); | ||
598 | } | 584 | } |
599 | 585 | ||
600 | #[test] | 586 | #[test] |
601 | fn test_path_with_path() { | 587 | fn test_path_with_path() { |
602 | let rules = create_rules( | 588 | parse_macro( |
603 | r#" | 589 | r#" |
604 | macro_rules! foo { | 590 | macro_rules! foo { |
605 | ($ i:path) => { | 591 | ($ i:path) => { |
@@ -607,13 +593,13 @@ fn test_path_with_path() { | |||
607 | } | 593 | } |
608 | } | 594 | } |
609 | "#, | 595 | "#, |
610 | ); | 596 | ) |
611 | assert_expansion(MacroKind::Items, &rules, "foo! { foo }", "fn foo () {let a = foo :: bar ;}"); | 597 | .assert_expand_items("foo! { foo }", "fn foo () {let a = foo :: bar ;}"); |
612 | } | 598 | } |
613 | 599 | ||
614 | #[test] | 600 | #[test] |
615 | fn test_expr() { | 601 | fn test_expr() { |
616 | let rules = create_rules( | 602 | parse_macro( |
617 | r#" | 603 | r#" |
618 | macro_rules! foo { | 604 | macro_rules! foo { |
619 | ($ i:expr) => { | 605 | ($ i:expr) => { |
@@ -621,11 +607,8 @@ fn test_expr() { | |||
621 | } | 607 | } |
622 | } | 608 | } |
623 | "#, | 609 | "#, |
624 | ); | 610 | ) |
625 | 611 | .assert_expand_items( | |
626 | assert_expansion( | ||
627 | MacroKind::Items, | ||
628 | &rules, | ||
629 | "foo! { 2 + 2 * baz(3).quux() }", | 612 | "foo! { 2 + 2 * baz(3).quux() }", |
630 | "fn bar () {2 + 2 * baz (3) . quux () ;}", | 613 | "fn bar () {2 + 2 * baz (3) . quux () ;}", |
631 | ); | 614 | ); |
@@ -633,7 +616,7 @@ fn test_expr() { | |||
633 | 616 | ||
634 | #[test] | 617 | #[test] |
635 | fn test_last_expr() { | 618 | fn test_last_expr() { |
636 | let rules = create_rules( | 619 | parse_macro( |
637 | r#" | 620 | r#" |
638 | macro_rules! vec { | 621 | macro_rules! vec { |
639 | ($($item:expr),*) => { | 622 | ($($item:expr),*) => { |
@@ -647,10 +630,8 @@ fn test_last_expr() { | |||
647 | }; | 630 | }; |
648 | } | 631 | } |
649 | "#, | 632 | "#, |
650 | ); | 633 | ) |
651 | assert_expansion( | 634 | .assert_expand_items( |
652 | MacroKind::Items, | ||
653 | &rules, | ||
654 | "vec!(1,2,3);", | 635 | "vec!(1,2,3);", |
655 | "{let mut v = Vec :: new () ; v . push (1) ; v . push (2) ; v . push (3) ; v}", | 636 | "{let mut v = Vec :: new () ; v . push (1) ; v . push (2) ; v . push (3) ; v}", |
656 | ); | 637 | ); |
@@ -658,7 +639,7 @@ fn test_last_expr() { | |||
658 | 639 | ||
659 | #[test] | 640 | #[test] |
660 | fn test_ty() { | 641 | fn test_ty() { |
661 | let rules = create_rules( | 642 | parse_macro( |
662 | r#" | 643 | r#" |
663 | macro_rules! foo { | 644 | macro_rules! foo { |
664 | ($ i:ty) => ( | 645 | ($ i:ty) => ( |
@@ -666,18 +647,13 @@ fn test_ty() { | |||
666 | ) | 647 | ) |
667 | } | 648 | } |
668 | "#, | 649 | "#, |
669 | ); | 650 | ) |
670 | assert_expansion( | 651 | .assert_expand_items("foo! { Baz<u8> }", "fn bar () -> Baz < u8 > {unimplemented ! ()}"); |
671 | MacroKind::Items, | ||
672 | &rules, | ||
673 | "foo! { Baz<u8> }", | ||
674 | "fn bar () -> Baz < u8 > {unimplemented ! ()}", | ||
675 | ); | ||
676 | } | 652 | } |
677 | 653 | ||
678 | #[test] | 654 | #[test] |
679 | fn test_ty_with_complex_type() { | 655 | fn test_ty_with_complex_type() { |
680 | let rules = create_rules( | 656 | parse_macro( |
681 | r#" | 657 | r#" |
682 | macro_rules! foo { | 658 | macro_rules! foo { |
683 | ($ i:ty) => ( | 659 | ($ i:ty) => ( |
@@ -685,20 +661,14 @@ fn test_ty_with_complex_type() { | |||
685 | ) | 661 | ) |
686 | } | 662 | } |
687 | "#, | 663 | "#, |
688 | ); | 664 | ) |
689 | |||
690 | // Reference lifetime struct with generic type | 665 | // Reference lifetime struct with generic type |
691 | assert_expansion( | 666 | .assert_expand_items( |
692 | MacroKind::Items, | ||
693 | &rules, | ||
694 | "foo! { &'a Baz<u8> }", | 667 | "foo! { &'a Baz<u8> }", |
695 | "fn bar () -> & 'a Baz < u8 > {unimplemented ! ()}", | 668 | "fn bar () -> & 'a Baz < u8 > {unimplemented ! ()}", |
696 | ); | 669 | ) |
697 | |||
698 | // extern "Rust" func type | 670 | // extern "Rust" func type |
699 | assert_expansion( | 671 | .assert_expand_items( |
700 | MacroKind::Items, | ||
701 | &rules, | ||
702 | r#"foo! { extern "Rust" fn() -> Ret }"#, | 672 | r#"foo! { extern "Rust" fn() -> Ret }"#, |
703 | r#"fn bar () -> extern "Rust" fn () -> Ret {unimplemented ! ()}"#, | 673 | r#"fn bar () -> extern "Rust" fn () -> Ret {unimplemented ! ()}"#, |
704 | ); | 674 | ); |
@@ -706,19 +676,19 @@ fn test_ty_with_complex_type() { | |||
706 | 676 | ||
707 | #[test] | 677 | #[test] |
708 | fn test_pat_() { | 678 | fn test_pat_() { |
709 | let rules = create_rules( | 679 | parse_macro( |
710 | r#" | 680 | r#" |
711 | macro_rules! foo { | 681 | macro_rules! foo { |
712 | ($ i:pat) => { fn foo() { let $ i; } } | 682 | ($ i:pat) => { fn foo() { let $ i; } } |
713 | } | 683 | } |
714 | "#, | 684 | "#, |
715 | ); | 685 | ) |
716 | assert_expansion(MacroKind::Items, &rules, "foo! { (a, b) }", "fn foo () {let (a , b) ;}"); | 686 | .assert_expand_items("foo! { (a, b) }", "fn foo () {let (a , b) ;}"); |
717 | } | 687 | } |
718 | 688 | ||
719 | #[test] | 689 | #[test] |
720 | fn test_stmt() { | 690 | fn test_stmt() { |
721 | let rules = create_rules( | 691 | parse_macro( |
722 | r#" | 692 | r#" |
723 | macro_rules! foo { | 693 | macro_rules! foo { |
724 | ($ i:stmt) => ( | 694 | ($ i:stmt) => ( |
@@ -726,14 +696,14 @@ fn test_stmt() { | |||
726 | ) | 696 | ) |
727 | } | 697 | } |
728 | "#, | 698 | "#, |
729 | ); | 699 | ) |
730 | assert_expansion(MacroKind::Items, &rules, "foo! { 2 }", "fn bar () {2 ;}"); | 700 | .assert_expand_items("foo! { 2 }", "fn bar () {2 ;}") |
731 | assert_expansion(MacroKind::Items, &rules, "foo! { let a = 0 }", "fn bar () {let a = 0 ;}"); | 701 | .assert_expand_items("foo! { let a = 0 }", "fn bar () {let a = 0 ;}"); |
732 | } | 702 | } |
733 | 703 | ||
734 | #[test] | 704 | #[test] |
735 | fn test_single_item() { | 705 | fn test_single_item() { |
736 | let rules = create_rules( | 706 | parse_macro( |
737 | r#" | 707 | r#" |
738 | macro_rules! foo { | 708 | macro_rules! foo { |
739 | ($ i:item) => ( | 709 | ($ i:item) => ( |
@@ -741,13 +711,13 @@ fn test_single_item() { | |||
741 | ) | 711 | ) |
742 | } | 712 | } |
743 | "#, | 713 | "#, |
744 | ); | 714 | ) |
745 | assert_expansion(MacroKind::Items, &rules, "foo! {mod c {}}", "mod c {}"); | 715 | .assert_expand_items("foo! {mod c {}}", "mod c {}"); |
746 | } | 716 | } |
747 | 717 | ||
748 | #[test] | 718 | #[test] |
749 | fn test_all_items() { | 719 | fn test_all_items() { |
750 | let rules = create_rules( | 720 | parse_macro( |
751 | r#" | 721 | r#" |
752 | macro_rules! foo { | 722 | macro_rules! foo { |
753 | ($ ($ i:item)*) => ($ ( | 723 | ($ ($ i:item)*) => ($ ( |
@@ -755,10 +725,8 @@ fn test_all_items() { | |||
755 | )*) | 725 | )*) |
756 | } | 726 | } |
757 | "#, | 727 | "#, |
758 | ); | 728 | ). |
759 | assert_expansion( | 729 | assert_expand_items( |
760 | MacroKind::Items, | ||
761 | &rules, | ||
762 | r#" | 730 | r#" |
763 | foo! { | 731 | foo! { |
764 | extern crate a; | 732 | extern crate a; |
@@ -782,19 +750,19 @@ fn test_all_items() { | |||
782 | 750 | ||
783 | #[test] | 751 | #[test] |
784 | fn test_block() { | 752 | fn test_block() { |
785 | let rules = create_rules( | 753 | parse_macro( |
786 | r#" | 754 | r#" |
787 | macro_rules! foo { | 755 | macro_rules! foo { |
788 | ($ i:block) => { fn foo() $ i } | 756 | ($ i:block) => { fn foo() $ i } |
789 | } | 757 | } |
790 | "#, | 758 | "#, |
791 | ); | 759 | ) |
792 | assert_expansion(MacroKind::Stmts, &rules, "foo! { { 1; } }", "fn foo () {1 ;}"); | 760 | .assert_expand_statements("foo! { { 1; } }", "fn foo () {1 ;}"); |
793 | } | 761 | } |
794 | 762 | ||
795 | #[test] | 763 | #[test] |
796 | fn test_meta() { | 764 | fn test_meta() { |
797 | let rules = create_rules( | 765 | parse_macro( |
798 | r#" | 766 | r#" |
799 | macro_rules! foo { | 767 | macro_rules! foo { |
800 | ($ i:meta) => ( | 768 | ($ i:meta) => ( |
@@ -803,10 +771,8 @@ fn test_meta() { | |||
803 | ) | 771 | ) |
804 | } | 772 | } |
805 | "#, | 773 | "#, |
806 | ); | 774 | ) |
807 | assert_expansion( | 775 | .assert_expand_items( |
808 | MacroKind::Items, | ||
809 | &rules, | ||
810 | r#"foo! { cfg(target_os = "windows") }"#, | 776 | r#"foo! { cfg(target_os = "windows") }"#, |
811 | r#"# [cfg (target_os = "windows")] fn bar () {}"#, | 777 | r#"# [cfg (target_os = "windows")] fn bar () {}"#, |
812 | ); | 778 | ); |
@@ -814,7 +780,7 @@ fn test_meta() { | |||
814 | 780 | ||
815 | #[test] | 781 | #[test] |
816 | fn test_meta_doc_comments() { | 782 | fn test_meta_doc_comments() { |
817 | let rules = create_rules( | 783 | parse_macro( |
818 | r#" | 784 | r#" |
819 | macro_rules! foo { | 785 | macro_rules! foo { |
820 | ($(#[$ i:meta])+) => ( | 786 | ($(#[$ i:meta])+) => ( |
@@ -823,10 +789,8 @@ fn test_meta_doc_comments() { | |||
823 | ) | 789 | ) |
824 | } | 790 | } |
825 | "#, | 791 | "#, |
826 | ); | 792 | ). |
827 | assert_expansion( | 793 | assert_expand_items( |
828 | MacroKind::Items, | ||
829 | &rules, | ||
830 | r#"foo! { | 794 | r#"foo! { |
831 | /// Single Line Doc 1 | 795 | /// Single Line Doc 1 |
832 | /** | 796 | /** |
@@ -839,69 +803,68 @@ fn test_meta_doc_comments() { | |||
839 | 803 | ||
840 | #[test] | 804 | #[test] |
841 | fn test_tt_block() { | 805 | fn test_tt_block() { |
842 | let rules = create_rules( | 806 | parse_macro( |
843 | r#" | 807 | r#" |
844 | macro_rules! foo { | 808 | macro_rules! foo { |
845 | ($ i:tt) => { fn foo() $ i } | 809 | ($ i:tt) => { fn foo() $ i } |
846 | } | 810 | } |
847 | "#, | 811 | "#, |
848 | ); | 812 | ) |
849 | assert_expansion(MacroKind::Items, &rules, r#"foo! { { 1; } }"#, r#"fn foo () {1 ;}"#); | 813 | .assert_expand_items(r#"foo! { { 1; } }"#, r#"fn foo () {1 ;}"#); |
850 | } | 814 | } |
851 | 815 | ||
852 | #[test] | 816 | #[test] |
853 | fn test_tt_group() { | 817 | fn test_tt_group() { |
854 | let rules = create_rules( | 818 | parse_macro( |
855 | r#" | 819 | r#" |
856 | macro_rules! foo { | 820 | macro_rules! foo { |
857 | ($($ i:tt)*) => { $($ i)* } | 821 | ($($ i:tt)*) => { $($ i)* } |
858 | } | 822 | } |
859 | "#, | 823 | "#, |
860 | ); | 824 | ) |
861 | assert_expansion(MacroKind::Items, &rules, r#"foo! { fn foo() {} }"#, r#"fn foo () {}"#); | 825 | .assert_expand_items(r#"foo! { fn foo() {} }"#, r#"fn foo () {}"#); |
862 | } | 826 | } |
863 | #[test] | 827 | #[test] |
864 | fn test_lifetime() { | 828 | fn test_lifetime() { |
865 | let rules = create_rules( | 829 | parse_macro( |
866 | r#" | 830 | r#" |
867 | macro_rules! foo { | 831 | macro_rules! foo { |
868 | ($ lt:lifetime) => { struct Ref<$ lt>{ s: &$ lt str } } | 832 | ($ lt:lifetime) => { struct Ref<$ lt>{ s: &$ lt str } } |
869 | } | 833 | } |
870 | "#, | 834 | "#, |
871 | ); | 835 | ) |
872 | assert_expansion(MacroKind::Items, &rules, r#"foo!{'a}"#, r#"struct Ref <'a > {s : &'a str}"#); | 836 | .assert_expand_items(r#"foo!{'a}"#, r#"struct Ref <'a > {s : &'a str}"#); |
873 | } | 837 | } |
874 | 838 | ||
875 | #[test] | 839 | #[test] |
876 | fn test_literal() { | 840 | fn test_literal() { |
877 | let rules = create_rules( | 841 | parse_macro( |
878 | r#" | 842 | r#" |
879 | macro_rules! foo { | 843 | macro_rules! foo { |
880 | ($ type:ty $ lit:literal) => { const VALUE: $ type = $ lit;}; | 844 | ($ type:ty $ lit:literal) => { const VALUE: $ type = $ lit;}; |
881 | } | 845 | } |
882 | "#, | 846 | "#, |
883 | ); | 847 | ) |
884 | assert_expansion(MacroKind::Items, &rules, r#"foo!(u8 0);"#, r#"const VALUE : u8 = 0 ;"#); | 848 | .assert_expand_items(r#"foo!(u8 0);"#, r#"const VALUE : u8 = 0 ;"#); |
885 | } | 849 | } |
886 | 850 | ||
887 | #[test] | 851 | #[test] |
888 | fn test_vis() { | 852 | fn test_vis() { |
889 | let rules = create_rules( | 853 | parse_macro( |
890 | r#" | 854 | r#" |
891 | macro_rules! foo { | 855 | macro_rules! foo { |
892 | ($ vis:vis $ name:ident) => { $ vis fn $ name() {}}; | 856 | ($ vis:vis $ name:ident) => { $ vis fn $ name() {}}; |
893 | } | 857 | } |
894 | "#, | 858 | "#, |
895 | ); | 859 | ) |
896 | assert_expansion(MacroKind::Items, &rules, r#"foo!(pub foo);"#, r#"pub fn foo () {}"#); | 860 | .assert_expand_items(r#"foo!(pub foo);"#, r#"pub fn foo () {}"#) |
897 | 861 | // test optional cases | |
898 | // test optional casse | 862 | .assert_expand_items(r#"foo!(foo);"#, r#"fn foo () {}"#); |
899 | assert_expansion(MacroKind::Items, &rules, r#"foo!(foo);"#, r#"fn foo () {}"#); | ||
900 | } | 863 | } |
901 | 864 | ||
902 | #[test] | 865 | #[test] |
903 | fn test_inner_macro_rules() { | 866 | fn test_inner_macro_rules() { |
904 | let rules = create_rules( | 867 | parse_macro( |
905 | r#" | 868 | r#" |
906 | macro_rules! foo { | 869 | macro_rules! foo { |
907 | ($a:ident, $b:ident, $c:tt) => { | 870 | ($a:ident, $b:ident, $c:tt) => { |
@@ -917,10 +880,8 @@ macro_rules! foo { | |||
917 | } | 880 | } |
918 | } | 881 | } |
919 | "#, | 882 | "#, |
920 | ); | 883 | ). |
921 | assert_expansion( | 884 | assert_expand_items( |
922 | MacroKind::Items, | ||
923 | &rules, | ||
924 | r#"foo!(x,y, 1);"#, | 885 | r#"foo!(x,y, 1);"#, |
925 | r#"macro_rules ! bar {($ bi : ident) => {fn $ bi () -> u8 {1}}} bar ! (x) ; fn y () -> u8 {1}"#, | 886 | r#"macro_rules ! bar {($ bi : ident) => {fn $ bi () -> u8 {1}}} bar ! (x) ; fn y () -> u8 {1}"#, |
926 | ); | 887 | ); |
@@ -929,7 +890,7 @@ macro_rules! foo { | |||
929 | // The following tests are based on real world situations | 890 | // The following tests are based on real world situations |
930 | #[test] | 891 | #[test] |
931 | fn test_vec() { | 892 | fn test_vec() { |
932 | let rules = create_rules( | 893 | let fixture = parse_macro( |
933 | r#" | 894 | r#" |
934 | macro_rules! vec { | 895 | macro_rules! vec { |
935 | ($($item:expr),*) => { | 896 | ($($item:expr),*) => { |
@@ -944,16 +905,14 @@ fn test_vec() { | |||
944 | } | 905 | } |
945 | "#, | 906 | "#, |
946 | ); | 907 | ); |
947 | assert_expansion(MacroKind::Items, &rules, r#"vec!();"#, r#"{let mut v = Vec :: new () ; v}"#); | 908 | fixture |
948 | assert_expansion( | 909 | .assert_expand_items(r#"vec!();"#, r#"{let mut v = Vec :: new () ; v}"#) |
949 | MacroKind::Items, | 910 | .assert_expand_items( |
950 | &rules, | 911 | r#"vec![1u32,2];"#, |
951 | r#"vec![1u32,2];"#, | 912 | r#"{let mut v = Vec :: new () ; v . push (1u32) ; v . push (2) ; v}"#, |
952 | r#"{let mut v = Vec :: new () ; v . push (1u32) ; v . push (2) ; v}"#, | 913 | ); |
953 | ); | ||
954 | 914 | ||
955 | let expansion = expand(&rules, r#"vec![1u32,2];"#); | 915 | let tree = fixture.expand_expr(r#"vec![1u32,2];"#); |
956 | let tree = token_tree_to_syntax_node(&expansion, FragmentKind::Expr).unwrap().0.syntax_node(); | ||
957 | 916 | ||
958 | assert_eq!( | 917 | assert_eq!( |
959 | format!("{:#?}", tree).trim(), | 918 | format!("{:#?}", tree).trim(), |
@@ -1027,7 +986,7 @@ fn test_vec() { | |||
1027 | fn test_winapi_struct() { | 986 | fn test_winapi_struct() { |
1028 | // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/macros.rs#L366 | 987 | // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/macros.rs#L366 |
1029 | 988 | ||
1030 | let rules = create_rules( | 989 | parse_macro( |
1031 | r#" | 990 | r#" |
1032 | macro_rules! STRUCT { | 991 | macro_rules! STRUCT { |
1033 | ($(#[$attrs:meta])* struct $name:ident { | 992 | ($(#[$attrs:meta])* struct $name:ident { |
@@ -1049,17 +1008,19 @@ macro_rules! STRUCT { | |||
1049 | ); | 1008 | ); |
1050 | } | 1009 | } |
1051 | "#, | 1010 | "#, |
1052 | ); | 1011 | ). |
1053 | // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/shared/d3d9caps.rs | 1012 | // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/shared/d3d9caps.rs |
1054 | assert_expansion(MacroKind::Items, &rules, r#"STRUCT!{struct D3DVSHADERCAPS2_0 {Caps: u8,}}"#, | 1013 | assert_expand_items(r#"STRUCT!{struct D3DVSHADERCAPS2_0 {Caps: u8,}}"#, |
1055 | "# [repr (C)] # [derive (Copy)] pub struct D3DVSHADERCAPS2_0 {pub Caps : u8 ,} impl Clone for D3DVSHADERCAPS2_0 {# [inline] fn clone (& self) -> D3DVSHADERCAPS2_0 {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DVSHADERCAPS2_0 {# [inline] fn default () -> D3DVSHADERCAPS2_0 {unsafe {$crate :: _core :: mem :: zeroed ()}}}"); | 1014 | "# [repr (C)] # [derive (Copy)] pub struct D3DVSHADERCAPS2_0 {pub Caps : u8 ,} impl Clone for D3DVSHADERCAPS2_0 {# [inline] fn clone (& self) -> D3DVSHADERCAPS2_0 {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DVSHADERCAPS2_0 {# [inline] fn default () -> D3DVSHADERCAPS2_0 {unsafe {$crate :: _core :: mem :: zeroed ()}}}" |
1056 | assert_expansion(MacroKind::Items, &rules, r#"STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct D3DCONTENTPROTECTIONCAPS {Caps : u8 ,}}"#, | 1015 | ) |
1057 | "# [repr (C)] # [derive (Copy)] # [cfg_attr (target_arch = \"x86\" , repr (packed))] pub struct D3DCONTENTPROTECTIONCAPS {pub Caps : u8 ,} impl Clone for D3DCONTENTPROTECTIONCAPS {# [inline] fn clone (& self) -> D3DCONTENTPROTECTIONCAPS {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DCONTENTPROTECTIONCAPS {# [inline] fn default () -> D3DCONTENTPROTECTIONCAPS {unsafe {$crate :: _core :: mem :: zeroed ()}}}"); | 1016 | .assert_expand_items(r#"STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct D3DCONTENTPROTECTIONCAPS {Caps : u8 ,}}"#, |
1017 | "# [repr (C)] # [derive (Copy)] # [cfg_attr (target_arch = \"x86\" , repr (packed))] pub struct D3DCONTENTPROTECTIONCAPS {pub Caps : u8 ,} impl Clone for D3DCONTENTPROTECTIONCAPS {# [inline] fn clone (& self) -> D3DCONTENTPROTECTIONCAPS {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DCONTENTPROTECTIONCAPS {# [inline] fn default () -> D3DCONTENTPROTECTIONCAPS {unsafe {$crate :: _core :: mem :: zeroed ()}}}" | ||
1018 | ); | ||
1058 | } | 1019 | } |
1059 | 1020 | ||
1060 | #[test] | 1021 | #[test] |
1061 | fn test_int_base() { | 1022 | fn test_int_base() { |
1062 | let rules = create_rules( | 1023 | parse_macro( |
1063 | r#" | 1024 | r#" |
1064 | macro_rules! int_base { | 1025 | macro_rules! int_base { |
1065 | ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => { | 1026 | ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => { |
@@ -1072,17 +1033,15 @@ macro_rules! int_base { | |||
1072 | } | 1033 | } |
1073 | } | 1034 | } |
1074 | "#, | 1035 | "#, |
1075 | ); | 1036 | ).assert_expand_items(r#" int_base!{Binary for isize as usize -> Binary}"#, |
1076 | |||
1077 | assert_expansion(MacroKind::Items, &rules, r#" int_base!{Binary for isize as usize -> Binary}"#, | ||
1078 | "# [stable (feature = \"rust1\" , since = \"1.0.0\")] impl fmt ::Binary for isize {fn fmt (& self , f : & mut fmt :: Formatter < \'_ >) -> fmt :: Result {Binary . fmt_int (* self as usize , f)}}" | 1037 | "# [stable (feature = \"rust1\" , since = \"1.0.0\")] impl fmt ::Binary for isize {fn fmt (& self , f : & mut fmt :: Formatter < \'_ >) -> fmt :: Result {Binary . fmt_int (* self as usize , f)}}" |
1079 | ); | 1038 | ); |
1080 | } | 1039 | } |
1081 | 1040 | ||
1082 | #[test] | 1041 | #[test] |
1083 | fn test_generate_pattern_iterators() { | 1042 | fn test_generate_pattern_iterators() { |
1084 | // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/str/mod.rs | 1043 | // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/str/mod.rs |
1085 | let rules = create_rules( | 1044 | parse_macro( |
1086 | r#" | 1045 | r#" |
1087 | macro_rules! generate_pattern_iterators { | 1046 | macro_rules! generate_pattern_iterators { |
1088 | { double ended; with $(#[$common_stability_attribute:meta])*, | 1047 | { double ended; with $(#[$common_stability_attribute:meta])*, |
@@ -1093,11 +1052,7 @@ macro_rules! generate_pattern_iterators { | |||
1093 | } | 1052 | } |
1094 | } | 1053 | } |
1095 | "#, | 1054 | "#, |
1096 | ); | 1055 | ).assert_expand_items( |
1097 | |||
1098 | assert_expansion( | ||
1099 | MacroKind::Items, | ||
1100 | &rules, | ||
1101 | r#"generate_pattern_iterators ! ( double ended ; with # [ stable ( feature = "rust1" , since = "1.0.0" ) ] , Split , RSplit , & 'a str );"#, | 1056 | r#"generate_pattern_iterators ! ( double ended ; with # [ stable ( feature = "rust1" , since = "1.0.0" ) ] , Split , RSplit , & 'a str );"#, |
1102 | "fn foo () {}", | 1057 | "fn foo () {}", |
1103 | ); | 1058 | ); |
@@ -1106,7 +1061,7 @@ macro_rules! generate_pattern_iterators { | |||
1106 | #[test] | 1061 | #[test] |
1107 | fn test_impl_fn_for_zst() { | 1062 | fn test_impl_fn_for_zst() { |
1108 | // from https://github.com/rust-lang/rust/blob/5d20ff4d2718c820632b38c1e49d4de648a9810b/src/libcore/internal_macros.rs | 1063 | // from https://github.com/rust-lang/rust/blob/5d20ff4d2718c820632b38c1e49d4de648a9810b/src/libcore/internal_macros.rs |
1109 | let rules = create_rules( | 1064 | parse_macro( |
1110 | r#" | 1065 | r#" |
1111 | macro_rules! impl_fn_for_zst { | 1066 | macro_rules! impl_fn_for_zst { |
1112 | { $( $( #[$attr: meta] )* | 1067 | { $( $( #[$attr: meta] )* |
@@ -1147,9 +1102,7 @@ $body: block; )+ | |||
1147 | } | 1102 | } |
1148 | } | 1103 | } |
1149 | "#, | 1104 | "#, |
1150 | ); | 1105 | ).assert_expand_items(r#" |
1151 | |||
1152 | assert_expansion(MacroKind::Items, &rules, r#" | ||
1153 | impl_fn_for_zst ! { | 1106 | impl_fn_for_zst ! { |
1154 | # [ derive ( Clone ) ] | 1107 | # [ derive ( Clone ) ] |
1155 | struct CharEscapeDebugContinue impl Fn = | c : char | -> char :: EscapeDebug { | 1108 | struct CharEscapeDebugContinue impl Fn = | c : char | -> char :: EscapeDebug { |
@@ -1166,13 +1119,14 @@ impl_fn_for_zst ! { | |||
1166 | } ; | 1119 | } ; |
1167 | } | 1120 | } |
1168 | "#, | 1121 | "#, |
1169 | "# [derive (Clone)] struct CharEscapeDebugContinue ; impl Fn < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDebug {{c . escape_debug_ext (false)}}} impl FnMut < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDebugContinue {type Output = char :: EscapeDebug ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeUnicode ; impl Fn < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeUnicode {{c . escape_unicode ()}}} impl FnMut < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeUnicode {type Output = char :: EscapeUnicode ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeDefault ; impl Fn < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDefault {{c . escape_default ()}}} impl FnMut < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDefault {type Output = char :: EscapeDefault ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (& self , (c ,))}}"); | 1122 | "# [derive (Clone)] struct CharEscapeDebugContinue ; impl Fn < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDebug {{c . escape_debug_ext (false)}}} impl FnMut < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDebugContinue {type Output = char :: EscapeDebug ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeUnicode ; impl Fn < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeUnicode {{c . escape_unicode ()}}} impl FnMut < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeUnicode {type Output = char :: EscapeUnicode ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeDefault ; impl Fn < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDefault {{c . escape_default ()}}} impl FnMut < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDefault {type Output = char :: EscapeDefault ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (& self , (c ,))}}" |
1123 | ); | ||
1170 | } | 1124 | } |
1171 | 1125 | ||
1172 | #[test] | 1126 | #[test] |
1173 | fn test_impl_nonzero_fmt() { | 1127 | fn test_impl_nonzero_fmt() { |
1174 | // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/num/mod.rs#L12 | 1128 | // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/num/mod.rs#L12 |
1175 | let rules = create_rules( | 1129 | parse_macro( |
1176 | r#" | 1130 | r#" |
1177 | macro_rules! impl_nonzero_fmt { | 1131 | macro_rules! impl_nonzero_fmt { |
1178 | ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { | 1132 | ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { |
@@ -1180,11 +1134,7 @@ fn test_impl_nonzero_fmt() { | |||
1180 | } | 1134 | } |
1181 | } | 1135 | } |
1182 | "#, | 1136 | "#, |
1183 | ); | 1137 | ).assert_expand_items( |
1184 | |||
1185 | assert_expansion( | ||
1186 | MacroKind::Items, | ||
1187 | &rules, | ||
1188 | r#"impl_nonzero_fmt! { # [stable(feature= "nonzero",since="1.28.0")] (Debug,Display,Binary,Octal,LowerHex,UpperHex) for NonZeroU8}"#, | 1138 | r#"impl_nonzero_fmt! { # [stable(feature= "nonzero",since="1.28.0")] (Debug,Display,Binary,Octal,LowerHex,UpperHex) for NonZeroU8}"#, |
1189 | "fn foo () {}", | 1139 | "fn foo () {}", |
1190 | ); | 1140 | ); |
@@ -1193,7 +1143,7 @@ fn test_impl_nonzero_fmt() { | |||
1193 | #[test] | 1143 | #[test] |
1194 | fn test_cfg_if_items() { | 1144 | fn test_cfg_if_items() { |
1195 | // from https://github.com/rust-lang/rust/blob/33fe1131cadba69d317156847be9a402b89f11bb/src/libstd/macros.rs#L986 | 1145 | // from https://github.com/rust-lang/rust/blob/33fe1131cadba69d317156847be9a402b89f11bb/src/libstd/macros.rs#L986 |
1196 | let rules = create_rules( | 1146 | parse_macro( |
1197 | r#" | 1147 | r#" |
1198 | macro_rules! __cfg_if_items { | 1148 | macro_rules! __cfg_if_items { |
1199 | (($($not:meta,)*) ; ) => {}; | 1149 | (($($not:meta,)*) ; ) => {}; |
@@ -1202,11 +1152,7 @@ fn test_cfg_if_items() { | |||
1202 | } | 1152 | } |
1203 | } | 1153 | } |
1204 | "#, | 1154 | "#, |
1205 | ); | 1155 | ).assert_expand_items( |
1206 | |||
1207 | assert_expansion( | ||
1208 | MacroKind::Items, | ||
1209 | &rules, | ||
1210 | r#"__cfg_if_items ! { ( rustdoc , ) ; ( ( ) ( # [ cfg ( any ( target_os = "redox" , unix ) ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as unix ; # [ cfg ( windows ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as windows ; # [ cfg ( any ( target_os = "linux" , target_os = "l4re" ) ) ] pub mod linux ; ) ) , }"#, | 1156 | r#"__cfg_if_items ! { ( rustdoc , ) ; ( ( ) ( # [ cfg ( any ( target_os = "redox" , unix ) ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as unix ; # [ cfg ( windows ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as windows ; # [ cfg ( any ( target_os = "linux" , target_os = "l4re" ) ) ] pub mod linux ; ) ) , }"#, |
1211 | "__cfg_if_items ! {(rustdoc ,) ;}", | 1157 | "__cfg_if_items ! {(rustdoc ,) ;}", |
1212 | ); | 1158 | ); |
@@ -1215,7 +1161,7 @@ fn test_cfg_if_items() { | |||
1215 | #[test] | 1161 | #[test] |
1216 | fn test_cfg_if_main() { | 1162 | fn test_cfg_if_main() { |
1217 | // from https://github.com/rust-lang/rust/blob/3d211248393686e0f73851fc7548f6605220fbe1/src/libpanic_unwind/macros.rs#L9 | 1163 | // from https://github.com/rust-lang/rust/blob/3d211248393686e0f73851fc7548f6605220fbe1/src/libpanic_unwind/macros.rs#L9 |
1218 | let rules = create_rules( | 1164 | parse_macro( |
1219 | r#" | 1165 | r#" |
1220 | macro_rules! cfg_if { | 1166 | macro_rules! cfg_if { |
1221 | ($( | 1167 | ($( |
@@ -1236,9 +1182,7 @@ fn test_cfg_if_main() { | |||
1236 | }; | 1182 | }; |
1237 | } | 1183 | } |
1238 | "#, | 1184 | "#, |
1239 | ); | 1185 | ).assert_expand_items(r#" |
1240 | |||
1241 | assert_expansion(MacroKind::Items, &rules, r#" | ||
1242 | cfg_if ! { | 1186 | cfg_if ! { |
1243 | if # [ cfg ( target_env = "msvc" ) ] { | 1187 | if # [ cfg ( target_env = "msvc" ) ] { |
1244 | // no extra unwinder support needed | 1188 | // no extra unwinder support needed |
@@ -1250,11 +1194,8 @@ cfg_if ! { | |||
1250 | } | 1194 | } |
1251 | } | 1195 | } |
1252 | "#, | 1196 | "#, |
1253 | "__cfg_if_items ! {() ; ((target_env = \"msvc\") ()) , ((all (target_arch = \"wasm32\" , not (target_os = \"emscripten\"))) ()) , (() (mod libunwind ; pub use libunwind :: * ;)) ,}"); | 1197 | "__cfg_if_items ! {() ; ((target_env = \"msvc\") ()) , ((all (target_arch = \"wasm32\" , not (target_os = \"emscripten\"))) ()) , (() (mod libunwind ; pub use libunwind :: * ;)) ,}" |
1254 | 1198 | ).assert_expand_items( | |
1255 | assert_expansion( | ||
1256 | MacroKind::Items, | ||
1257 | &rules, | ||
1258 | r#" | 1199 | r#" |
1259 | cfg_if ! { @ __apply cfg ( all ( not ( any ( not ( any ( target_os = "solaris" , target_os = "illumos" ) ) ) ) ) ) , } | 1200 | cfg_if ! { @ __apply cfg ( all ( not ( any ( not ( any ( target_os = "solaris" , target_os = "illumos" ) ) ) ) ) ) , } |
1260 | "#, | 1201 | "#, |
@@ -1265,7 +1206,7 @@ cfg_if ! { @ __apply cfg ( all ( not ( any ( not ( any ( target_os = "solaris" , | |||
1265 | #[test] | 1206 | #[test] |
1266 | fn test_proptest_arbitrary() { | 1207 | fn test_proptest_arbitrary() { |
1267 | // from https://github.com/AltSysrq/proptest/blob/d1c4b049337d2f75dd6f49a095115f7c532e5129/proptest/src/arbitrary/macros.rs#L16 | 1208 | // from https://github.com/AltSysrq/proptest/blob/d1c4b049337d2f75dd6f49a095115f7c532e5129/proptest/src/arbitrary/macros.rs#L16 |
1268 | let rules = create_rules( | 1209 | parse_macro( |
1269 | r#" | 1210 | r#" |
1270 | macro_rules! arbitrary { | 1211 | macro_rules! arbitrary { |
1271 | ([$($bounds : tt)*] $typ: ty, $strat: ty, $params: ty; | 1212 | ([$($bounds : tt)*] $typ: ty, $strat: ty, $params: ty; |
@@ -1280,22 +1221,21 @@ macro_rules! arbitrary { | |||
1280 | }; | 1221 | }; |
1281 | 1222 | ||
1282 | }"#, | 1223 | }"#, |
1283 | ); | 1224 | ).assert_expand_items(r#"arbitrary ! ( [ A : Arbitrary ] |
1284 | |||
1285 | assert_expansion(MacroKind::Items, &rules, r#"arbitrary ! ( [ A : Arbitrary ] | ||
1286 | Vec < A > , | 1225 | Vec < A > , |
1287 | VecStrategy < A :: Strategy > , | 1226 | VecStrategy < A :: Strategy > , |
1288 | RangedParams1 < A :: Parameters > ; | 1227 | RangedParams1 < A :: Parameters > ; |
1289 | args => { let product_unpack ! [ range , a ] = args ; vec ( any_with :: < A > ( a ) , range ) } | 1228 | args => { let product_unpack ! [ range , a ] = args ; vec ( any_with :: < A > ( a ) , range ) } |
1290 | ) ;"#, | 1229 | ) ;"#, |
1291 | "impl <A : Arbitrary > $crate :: arbitrary :: Arbitrary for Vec < A > {type Parameters = RangedParams1 < A :: Parameters > ; type Strategy = VecStrategy < A :: Strategy > ; fn arbitrary_with (args : Self :: Parameters) -> Self :: Strategy {{let product_unpack ! [range , a] = args ; vec (any_with :: < A > (a) , range)}}}"); | 1230 | "impl <A : Arbitrary > $crate :: arbitrary :: Arbitrary for Vec < A > {type Parameters = RangedParams1 < A :: Parameters > ; type Strategy = VecStrategy < A :: Strategy > ; fn arbitrary_with (args : Self :: Parameters) -> Self :: Strategy {{let product_unpack ! [range , a] = args ; vec (any_with :: < A > (a) , range)}}}" |
1231 | ); | ||
1292 | } | 1232 | } |
1293 | 1233 | ||
1294 | #[test] | 1234 | #[test] |
1295 | fn test_old_ridl() { | 1235 | fn test_old_ridl() { |
1296 | // This is from winapi 2.8, which do not have a link from github | 1236 | // This is from winapi 2.8, which do not have a link from github |
1297 | // | 1237 | // |
1298 | let rules = create_rules( | 1238 | let expanded = parse_macro( |
1299 | r#" | 1239 | r#" |
1300 | #[macro_export] | 1240 | #[macro_export] |
1301 | macro_rules! RIDL { | 1241 | macro_rules! RIDL { |
@@ -1311,21 +1251,17 @@ macro_rules! RIDL { | |||
1311 | } | 1251 | } |
1312 | }; | 1252 | }; |
1313 | }"#, | 1253 | }"#, |
1314 | ); | 1254 | ).expand_tt(r#" |
1255 | RIDL!{interface ID3D11Asynchronous(ID3D11AsynchronousVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) { | ||
1256 | fn GetDataSize(&mut self) -> UINT | ||
1257 | }}"#); | ||
1315 | 1258 | ||
1316 | let expanded = expand( | ||
1317 | &rules, | ||
1318 | r#" | ||
1319 | RIDL!{interface ID3D11Asynchronous(ID3D11AsynchronousVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) { | ||
1320 | fn GetDataSize(&mut self) -> UINT | ||
1321 | }}"#, | ||
1322 | ); | ||
1323 | assert_eq!(expanded.to_string(), "impl ID3D11Asynchronous {pub unsafe fn GetDataSize (& mut self) -> UINT {((* self . lpVtbl) .GetDataSize) (self)}}"); | 1259 | assert_eq!(expanded.to_string(), "impl ID3D11Asynchronous {pub unsafe fn GetDataSize (& mut self) -> UINT {((* self . lpVtbl) .GetDataSize) (self)}}"); |
1324 | } | 1260 | } |
1325 | 1261 | ||
1326 | #[test] | 1262 | #[test] |
1327 | fn test_quick_error() { | 1263 | fn test_quick_error() { |
1328 | let rules = create_rules( | 1264 | let expanded = parse_macro( |
1329 | r#" | 1265 | r#" |
1330 | macro_rules! quick_error { | 1266 | macro_rules! quick_error { |
1331 | 1267 | ||
@@ -1348,10 +1284,8 @@ macro_rules! quick_error { | |||
1348 | 1284 | ||
1349 | } | 1285 | } |
1350 | "#, | 1286 | "#, |
1351 | ); | 1287 | ) |
1352 | 1288 | .expand_tt( | |
1353 | let expanded = expand( | ||
1354 | &rules, | ||
1355 | r#" | 1289 | r#" |
1356 | quick_error ! (SORT [enum Wrapped # [derive (Debug)]] items [ | 1290 | quick_error ! (SORT [enum Wrapped # [derive (Debug)]] items [ |
1357 | => One : UNIT [] {} | 1291 | => One : UNIT [] {} |
@@ -1365,7 +1299,7 @@ quick_error ! (SORT [enum Wrapped # [derive (Debug)]] items [ | |||
1365 | 1299 | ||
1366 | #[test] | 1300 | #[test] |
1367 | fn test_empty_repeat_vars_in_empty_repeat_vars() { | 1301 | fn test_empty_repeat_vars_in_empty_repeat_vars() { |
1368 | let rules = create_rules( | 1302 | parse_macro( |
1369 | r#" | 1303 | r#" |
1370 | macro_rules! delegate_impl { | 1304 | macro_rules! delegate_impl { |
1371 | ([$self_type:ident, $self_wrap:ty, $self_map:ident] | 1305 | ([$self_type:ident, $self_wrap:ty, $self_map:ident] |
@@ -1412,103 +1346,117 @@ macro_rules! delegate_impl { | |||
1412 | } | 1346 | } |
1413 | } | 1347 | } |
1414 | "#, | 1348 | "#, |
1415 | ); | 1349 | ).assert_expand_items( |
1416 | |||
1417 | assert_expansion( | ||
1418 | MacroKind::Items, | ||
1419 | &rules, | ||
1420 | r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#, | 1350 | r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#, |
1421 | "impl <> Data for & \'a mut G where G : Data {}", | 1351 | "impl <> Data for & \'a mut G where G : Data {}", |
1422 | ); | 1352 | ); |
1423 | } | 1353 | } |
1424 | 1354 | ||
1425 | pub(crate) fn create_rules(macro_definition: &str) -> MacroRules { | 1355 | #[test] |
1426 | let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap(); | 1356 | fn expr_interpolation() { |
1427 | let macro_definition = | 1357 | let expanded = parse_macro( |
1428 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | 1358 | r#" |
1359 | macro_rules! id { | ||
1360 | ($expr:expr) => { | ||
1361 | map($expr) | ||
1362 | } | ||
1363 | } | ||
1364 | "#, | ||
1365 | ) | ||
1366 | .expand_expr("id!(x + foo);"); | ||
1429 | 1367 | ||
1430 | let (definition_tt, _) = ast_to_token_tree(¯o_definition.token_tree().unwrap()).unwrap(); | 1368 | assert_eq!(expanded.to_string(), "map(x+foo)"); |
1431 | crate::MacroRules::parse(&definition_tt).unwrap() | ||
1432 | } | 1369 | } |
1433 | 1370 | ||
1434 | pub(crate) fn expand(rules: &MacroRules, invocation: &str) -> tt::Subtree { | 1371 | pub(crate) struct MacroFixture { |
1435 | let source_file = ast::SourceFile::parse(invocation).ok().unwrap(); | 1372 | rules: MacroRules, |
1436 | let macro_invocation = | 1373 | } |
1437 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | ||
1438 | 1374 | ||
1439 | let (invocation_tt, _) = ast_to_token_tree(¯o_invocation.token_tree().unwrap()).unwrap(); | 1375 | impl MacroFixture { |
1376 | pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree { | ||
1377 | let source_file = ast::SourceFile::parse(invocation).ok().unwrap(); | ||
1378 | let macro_invocation = | ||
1379 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | ||
1440 | 1380 | ||
1441 | rules.expand(&invocation_tt).unwrap() | 1381 | let (invocation_tt, _) = |
1442 | } | 1382 | ast_to_token_tree(¯o_invocation.token_tree().unwrap()).unwrap(); |
1443 | 1383 | ||
1444 | pub(crate) enum MacroKind { | 1384 | self.rules.expand(&invocation_tt).unwrap() |
1445 | Items, | 1385 | } |
1446 | Stmts, | ||
1447 | } | ||
1448 | 1386 | ||
1449 | pub(crate) fn assert_expansion( | 1387 | fn expand_items(&self, invocation: &str) -> SyntaxNode { |
1450 | kind: MacroKind, | 1388 | let expanded = self.expand_tt(invocation); |
1451 | rules: &MacroRules, | 1389 | token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap().0.syntax_node() |
1452 | invocation: &str, | 1390 | } |
1453 | expected: &str, | ||
1454 | ) -> tt::Subtree { | ||
1455 | let expanded = expand(rules, invocation); | ||
1456 | assert_eq!(expanded.to_string(), expected); | ||
1457 | 1391 | ||
1458 | let expected = expected.replace("$crate", "C_C__C"); | 1392 | fn expand_statements(&self, invocation: &str) -> SyntaxNode { |
1393 | let expanded = self.expand_tt(invocation); | ||
1394 | token_tree_to_syntax_node(&expanded, FragmentKind::Statements).unwrap().0.syntax_node() | ||
1395 | } | ||
1459 | 1396 | ||
1460 | // wrap the given text to a macro call | 1397 | fn expand_expr(&self, invocation: &str) -> SyntaxNode { |
1461 | let expected = { | 1398 | let expanded = self.expand_tt(invocation); |
1462 | let wrapped = format!("wrap_macro!( {} )", expected); | 1399 | token_tree_to_syntax_node(&expanded, FragmentKind::Expr).unwrap().0.syntax_node() |
1463 | let wrapped = ast::SourceFile::parse(&wrapped); | 1400 | } |
1464 | let wrapped = wrapped.tree().syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | ||
1465 | let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0; | ||
1466 | wrapped.delimiter = tt::Delimiter::None; | ||
1467 | wrapped | ||
1468 | }; | ||
1469 | let (expanded_tree, expected_tree) = match kind { | ||
1470 | MacroKind::Items => { | ||
1471 | let expanded_tree = | ||
1472 | token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap().0.syntax_node(); | ||
1473 | let expected_tree = | ||
1474 | token_tree_to_syntax_node(&expected, FragmentKind::Items).unwrap().0.syntax_node(); | ||
1475 | |||
1476 | ( | ||
1477 | debug_dump_ignore_spaces(&expanded_tree).trim().to_string(), | ||
1478 | debug_dump_ignore_spaces(&expected_tree).trim().to_string(), | ||
1479 | ) | ||
1480 | } | ||
1481 | 1401 | ||
1482 | MacroKind::Stmts => { | 1402 | fn assert_expand_tt(&self, invocation: &str, expected: &str) { |
1483 | let expanded_tree = token_tree_to_syntax_node(&expanded, FragmentKind::Statements) | 1403 | let expansion = self.expand_tt(invocation); |
1484 | .unwrap() | 1404 | assert_eq!(expansion.to_string(), expected); |
1485 | .0 | 1405 | } |
1486 | .syntax_node(); | ||
1487 | let expected_tree = token_tree_to_syntax_node(&expected, FragmentKind::Statements) | ||
1488 | .unwrap() | ||
1489 | .0 | ||
1490 | .syntax_node(); | ||
1491 | |||
1492 | ( | ||
1493 | debug_dump_ignore_spaces(&expanded_tree).trim().to_string(), | ||
1494 | debug_dump_ignore_spaces(&expected_tree).trim().to_string(), | ||
1495 | ) | ||
1496 | } | ||
1497 | }; | ||
1498 | 1406 | ||
1499 | let expected_tree = expected_tree.replace("C_C__C", "$crate"); | 1407 | fn assert_expand_items(&self, invocation: &str, expected: &str) -> &MacroFixture { |
1500 | assert_eq!( | 1408 | self.assert_expansion(FragmentKind::Items, invocation, expected); |
1501 | expanded_tree, expected_tree, | 1409 | self |
1502 | "\nleft:\n{}\nright:\n{}", | 1410 | } |
1503 | expanded_tree, expected_tree, | 1411 | |
1504 | ); | 1412 | fn assert_expand_statements(&self, invocation: &str, expected: &str) -> &MacroFixture { |
1413 | self.assert_expansion(FragmentKind::Statements, invocation, expected); | ||
1414 | self | ||
1415 | } | ||
1505 | 1416 | ||
1506 | expanded | 1417 | fn assert_expansion(&self, kind: FragmentKind, invocation: &str, expected: &str) { |
1418 | let expanded = self.expand_tt(invocation); | ||
1419 | assert_eq!(expanded.to_string(), expected); | ||
1420 | |||
1421 | let expected = expected.replace("$crate", "C_C__C"); | ||
1422 | |||
1423 | // wrap the given text to a macro call | ||
1424 | let expected = { | ||
1425 | let wrapped = format!("wrap_macro!( {} )", expected); | ||
1426 | let wrapped = ast::SourceFile::parse(&wrapped); | ||
1427 | let wrapped = | ||
1428 | wrapped.tree().syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | ||
1429 | let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0; | ||
1430 | wrapped.delimiter = None; | ||
1431 | wrapped | ||
1432 | }; | ||
1433 | |||
1434 | let expanded_tree = token_tree_to_syntax_node(&expanded, kind).unwrap().0.syntax_node(); | ||
1435 | let expanded_tree = debug_dump_ignore_spaces(&expanded_tree).trim().to_string(); | ||
1436 | |||
1437 | let expected_tree = token_tree_to_syntax_node(&expected, kind).unwrap().0.syntax_node(); | ||
1438 | let expected_tree = debug_dump_ignore_spaces(&expected_tree).trim().to_string(); | ||
1439 | |||
1440 | let expected_tree = expected_tree.replace("C_C__C", "$crate"); | ||
1441 | assert_eq!( | ||
1442 | expanded_tree, expected_tree, | ||
1443 | "\nleft:\n{}\nright:\n{}", | ||
1444 | expanded_tree, expected_tree, | ||
1445 | ); | ||
1446 | } | ||
1507 | } | 1447 | } |
1508 | 1448 | ||
1509 | pub fn debug_dump_ignore_spaces(node: &ra_syntax::SyntaxNode) -> String { | 1449 | pub(crate) fn parse_macro(macro_definition: &str) -> MacroFixture { |
1510 | use std::fmt::Write; | 1450 | let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap(); |
1451 | let macro_definition = | ||
1452 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | ||
1453 | |||
1454 | let (definition_tt, _) = ast_to_token_tree(¯o_definition.token_tree().unwrap()).unwrap(); | ||
1455 | let rules = MacroRules::parse(&definition_tt).unwrap(); | ||
1456 | MacroFixture { rules } | ||
1457 | } | ||
1511 | 1458 | ||
1459 | fn debug_dump_ignore_spaces(node: &ra_syntax::SyntaxNode) -> String { | ||
1512 | let mut level = 0; | 1460 | let mut level = 0; |
1513 | let mut buf = String::new(); | 1461 | let mut buf = String::new(); |
1514 | macro_rules! indent { | 1462 | macro_rules! indent { |