diff options
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | crates/ra_mbe/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 112 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_expander.rs | 69 | ||||
-rw-r--r-- | crates/ra_mbe/src/subtree_source.rs | 9 | ||||
-rw-r--r-- | crates/ra_mbe/src/syntax_bridge.rs | 16 | ||||
-rw-r--r-- | crates/ra_mbe/src/tt_cursor.rs | 2 | ||||
-rw-r--r-- | crates/ra_parser/src/grammar.rs | 17 |
8 files changed, 203 insertions, 24 deletions
diff --git a/Cargo.lock b/Cargo.lock index be574ca53..de6e9ec9a 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -1059,6 +1059,7 @@ name = "ra_mbe" | |||
1059 | version = "0.1.0" | 1059 | version = "0.1.0" |
1060 | dependencies = [ | 1060 | dependencies = [ |
1061 | "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", | 1061 | "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", |
1062 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||
1062 | "ra_parser 0.1.0", | 1063 | "ra_parser 0.1.0", |
1063 | "ra_syntax 0.1.0", | 1064 | "ra_syntax 0.1.0", |
1064 | "ra_tt 0.1.0", | 1065 | "ra_tt 0.1.0", |
diff --git a/crates/ra_mbe/Cargo.toml b/crates/ra_mbe/Cargo.toml index 1e5ed6907..68f559295 100644 --- a/crates/ra_mbe/Cargo.toml +++ b/crates/ra_mbe/Cargo.toml | |||
@@ -11,3 +11,4 @@ tt = { path = "../ra_tt", package = "ra_tt" } | |||
11 | itertools = "0.8.0" | 11 | itertools = "0.8.0" |
12 | rustc-hash = "1.0.0" | 12 | rustc-hash = "1.0.0" |
13 | smallvec = "0.6.9" | 13 | smallvec = "0.6.9" |
14 | log = "0.4.5" | ||
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index 7ebba807c..7817232d6 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -437,6 +437,30 @@ impl_froms!(TokenTree: Leaf, Subtree); | |||
437 | } | 437 | } |
438 | 438 | ||
439 | #[test] | 439 | #[test] |
440 | fn test_match_group_zero_match() { | ||
441 | let rules = create_rules( | ||
442 | r#" | ||
443 | macro_rules! foo { | ||
444 | ( $($i:ident)* ) => (); | ||
445 | }"#, | ||
446 | ); | ||
447 | |||
448 | assert_expansion(&rules, "foo! ()", ""); | ||
449 | } | ||
450 | |||
451 | #[test] | ||
452 | fn test_match_group_in_group() { | ||
453 | let rules = create_rules( | ||
454 | r#" | ||
455 | macro_rules! foo { | ||
456 | { $( ( $($i:ident)* ) )* } => ( $( ( $($i)* ) )* ); | ||
457 | }"#, | ||
458 | ); | ||
459 | |||
460 | assert_expansion(&rules, "foo! ( (a b) )", "(a b)"); | ||
461 | } | ||
462 | |||
463 | #[test] | ||
440 | fn test_expand_to_item_list() { | 464 | fn test_expand_to_item_list() { |
441 | let rules = create_rules( | 465 | let rules = create_rules( |
442 | " | 466 | " |
@@ -1118,7 +1142,37 @@ macro_rules! impl_fn_for_zst { | |||
1118 | |$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty | 1142 | |$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty |
1119 | $body: block; )+ | 1143 | $body: block; )+ |
1120 | } => { | 1144 | } => { |
1121 | fn foo(){} | 1145 | $( |
1146 | $( #[$attr] )* | ||
1147 | struct $Name; | ||
1148 | |||
1149 | impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name { | ||
1150 | #[inline] | ||
1151 | extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy { | ||
1152 | $body | ||
1153 | } | ||
1154 | } | ||
1155 | |||
1156 | impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name { | ||
1157 | #[inline] | ||
1158 | extern "rust-call" fn call_mut( | ||
1159 | &mut self, | ||
1160 | ($( $arg, )*): ($( $ArgTy, )*) | ||
1161 | ) -> $ReturnTy { | ||
1162 | Fn::call(&*self, ($( $arg, )*)) | ||
1163 | } | ||
1164 | } | ||
1165 | |||
1166 | impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name { | ||
1167 | type Output = $ReturnTy; | ||
1168 | |||
1169 | #[inline] | ||
1170 | extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy { | ||
1171 | Fn::call(&self, ($( $arg, )*)) | ||
1172 | } | ||
1173 | } | ||
1174 | )+ | ||
1175 | } | ||
1122 | } | 1176 | } |
1123 | } | 1177 | } |
1124 | "#, | 1178 | "#, |
@@ -1141,7 +1195,7 @@ impl_fn_for_zst ! { | |||
1141 | } ; | 1195 | } ; |
1142 | } | 1196 | } |
1143 | "#, | 1197 | "#, |
1144 | "fn foo () {}"); | 1198 | "# [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 ,))}}"); |
1145 | } | 1199 | } |
1146 | 1200 | ||
1147 | #[test] | 1201 | #[test] |
@@ -1160,4 +1214,58 @@ impl_fn_for_zst ! { | |||
1160 | assert_expansion(&rules, r#"impl_nonzero_fmt ! { # [ stable ( feature = "nonzero" , since = "1.28.0" ) ] ( Debug , Display , Binary , Octal , LowerHex , UpperHex ) for NonZeroU8 }"#, | 1214 | assert_expansion(&rules, r#"impl_nonzero_fmt ! { # [ stable ( feature = "nonzero" , since = "1.28.0" ) ] ( Debug , Display , Binary , Octal , LowerHex , UpperHex ) for NonZeroU8 }"#, |
1161 | "fn foo () {}"); | 1215 | "fn foo () {}"); |
1162 | } | 1216 | } |
1217 | |||
1218 | #[test] | ||
1219 | fn test_cfg_if_items() { | ||
1220 | // from https://github.com/rust-lang/rust/blob/33fe1131cadba69d317156847be9a402b89f11bb/src/libstd/macros.rs#L986 | ||
1221 | let rules = create_rules( | ||
1222 | r#" | ||
1223 | macro_rules! __cfg_if_items { | ||
1224 | (($($not:meta,)*) ; ) => {}; | ||
1225 | (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { | ||
1226 | __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* } | ||
1227 | } | ||
1228 | } | ||
1229 | "#, | ||
1230 | ); | ||
1231 | |||
1232 | assert_expansion(&rules, 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 ; ) ) , }"#, | ||
1233 | "__cfg_if_items ! {(rustdoc , ) ; }"); | ||
1234 | } | ||
1235 | |||
1236 | #[test] | ||
1237 | fn test_cfg_if_main() { | ||
1238 | // from https://github.com/rust-lang/rust/blob/3d211248393686e0f73851fc7548f6605220fbe1/src/libpanic_unwind/macros.rs#L9 | ||
1239 | let rules = create_rules( | ||
1240 | r#" | ||
1241 | macro_rules! cfg_if { | ||
1242 | ($( | ||
1243 | if #[cfg($($meta:meta),*)] { $($it:item)* } | ||
1244 | ) else * else { | ||
1245 | $($it2:item)* | ||
1246 | }) => { | ||
1247 | __cfg_if_items! { | ||
1248 | () ; | ||
1249 | $( ( ($($meta),*) ($($it)*) ), )* | ||
1250 | ( () ($($it2)*) ), | ||
1251 | } | ||
1252 | } | ||
1253 | } | ||
1254 | "#, | ||
1255 | ); | ||
1256 | |||
1257 | assert_expansion(&rules, r#" | ||
1258 | cfg_if ! { | ||
1259 | if # [ cfg ( target_env = "msvc" ) ] { | ||
1260 | // no extra unwinder support needed | ||
1261 | } else if # [ cfg ( all ( target_arch = "wasm32" , not ( target_os = "emscripten" ) ) ) ] { | ||
1262 | // no unwinder on the system! | ||
1263 | } else { | ||
1264 | mod libunwind ; | ||
1265 | pub use libunwind :: * ; | ||
1266 | } | ||
1267 | } | ||
1268 | "#, | ||
1269 | "__cfg_if_items ! {() ; (() (mod libunwind ; pub use libunwind :: * ;)) ,}"); | ||
1270 | } | ||
1163 | } | 1271 | } |
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs index 7411dd8b1..d5189b537 100644 --- a/crates/ra_mbe/src/mbe_expander.rs +++ b/crates/ra_mbe/src/mbe_expander.rs | |||
@@ -21,7 +21,10 @@ fn expand_rule(rule: &crate::Rule, input: &tt::Subtree) -> Result<tt::Subtree, E | |||
21 | if !input.is_eof() { | 21 | if !input.is_eof() { |
22 | return Err(ExpandError::UnexpectedToken); | 22 | return Err(ExpandError::UnexpectedToken); |
23 | } | 23 | } |
24 | expand_subtree(&rule.rhs, &bindings, &mut Vec::new()) | 24 | |
25 | let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new(), var_expanded: false }; | ||
26 | |||
27 | expand_subtree(&rule.rhs, &mut ctx) | ||
25 | } | 28 | } |
26 | 29 | ||
27 | /// The actual algorithm for expansion is not too hard, but is pretty tricky. | 30 | /// The actual algorithm for expansion is not too hard, but is pretty tricky. |
@@ -225,7 +228,7 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
225 | crate::TokenTree::Repeat(crate::Repeat { subtree, kind, separator }) => { | 228 | crate::TokenTree::Repeat(crate::Repeat { subtree, kind, separator }) => { |
226 | // Dirty hack to make macro-expansion terminate. | 229 | // Dirty hack to make macro-expansion terminate. |
227 | // This should be replaced by a propper macro-by-example implementation | 230 | // This should be replaced by a propper macro-by-example implementation |
228 | let mut limit = 128; | 231 | let mut limit = 65536; |
229 | let mut counter = 0; | 232 | let mut counter = 0; |
230 | 233 | ||
231 | let mut memento = input.save(); | 234 | let mut memento = input.save(); |
@@ -236,6 +239,7 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
236 | counter += 1; | 239 | counter += 1; |
237 | limit -= 1; | 240 | limit -= 1; |
238 | if limit == 0 { | 241 | if limit == 0 { |
242 | log::warn!("match_lhs excced in repeat pattern exceed limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", subtree, input, kind, separator); | ||
239 | break; | 243 | break; |
240 | } | 244 | } |
241 | 245 | ||
@@ -303,15 +307,21 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
303 | Ok(res) | 307 | Ok(res) |
304 | } | 308 | } |
305 | 309 | ||
310 | #[derive(Debug)] | ||
311 | struct ExpandCtx<'a> { | ||
312 | bindings: &'a Bindings, | ||
313 | nesting: Vec<usize>, | ||
314 | var_expanded: bool, | ||
315 | } | ||
316 | |||
306 | fn expand_subtree( | 317 | fn expand_subtree( |
307 | template: &crate::Subtree, | 318 | template: &crate::Subtree, |
308 | bindings: &Bindings, | 319 | ctx: &mut ExpandCtx, |
309 | nesting: &mut Vec<usize>, | ||
310 | ) -> Result<tt::Subtree, ExpandError> { | 320 | ) -> Result<tt::Subtree, ExpandError> { |
311 | let token_trees = template | 321 | let token_trees = template |
312 | .token_trees | 322 | .token_trees |
313 | .iter() | 323 | .iter() |
314 | .map(|it| expand_tt(it, bindings, nesting)) | 324 | .map(|it| expand_tt(it, ctx)) |
315 | .collect::<Result<Vec<_>, ExpandError>>()?; | 325 | .collect::<Result<Vec<_>, ExpandError>>()?; |
316 | 326 | ||
317 | Ok(tt::Subtree { token_trees, delimiter: template.delimiter }) | 327 | Ok(tt::Subtree { token_trees, delimiter: template.delimiter }) |
@@ -333,26 +343,43 @@ fn reduce_single_token(mut subtree: tt::Subtree) -> tt::TokenTree { | |||
333 | 343 | ||
334 | fn expand_tt( | 344 | fn expand_tt( |
335 | template: &crate::TokenTree, | 345 | template: &crate::TokenTree, |
336 | bindings: &Bindings, | 346 | ctx: &mut ExpandCtx, |
337 | nesting: &mut Vec<usize>, | ||
338 | ) -> Result<tt::TokenTree, ExpandError> { | 347 | ) -> Result<tt::TokenTree, ExpandError> { |
339 | let res: tt::TokenTree = match template { | 348 | let res: tt::TokenTree = match template { |
340 | crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, bindings, nesting)?.into(), | 349 | crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, ctx)?.into(), |
341 | crate::TokenTree::Repeat(repeat) => { | 350 | crate::TokenTree::Repeat(repeat) => { |
342 | let mut token_trees: Vec<tt::TokenTree> = Vec::new(); | 351 | let mut token_trees: Vec<tt::TokenTree> = Vec::new(); |
343 | nesting.push(0); | 352 | ctx.nesting.push(0); |
344 | // Dirty hack to make macro-expansion terminate. | 353 | // Dirty hack to make macro-expansion terminate. |
345 | // This should be replaced by a propper macro-by-example implementation | 354 | // This should be replaced by a propper macro-by-example implementation |
346 | let mut limit = 128; | 355 | let mut limit = 65536; |
347 | let mut has_seps = 0; | 356 | let mut has_seps = 0; |
357 | let mut counter = 0; | ||
358 | |||
359 | let mut some_var_expanded = false; | ||
360 | ctx.var_expanded = false; | ||
361 | |||
362 | while let Ok(t) = expand_subtree(&repeat.subtree, ctx) { | ||
363 | // if no var expaned in the child, we count it as a fail | ||
364 | if !ctx.var_expanded { | ||
365 | break; | ||
366 | } | ||
367 | some_var_expanded = true; | ||
368 | ctx.var_expanded = false; | ||
348 | 369 | ||
349 | while let Ok(t) = expand_subtree(&repeat.subtree, bindings, nesting) { | 370 | counter += 1; |
350 | limit -= 1; | 371 | limit -= 1; |
351 | if limit == 0 { | 372 | if limit == 0 { |
373 | log::warn!( | ||
374 | "expand_tt excced in repeat pattern exceed limit => {:#?}\n{:#?}", | ||
375 | template, | ||
376 | ctx | ||
377 | ); | ||
352 | break; | 378 | break; |
353 | } | 379 | } |
354 | let idx = nesting.pop().unwrap(); | 380 | |
355 | nesting.push(idx + 1); | 381 | let idx = ctx.nesting.pop().unwrap(); |
382 | ctx.nesting.push(idx + 1); | ||
356 | token_trees.push(reduce_single_token(t).into()); | 383 | token_trees.push(reduce_single_token(t).into()); |
357 | 384 | ||
358 | if let Some(ref sep) = repeat.separator { | 385 | if let Some(ref sep) = repeat.separator { |
@@ -374,12 +401,23 @@ fn expand_tt( | |||
374 | } | 401 | } |
375 | } | 402 | } |
376 | } | 403 | } |
404 | |||
405 | if let crate::RepeatKind::ZeroOrOne = repeat.kind { | ||
406 | break; | ||
407 | } | ||
377 | } | 408 | } |
378 | nesting.pop().unwrap(); | 409 | |
410 | ctx.var_expanded = some_var_expanded; | ||
411 | |||
412 | ctx.nesting.pop().unwrap(); | ||
379 | for _ in 0..has_seps { | 413 | for _ in 0..has_seps { |
380 | token_trees.pop(); | 414 | token_trees.pop(); |
381 | } | 415 | } |
382 | 416 | ||
417 | if crate::RepeatKind::OneOrMore == repeat.kind && counter == 0 { | ||
418 | return Err(ExpandError::UnexpectedToken); | ||
419 | } | ||
420 | |||
383 | // Check if it is a singel token subtree without any delimiter | 421 | // Check if it is a singel token subtree without any delimiter |
384 | // e.g {Delimiter:None> ['>'] /Delimiter:None>} | 422 | // e.g {Delimiter:None> ['>'] /Delimiter:None>} |
385 | reduce_single_token(tt::Subtree { token_trees, delimiter: tt::Delimiter::None }) | 423 | reduce_single_token(tt::Subtree { token_trees, delimiter: tt::Delimiter::None }) |
@@ -396,7 +434,8 @@ fn expand_tt( | |||
396 | tt::Leaf::from(tt::Ident { text: "$crate".into(), id: TokenId::unspecified() }) | 434 | tt::Leaf::from(tt::Ident { text: "$crate".into(), id: TokenId::unspecified() }) |
397 | .into() | 435 | .into() |
398 | } else { | 436 | } else { |
399 | let tkn = bindings.get(&v.text, nesting)?.clone(); | 437 | let tkn = ctx.bindings.get(&v.text, &ctx.nesting)?.clone(); |
438 | ctx.var_expanded = true; | ||
400 | 439 | ||
401 | if let tt::TokenTree::Subtree(subtree) = tkn { | 440 | if let tt::TokenTree::Subtree(subtree) = tkn { |
402 | reduce_single_token(subtree) | 441 | reduce_single_token(subtree) |
diff --git a/crates/ra_mbe/src/subtree_source.rs b/crates/ra_mbe/src/subtree_source.rs index e979777fe..845020f4e 100644 --- a/crates/ra_mbe/src/subtree_source.rs +++ b/crates/ra_mbe/src/subtree_source.rs | |||
@@ -212,7 +212,7 @@ impl<'a> SubTreeWalker<'a> { | |||
212 | } | 212 | } |
213 | 213 | ||
214 | pub(crate) trait Querier { | 214 | pub(crate) trait Querier { |
215 | fn token(&self, uidx: usize) -> (SyntaxKind, SmolStr); | 215 | fn token(&self, uidx: usize) -> (SyntaxKind, SmolStr, bool); |
216 | } | 216 | } |
217 | 217 | ||
218 | // A wrapper class for ref cell | 218 | // A wrapper class for ref cell |
@@ -292,9 +292,10 @@ impl<'a> WalkerOwner<'a> { | |||
292 | } | 292 | } |
293 | 293 | ||
294 | impl<'a> Querier for WalkerOwner<'a> { | 294 | impl<'a> Querier for WalkerOwner<'a> { |
295 | fn token(&self, uidx: usize) -> (SyntaxKind, SmolStr) { | 295 | fn token(&self, uidx: usize) -> (SyntaxKind, SmolStr, bool) { |
296 | let tkn = self.get(uidx).unwrap(); | 296 | self.get(uidx) |
297 | (tkn.kind, tkn.text) | 297 | .map(|tkn| (tkn.kind, tkn.text, tkn.is_joint_to_next)) |
298 | .unwrap_or_else(|| (SyntaxKind::EOF, "".into(), false)) | ||
298 | } | 299 | } |
299 | } | 300 | } |
300 | 301 | ||
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs index 9cca19dbb..e0f228ce9 100644 --- a/crates/ra_mbe/src/syntax_bridge.rs +++ b/crates/ra_mbe/src/syntax_bridge.rs | |||
@@ -123,6 +123,11 @@ fn convert_tt( | |||
123 | global_offset: TextUnit, | 123 | global_offset: TextUnit, |
124 | tt: &SyntaxNode, | 124 | tt: &SyntaxNode, |
125 | ) -> Option<tt::Subtree> { | 125 | ) -> Option<tt::Subtree> { |
126 | // This tree is empty | ||
127 | if tt.first_child_or_token().is_none() { | ||
128 | return Some(tt::Subtree { token_trees: vec![], delimiter: tt::Delimiter::None }); | ||
129 | } | ||
130 | |||
126 | let first_child = tt.first_child_or_token()?; | 131 | let first_child = tt.first_child_or_token()?; |
127 | let last_child = tt.last_child_or_token()?; | 132 | let last_child = tt.last_child_or_token()?; |
128 | let (delimiter, skip_first) = match (first_child.kind(), last_child.kind()) { | 133 | let (delimiter, skip_first) = match (first_child.kind(), last_child.kind()) { |
@@ -233,7 +238,16 @@ impl<'a, Q: Querier> TreeSink for TtTreeSink<'a, Q> { | |||
233 | self.text_pos += TextUnit::of_str(&self.buf); | 238 | self.text_pos += TextUnit::of_str(&self.buf); |
234 | let text = SmolStr::new(self.buf.as_str()); | 239 | let text = SmolStr::new(self.buf.as_str()); |
235 | self.buf.clear(); | 240 | self.buf.clear(); |
236 | self.inner.token(kind, text) | 241 | self.inner.token(kind, text); |
242 | |||
243 | // // Add a white space to token | ||
244 | // let (last_kind, _, last_joint_to_next ) = self.src_querier.token(self.token_pos-n_tokens as usize); | ||
245 | // if !last_joint_to_next && last_kind.is_punct() { | ||
246 | // let (cur_kind, _, _ ) = self.src_querier.token(self.token_pos); | ||
247 | // if cur_kind.is_punct() { | ||
248 | // self.inner.token(WHITESPACE, " ".into()); | ||
249 | // } | ||
250 | // } | ||
237 | } | 251 | } |
238 | 252 | ||
239 | fn start_node(&mut self, kind: SyntaxKind) { | 253 | fn start_node(&mut self, kind: SyntaxKind) { |
diff --git a/crates/ra_mbe/src/tt_cursor.rs b/crates/ra_mbe/src/tt_cursor.rs index 343416421..eef642a9c 100644 --- a/crates/ra_mbe/src/tt_cursor.rs +++ b/crates/ra_mbe/src/tt_cursor.rs | |||
@@ -3,7 +3,7 @@ use crate::subtree_parser::Parser; | |||
3 | use crate::subtree_source::TokenPeek; | 3 | use crate::subtree_source::TokenPeek; |
4 | use smallvec::{SmallVec, smallvec}; | 4 | use smallvec::{SmallVec, smallvec}; |
5 | 5 | ||
6 | #[derive(Clone)] | 6 | #[derive(Debug, Clone)] |
7 | pub(crate) struct TtCursor<'a> { | 7 | pub(crate) struct TtCursor<'a> { |
8 | subtree: &'a tt::Subtree, | 8 | subtree: &'a tt::Subtree, |
9 | pos: usize, | 9 | pos: usize, |
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs index 67eae749d..a538ec081 100644 --- a/crates/ra_parser/src/grammar.rs +++ b/crates/ra_parser/src/grammar.rs | |||
@@ -119,7 +119,22 @@ pub(crate) fn meta_item(p: &mut Parser) { | |||
119 | items::token_tree(p); | 119 | items::token_tree(p); |
120 | break; | 120 | break; |
121 | } else { | 121 | } else { |
122 | p.bump(); | 122 | // https://doc.rust-lang.org/reference/attributes.html |
123 | // https://doc.rust-lang.org/reference/paths.html#simple-paths | ||
124 | // The start of an meta must be a simple path | ||
125 | match p.current() { | ||
126 | IDENT | COLONCOLON | SUPER_KW | SELF_KW | CRATE_KW => p.bump(), | ||
127 | EQ => { | ||
128 | p.bump(); | ||
129 | match p.current() { | ||
130 | c if c.is_literal() => p.bump(), | ||
131 | TRUE_KW | FALSE_KW => p.bump(), | ||
132 | _ => {} | ||
133 | } | ||
134 | break; | ||
135 | } | ||
136 | _ => break, | ||
137 | } | ||
123 | } | 138 | } |
124 | } | 139 | } |
125 | 140 | ||