aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--crates/ra_mbe/Cargo.toml1
-rw-r--r--crates/ra_mbe/src/lib.rs112
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs69
-rw-r--r--crates/ra_mbe/src/subtree_source.rs9
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs16
-rw-r--r--crates/ra_mbe/src/tt_cursor.rs2
-rw-r--r--crates/ra_parser/src/grammar.rs17
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"
1059version = "0.1.0" 1059version = "0.1.0"
1060dependencies = [ 1060dependencies = [
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" }
11itertools = "0.8.0" 11itertools = "0.8.0"
12rustc-hash = "1.0.0" 12rustc-hash = "1.0.0"
13smallvec = "0.6.9" 13smallvec = "0.6.9"
14log = "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#"
1258cfg_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)]
311struct ExpandCtx<'a> {
312 bindings: &'a Bindings,
313 nesting: Vec<usize>,
314 var_expanded: bool,
315}
316
306fn expand_subtree( 317fn 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
334fn expand_tt( 344fn 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
214pub(crate) trait Querier { 214pub(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
294impl<'a> Querier for WalkerOwner<'a> { 294impl<'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;
3use crate::subtree_source::TokenPeek; 3use crate::subtree_source::TokenPeek;
4use smallvec::{SmallVec, smallvec}; 4use smallvec::{SmallVec, smallvec};
5 5
6#[derive(Clone)] 6#[derive(Debug, Clone)]
7pub(crate) struct TtCursor<'a> { 7pub(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