diff options
Diffstat (limited to 'crates/ra_mbe/src')
-rw-r--r-- | crates/ra_mbe/src/mbe_expander/matcher.rs | 40 | ||||
-rw-r--r-- | crates/ra_mbe/src/subtree_source.rs | 47 | ||||
-rw-r--r-- | crates/ra_mbe/src/syntax_bridge.rs | 39 | ||||
-rw-r--r-- | crates/ra_mbe/src/tests.rs | 57 | ||||
-rw-r--r-- | crates/ra_mbe/src/tt_iter.rs | 8 |
5 files changed, 163 insertions, 28 deletions
diff --git a/crates/ra_mbe/src/mbe_expander/matcher.rs b/crates/ra_mbe/src/mbe_expander/matcher.rs index 2579382da..78f9efa1b 100644 --- a/crates/ra_mbe/src/mbe_expander/matcher.rs +++ b/crates/ra_mbe/src/mbe_expander/matcher.rs | |||
@@ -187,7 +187,11 @@ impl<'a> TtIter<'a> { | |||
187 | _ => false, | 187 | _ => false, |
188 | }, | 188 | }, |
189 | Separator::Literal(lhs) => match fork.expect_literal() { | 189 | Separator::Literal(lhs) => match fork.expect_literal() { |
190 | Ok(rhs) => rhs.text == lhs.text, | 190 | Ok(rhs) => match rhs { |
191 | tt::Leaf::Literal(rhs) => rhs.text == lhs.text, | ||
192 | tt::Leaf::Ident(rhs) => rhs.text == lhs.text, | ||
193 | tt::Leaf::Punct(_) => false, | ||
194 | }, | ||
191 | _ => false, | 195 | _ => false, |
192 | }, | 196 | }, |
193 | Separator::Puncts(lhss) => lhss.iter().all(|lhs| match fork.expect_punct() { | 197 | Separator::Puncts(lhss) => lhss.iter().all(|lhs| match fork.expect_punct() { |
@@ -202,6 +206,13 @@ impl<'a> TtIter<'a> { | |||
202 | } | 206 | } |
203 | 207 | ||
204 | pub(crate) fn expect_tt(&mut self) -> Result<tt::TokenTree, ()> { | 208 | pub(crate) fn expect_tt(&mut self) -> Result<tt::TokenTree, ()> { |
209 | match self.peek_n(0) { | ||
210 | Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) if punct.char == '\'' => { | ||
211 | return self.expect_lifetime(); | ||
212 | } | ||
213 | _ => (), | ||
214 | } | ||
215 | |||
205 | let tt = self.next().ok_or_else(|| ())?.clone(); | 216 | let tt = self.next().ok_or_else(|| ())?.clone(); |
206 | let punct = match tt { | 217 | let punct = match tt { |
207 | tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if punct.spacing == tt::Spacing::Joint => { | 218 | tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if punct.spacing == tt::Spacing::Joint => { |
@@ -255,13 +266,21 @@ impl<'a> TtIter<'a> { | |||
255 | } | 266 | } |
256 | } | 267 | } |
257 | 268 | ||
258 | pub(crate) fn expect_lifetime(&mut self) -> Result<&tt::Ident, ()> { | 269 | pub(crate) fn expect_lifetime(&mut self) -> Result<tt::TokenTree, ()> { |
259 | let ident = self.expect_ident()?; | 270 | let punct = self.expect_punct()?; |
260 | // check if it start from "`" | 271 | if punct.char != '\'' { |
261 | if !ident.text.starts_with('\'') { | ||
262 | return Err(()); | 272 | return Err(()); |
263 | } | 273 | } |
264 | Ok(ident) | 274 | let ident = self.expect_ident()?; |
275 | |||
276 | Ok(tt::Subtree { | ||
277 | delimiter: None, | ||
278 | token_trees: vec![ | ||
279 | tt::Leaf::Punct(punct.clone()).into(), | ||
280 | tt::Leaf::Ident(ident.clone()).into(), | ||
281 | ], | ||
282 | } | ||
283 | .into()) | ||
265 | } | 284 | } |
266 | 285 | ||
267 | pub(crate) fn expect_fragment( | 286 | pub(crate) fn expect_fragment( |
@@ -274,7 +293,10 @@ impl<'a> TtIter<'a> { | |||
274 | } | 293 | } |
275 | 294 | ||
276 | impl<'a> TreeSink for OffsetTokenSink<'a> { | 295 | impl<'a> TreeSink for OffsetTokenSink<'a> { |
277 | fn token(&mut self, _kind: SyntaxKind, n_tokens: u8) { | 296 | fn token(&mut self, kind: SyntaxKind, mut n_tokens: u8) { |
297 | if kind == SyntaxKind::LIFETIME { | ||
298 | n_tokens = 2; | ||
299 | } | ||
278 | for _ in 0..n_tokens { | 300 | for _ in 0..n_tokens { |
279 | self.cursor = self.cursor.bump_subtree(); | 301 | self.cursor = self.cursor.bump_subtree(); |
280 | } | 302 | } |
@@ -286,7 +308,7 @@ impl<'a> TtIter<'a> { | |||
286 | } | 308 | } |
287 | } | 309 | } |
288 | 310 | ||
289 | let buffer = TokenBuffer::new(self.inner.as_slice()); | 311 | let buffer = TokenBuffer::new(&self.inner.as_slice()); |
290 | let mut src = SubtreeTokenSource::new(&buffer); | 312 | let mut src = SubtreeTokenSource::new(&buffer); |
291 | let mut sink = OffsetTokenSink { cursor: buffer.begin(), error: false }; | 313 | let mut sink = OffsetTokenSink { cursor: buffer.begin(), error: false }; |
292 | 314 | ||
@@ -422,7 +444,7 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragmen | |||
422 | "tt" => input.expect_tt().map(Some).map_err(|()| err!()), | 444 | "tt" => input.expect_tt().map(Some).map_err(|()| err!()), |
423 | "lifetime" => input | 445 | "lifetime" => input |
424 | .expect_lifetime() | 446 | .expect_lifetime() |
425 | .map(|ident| Some(tt::Leaf::Ident(ident.clone()).into())) | 447 | .map(|tt| Some(tt)) |
426 | .map_err(|()| err!("expected lifetime")), | 448 | .map_err(|()| err!("expected lifetime")), |
427 | "literal" => input | 449 | "literal" => input |
428 | .expect_literal() | 450 | .expect_literal() |
diff --git a/crates/ra_mbe/src/subtree_source.rs b/crates/ra_mbe/src/subtree_source.rs index 91e324db9..d7866452d 100644 --- a/crates/ra_mbe/src/subtree_source.rs +++ b/crates/ra_mbe/src/subtree_source.rs | |||
@@ -50,6 +50,26 @@ impl<'a> SubtreeTokenSource<'a> { | |||
50 | } | 50 | } |
51 | 51 | ||
52 | fn get(&self, pos: usize) -> Ref<Option<TtToken>> { | 52 | fn get(&self, pos: usize) -> Ref<Option<TtToken>> { |
53 | fn is_lifetime(c: Cursor) -> Option<(Cursor, SmolStr)> { | ||
54 | let tkn = c.token_tree(); | ||
55 | |||
56 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = tkn { | ||
57 | if punct.char == '\'' { | ||
58 | let next = c.bump(); | ||
59 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) = next.token_tree() { | ||
60 | let res_cursor = next.bump(); | ||
61 | let text = SmolStr::new("'".to_string() + &ident.to_string()); | ||
62 | |||
63 | return Some((res_cursor, text)); | ||
64 | } else { | ||
65 | panic!("Next token must be ident : {:#?}", next.token_tree()); | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | |||
70 | None | ||
71 | } | ||
72 | |||
53 | if pos < self.cached.borrow().len() { | 73 | if pos < self.cached.borrow().len() { |
54 | return Ref::map(self.cached.borrow(), |c| &c[pos]); | 74 | return Ref::map(self.cached.borrow(), |c| &c[pos]); |
55 | } | 75 | } |
@@ -63,6 +83,12 @@ impl<'a> SubtreeTokenSource<'a> { | |||
63 | continue; | 83 | continue; |
64 | } | 84 | } |
65 | 85 | ||
86 | if let Some((curr, text)) = is_lifetime(cursor) { | ||
87 | cached.push(Some(TtToken { kind: LIFETIME, is_joint_to_next: false, text })); | ||
88 | self.cached_cursor.set(curr); | ||
89 | continue; | ||
90 | } | ||
91 | |||
66 | match cursor.token_tree() { | 92 | match cursor.token_tree() { |
67 | Some(tt::TokenTree::Leaf(leaf)) => { | 93 | Some(tt::TokenTree::Leaf(leaf)) => { |
68 | cached.push(Some(convert_leaf(&leaf))); | 94 | cached.push(Some(convert_leaf(&leaf))); |
@@ -132,27 +158,28 @@ fn convert_literal(l: &tt::Literal) -> TtToken { | |||
132 | let kind = lex_single_syntax_kind(&l.text) | 158 | let kind = lex_single_syntax_kind(&l.text) |
133 | .map(|(kind, _error)| kind) | 159 | .map(|(kind, _error)| kind) |
134 | .filter(|kind| kind.is_literal()) | 160 | .filter(|kind| kind.is_literal()) |
135 | .unwrap_or_else(|| match l.text.as_ref() { | 161 | .unwrap_or_else(|| panic!("Fail to convert given literal {:#?}", &l)); |
136 | "true" => T![true], | ||
137 | "false" => T![false], | ||
138 | _ => panic!("Fail to convert given literal {:#?}", &l), | ||
139 | }); | ||
140 | 162 | ||
141 | TtToken { kind, is_joint_to_next: false, text: l.text.clone() } | 163 | TtToken { kind, is_joint_to_next: false, text: l.text.clone() } |
142 | } | 164 | } |
143 | 165 | ||
144 | fn convert_ident(ident: &tt::Ident) -> TtToken { | 166 | fn convert_ident(ident: &tt::Ident) -> TtToken { |
145 | let kind = if ident.text.starts_with('\'') { | 167 | let kind = match ident.text.as_ref() { |
146 | LIFETIME | 168 | "true" => T![true], |
147 | } else { | 169 | "false" => T![false], |
148 | SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT) | 170 | i if i.starts_with('\'') => LIFETIME, |
171 | _ => SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT), | ||
149 | }; | 172 | }; |
150 | 173 | ||
151 | TtToken { kind, is_joint_to_next: false, text: ident.text.clone() } | 174 | TtToken { kind, is_joint_to_next: false, text: ident.text.clone() } |
152 | } | 175 | } |
153 | 176 | ||
154 | fn convert_punct(p: tt::Punct) -> TtToken { | 177 | fn convert_punct(p: tt::Punct) -> TtToken { |
155 | let kind = SyntaxKind::from_char(p.char).unwrap(); | 178 | let kind = match SyntaxKind::from_char(p.char) { |
179 | None => panic!("{:#?} is not a valid punct", p), | ||
180 | Some(kind) => kind, | ||
181 | }; | ||
182 | |||
156 | let text = { | 183 | let text = { |
157 | let mut buf = [0u8; 4]; | 184 | let mut buf = [0u8; 4]; |
158 | let s: &str = p.char.encode_utf8(&mut buf); | 185 | let s: &str = p.char.encode_utf8(&mut buf); |
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs index 31e9b22e7..2b4390eb2 100644 --- a/crates/ra_mbe/src/syntax_bridge.rs +++ b/crates/ra_mbe/src/syntax_bridge.rs | |||
@@ -271,7 +271,7 @@ struct RawConvertor<'a> { | |||
271 | inner: std::slice::Iter<'a, RawToken>, | 271 | inner: std::slice::Iter<'a, RawToken>, |
272 | } | 272 | } |
273 | 273 | ||
274 | trait SrcToken { | 274 | trait SrcToken: std::fmt::Debug { |
275 | fn kind(&self) -> SyntaxKind; | 275 | fn kind(&self) -> SyntaxKind; |
276 | 276 | ||
277 | fn to_char(&self) -> Option<char>; | 277 | fn to_char(&self) -> Option<char>; |
@@ -361,8 +361,12 @@ trait TokenConvertor { | |||
361 | Some(next) if next.kind().is_punct() => tt::Spacing::Joint, | 361 | Some(next) if next.kind().is_punct() => tt::Spacing::Joint, |
362 | _ => tt::Spacing::Alone, | 362 | _ => tt::Spacing::Alone, |
363 | }; | 363 | }; |
364 | let char = token.to_char().expect("Token from lexer must be single char"); | 364 | let char = match token.to_char() { |
365 | 365 | Some(c) => c, | |
366 | None => { | ||
367 | panic!("Token from lexer must be single char: token = {:#?}", token); | ||
368 | } | ||
369 | }; | ||
366 | tt::Leaf::from(tt::Punct { char, spacing, id: self.id_alloc().alloc(range) }).into() | 370 | tt::Leaf::from(tt::Punct { char, spacing, id: self.id_alloc().alloc(range) }).into() |
367 | } | 371 | } |
368 | } else { | 372 | } else { |
@@ -372,10 +376,29 @@ trait TokenConvertor { | |||
372 | }; | 376 | }; |
373 | } | 377 | } |
374 | let leaf: tt::Leaf = match k { | 378 | let leaf: tt::Leaf = match k { |
375 | T![true] | T![false] => make_leaf!(Literal), | 379 | T![true] | T![false] => make_leaf!(Ident), |
376 | IDENT | LIFETIME => make_leaf!(Ident), | 380 | IDENT => make_leaf!(Ident), |
377 | k if k.is_keyword() => make_leaf!(Ident), | 381 | k if k.is_keyword() => make_leaf!(Ident), |
378 | k if k.is_literal() => make_leaf!(Literal), | 382 | k if k.is_literal() => make_leaf!(Literal), |
383 | LIFETIME => { | ||
384 | let char_unit = TextUnit::from_usize(1); | ||
385 | let r = TextRange::offset_len(range.start(), char_unit); | ||
386 | let apostrophe = tt::Leaf::from(tt::Punct { | ||
387 | char: '\'', | ||
388 | spacing: tt::Spacing::Joint, | ||
389 | id: self.id_alloc().alloc(r), | ||
390 | }); | ||
391 | result.push(apostrophe.into()); | ||
392 | |||
393 | let r = | ||
394 | TextRange::offset_len(range.start() + char_unit, range.len() - char_unit); | ||
395 | let ident = tt::Leaf::from(tt::Ident { | ||
396 | text: SmolStr::new(&token.to_text()[1..]), | ||
397 | id: self.id_alloc().alloc(r), | ||
398 | }); | ||
399 | result.push(ident.into()); | ||
400 | return; | ||
401 | } | ||
379 | _ => return, | 402 | _ => return, |
380 | }; | 403 | }; |
381 | 404 | ||
@@ -455,6 +478,7 @@ impl Convertor { | |||
455 | } | 478 | } |
456 | } | 479 | } |
457 | 480 | ||
481 | #[derive(Debug)] | ||
458 | enum SynToken { | 482 | enum SynToken { |
459 | Ordiniary(SyntaxToken), | 483 | Ordiniary(SyntaxToken), |
460 | Punch(SyntaxToken, TextUnit), | 484 | Punch(SyntaxToken, TextUnit), |
@@ -592,11 +616,14 @@ fn delim_to_str(d: Option<tt::DelimiterKind>, closing: bool) -> SmolStr { | |||
592 | } | 616 | } |
593 | 617 | ||
594 | impl<'a> TreeSink for TtTreeSink<'a> { | 618 | impl<'a> TreeSink for TtTreeSink<'a> { |
595 | fn token(&mut self, kind: SyntaxKind, n_tokens: u8) { | 619 | fn token(&mut self, kind: SyntaxKind, mut n_tokens: u8) { |
596 | if kind == L_DOLLAR || kind == R_DOLLAR { | 620 | if kind == L_DOLLAR || kind == R_DOLLAR { |
597 | self.cursor = self.cursor.bump_subtree(); | 621 | self.cursor = self.cursor.bump_subtree(); |
598 | return; | 622 | return; |
599 | } | 623 | } |
624 | if kind == LIFETIME { | ||
625 | n_tokens = 2; | ||
626 | } | ||
600 | 627 | ||
601 | let mut last = self.cursor; | 628 | let mut last = self.cursor; |
602 | for _ in 0..n_tokens { | 629 | for _ in 0..n_tokens { |
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs index 5d1274d21..100ed41f2 100644 --- a/crates/ra_mbe/src/tests.rs +++ b/crates/ra_mbe/src/tests.rs | |||
@@ -215,6 +215,33 @@ SUBTREE $ | |||
215 | } | 215 | } |
216 | 216 | ||
217 | #[test] | 217 | #[test] |
218 | fn test_lifetime_split() { | ||
219 | parse_macro( | ||
220 | r#" | ||
221 | macro_rules! foo { | ||
222 | ($($t:tt)*) => { $($t)*} | ||
223 | } | ||
224 | "#, | ||
225 | ) | ||
226 | .assert_expand( | ||
227 | r#"foo!(static bar: &'static str = "hello";);"#, | ||
228 | r#" | ||
229 | SUBTREE $ | ||
230 | IDENT static 17 | ||
231 | IDENT bar 18 | ||
232 | PUNCH : [alone] 19 | ||
233 | PUNCH & [alone] 20 | ||
234 | PUNCH ' [joint] 21 | ||
235 | IDENT static 22 | ||
236 | IDENT str 23 | ||
237 | PUNCH = [alone] 24 | ||
238 | LITERAL "hello" 25 | ||
239 | PUNCH ; [joint] 26 | ||
240 | "#, | ||
241 | ); | ||
242 | } | ||
243 | |||
244 | #[test] | ||
218 | fn test_expr_order() { | 245 | fn test_expr_order() { |
219 | let expanded = parse_macro( | 246 | let expanded = parse_macro( |
220 | r#" | 247 | r#" |
@@ -989,6 +1016,36 @@ fn test_literal() { | |||
989 | } | 1016 | } |
990 | 1017 | ||
991 | #[test] | 1018 | #[test] |
1019 | fn test_boolean_is_ident() { | ||
1020 | parse_macro( | ||
1021 | r#" | ||
1022 | macro_rules! foo { | ||
1023 | ($lit0:literal, $lit1:literal) => { const VALUE: (bool,bool) = ($lit0,$lit1); }; | ||
1024 | } | ||
1025 | "#, | ||
1026 | ) | ||
1027 | .assert_expand( | ||
1028 | r#"foo!(true,false);"#, | ||
1029 | r#" | ||
1030 | SUBTREE $ | ||
1031 | IDENT const 14 | ||
1032 | IDENT VALUE 15 | ||
1033 | PUNCH : [alone] 16 | ||
1034 | SUBTREE () 17 | ||
1035 | IDENT bool 18 | ||
1036 | PUNCH , [alone] 19 | ||
1037 | IDENT bool 20 | ||
1038 | PUNCH = [alone] 21 | ||
1039 | SUBTREE () 22 | ||
1040 | IDENT true 29 | ||
1041 | PUNCH , [joint] 25 | ||
1042 | IDENT false 31 | ||
1043 | PUNCH ; [alone] 28 | ||
1044 | "#, | ||
1045 | ); | ||
1046 | } | ||
1047 | |||
1048 | #[test] | ||
992 | fn test_vis() { | 1049 | fn test_vis() { |
993 | parse_macro( | 1050 | parse_macro( |
994 | r#" | 1051 | r#" |
diff --git a/crates/ra_mbe/src/tt_iter.rs b/crates/ra_mbe/src/tt_iter.rs index 100184e66..46c420718 100644 --- a/crates/ra_mbe/src/tt_iter.rs +++ b/crates/ra_mbe/src/tt_iter.rs | |||
@@ -40,9 +40,11 @@ impl<'a> TtIter<'a> { | |||
40 | } | 40 | } |
41 | } | 41 | } |
42 | 42 | ||
43 | pub(crate) fn expect_literal(&mut self) -> Result<&'a tt::Literal, ()> { | 43 | pub(crate) fn expect_literal(&mut self) -> Result<&'a tt::Leaf, ()> { |
44 | match self.expect_leaf()? { | 44 | let it = self.expect_leaf()?; |
45 | tt::Leaf::Literal(it) => Ok(it), | 45 | match it { |
46 | tt::Leaf::Literal(_) => Ok(it), | ||
47 | tt::Leaf::Ident(ident) if ident.text == "true" || ident.text == "false" => Ok(it), | ||
46 | _ => Err(()), | 48 | _ => Err(()), |
47 | } | 49 | } |
48 | } | 50 | } |