diff options
Diffstat (limited to 'crates/mbe')
-rw-r--r-- | crates/mbe/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/mbe/src/mbe_expander/matcher.rs | 4 | ||||
-rw-r--r-- | crates/mbe/src/mbe_expander/transcriber.rs | 35 | ||||
-rw-r--r-- | crates/mbe/src/parser.rs | 15 | ||||
-rw-r--r-- | crates/mbe/src/syntax_bridge.rs | 12 | ||||
-rw-r--r-- | crates/mbe/src/tests.rs | 48 |
6 files changed, 73 insertions, 45 deletions
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs index b3472879d..19543d777 100644 --- a/crates/mbe/src/lib.rs +++ b/crates/mbe/src/lib.rs | |||
@@ -24,7 +24,7 @@ use crate::{ | |||
24 | #[derive(Debug, PartialEq, Eq)] | 24 | #[derive(Debug, PartialEq, Eq)] |
25 | pub enum ParseError { | 25 | pub enum ParseError { |
26 | Expected(String), | 26 | Expected(String), |
27 | RepetitionEmtpyTokenTree, | 27 | RepetitionEmptyTokenTree, |
28 | } | 28 | } |
29 | 29 | ||
30 | #[derive(Debug, PartialEq, Eq, Clone)] | 30 | #[derive(Debug, PartialEq, Eq, Clone)] |
@@ -270,7 +270,7 @@ fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> { | |||
270 | } | 270 | } |
271 | false | 271 | false |
272 | }) { | 272 | }) { |
273 | return Err(ParseError::RepetitionEmtpyTokenTree); | 273 | return Err(ParseError::RepetitionEmptyTokenTree); |
274 | } | 274 | } |
275 | } | 275 | } |
276 | validate(subtree)? | 276 | validate(subtree)? |
diff --git a/crates/mbe/src/mbe_expander/matcher.rs b/crates/mbe/src/mbe_expander/matcher.rs index fdc8844ce..d32e60521 100644 --- a/crates/mbe/src/mbe_expander/matcher.rs +++ b/crates/mbe/src/mbe_expander/matcher.rs | |||
@@ -150,7 +150,7 @@ fn match_subtree( | |||
150 | res.add_err(err!("leftover tokens")); | 150 | res.add_err(err!("leftover tokens")); |
151 | } | 151 | } |
152 | } | 152 | } |
153 | Op::Var { name, kind } => { | 153 | Op::Var { name, kind, .. } => { |
154 | let kind = match kind { | 154 | let kind = match kind { |
155 | Some(k) => k, | 155 | Some(k) => k, |
156 | None => { | 156 | None => { |
@@ -378,7 +378,7 @@ pub(super) fn match_repeat( | |||
378 | src: &mut TtIter, | 378 | src: &mut TtIter, |
379 | ) -> Result<(), ExpandError> { | 379 | ) -> Result<(), ExpandError> { |
380 | // Dirty hack to make macro-expansion terminate. | 380 | // Dirty hack to make macro-expansion terminate. |
381 | // This should be replaced by a propper macro-by-example implementation | 381 | // This should be replaced by a proper macro-by-example implementation |
382 | let mut limit = 65536; | 382 | let mut limit = 65536; |
383 | let mut counter = 0; | 383 | let mut counter = 0; |
384 | 384 | ||
diff --git a/crates/mbe/src/mbe_expander/transcriber.rs b/crates/mbe/src/mbe_expander/transcriber.rs index 720531237..59a3c80a8 100644 --- a/crates/mbe/src/mbe_expander/transcriber.rs +++ b/crates/mbe/src/mbe_expander/transcriber.rs | |||
@@ -67,7 +67,7 @@ struct NestingState { | |||
67 | /// because there is no variable in use by the current repetition | 67 | /// because there is no variable in use by the current repetition |
68 | hit: bool, | 68 | hit: bool, |
69 | /// `at_end` is currently necessary to tell `expand_repeat` if it should stop | 69 | /// `at_end` is currently necessary to tell `expand_repeat` if it should stop |
70 | /// because there is no more value avaible for the current repetition | 70 | /// because there is no more value available for the current repetition |
71 | at_end: bool, | 71 | at_end: bool, |
72 | } | 72 | } |
73 | 73 | ||
@@ -100,8 +100,8 @@ fn expand_subtree( | |||
100 | err = err.or(e); | 100 | err = err.or(e); |
101 | arena.push(tt.into()); | 101 | arena.push(tt.into()); |
102 | } | 102 | } |
103 | Op::Var { name, .. } => { | 103 | Op::Var { name, id, .. } => { |
104 | let ExpandResult { value: fragment, err: e } = expand_var(ctx, &name); | 104 | let ExpandResult { value: fragment, err: e } = expand_var(ctx, &name, *id); |
105 | err = err.or(e); | 105 | err = err.or(e); |
106 | push_fragment(arena, fragment); | 106 | push_fragment(arena, fragment); |
107 | } | 107 | } |
@@ -118,14 +118,11 @@ fn expand_subtree( | |||
118 | ExpandResult { value: tt::Subtree { delimiter: template.delimiter, token_trees: tts }, err } | 118 | ExpandResult { value: tt::Subtree { delimiter: template.delimiter, token_trees: tts }, err } |
119 | } | 119 | } |
120 | 120 | ||
121 | fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> { | 121 | fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr, id: tt::TokenId) -> ExpandResult<Fragment> { |
122 | if v == "crate" { | 122 | // We already handle $crate case in mbe parser |
123 | // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path. | 123 | debug_assert!(v != "crate"); |
124 | let tt = | 124 | |
125 | tt::Leaf::from(tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() }) | 125 | if !ctx.bindings.contains(v) { |
126 | .into(); | ||
127 | ExpandResult::ok(Fragment::Tokens(tt)) | ||
128 | } else if !ctx.bindings.contains(v) { | ||
129 | // Note that it is possible to have a `$var` inside a macro which is not bound. | 126 | // Note that it is possible to have a `$var` inside a macro which is not bound. |
130 | // For example: | 127 | // For example: |
131 | // ``` | 128 | // ``` |
@@ -142,14 +139,8 @@ fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> { | |||
142 | let tt = tt::Subtree { | 139 | let tt = tt::Subtree { |
143 | delimiter: None, | 140 | delimiter: None, |
144 | token_trees: vec![ | 141 | token_trees: vec![ |
145 | tt::Leaf::from(tt::Punct { | 142 | tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, id }).into(), |
146 | char: '$', | 143 | tt::Leaf::from(tt::Ident { text: v.clone(), id }).into(), |
147 | spacing: tt::Spacing::Alone, | ||
148 | id: tt::TokenId::unspecified(), | ||
149 | }) | ||
150 | .into(), | ||
151 | tt::Leaf::from(tt::Ident { text: v.clone(), id: tt::TokenId::unspecified() }) | ||
152 | .into(), | ||
153 | ], | 144 | ], |
154 | } | 145 | } |
155 | .into(); | 146 | .into(); |
@@ -188,11 +179,7 @@ fn expand_repeat( | |||
188 | 179 | ||
189 | counter += 1; | 180 | counter += 1; |
190 | if counter == limit { | 181 | if counter == limit { |
191 | log::warn!( | 182 | log::warn!("expand_tt in repeat pattern exceed limit => {:#?}\n{:#?}", template, ctx); |
192 | "expand_tt excced in repeat pattern exceed limit => {:#?}\n{:#?}", | ||
193 | template, | ||
194 | ctx | ||
195 | ); | ||
196 | break; | 183 | break; |
197 | } | 184 | } |
198 | 185 | ||
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs index 2f3ebc831..f3047972d 100644 --- a/crates/mbe/src/parser.rs +++ b/crates/mbe/src/parser.rs | |||
@@ -8,7 +8,7 @@ use crate::{tt_iter::TtIter, ExpandError, MetaTemplate}; | |||
8 | 8 | ||
9 | #[derive(Clone, Debug, PartialEq, Eq)] | 9 | #[derive(Clone, Debug, PartialEq, Eq)] |
10 | pub(crate) enum Op { | 10 | pub(crate) enum Op { |
11 | Var { name: SmolStr, kind: Option<SmolStr> }, | 11 | Var { name: SmolStr, kind: Option<SmolStr>, id: tt::TokenId }, |
12 | Repeat { subtree: MetaTemplate, kind: RepeatKind, separator: Option<Separator> }, | 12 | Repeat { subtree: MetaTemplate, kind: RepeatKind, separator: Option<Separator> }, |
13 | Leaf(tt::Leaf), | 13 | Leaf(tt::Leaf), |
14 | Subtree(MetaTemplate), | 14 | Subtree(MetaTemplate), |
@@ -106,18 +106,25 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul | |||
106 | } | 106 | } |
107 | let name = UNDERSCORE.clone(); | 107 | let name = UNDERSCORE.clone(); |
108 | let kind = eat_fragment_kind(src, mode)?; | 108 | let kind = eat_fragment_kind(src, mode)?; |
109 | Op::Var { name, kind } | 109 | let id = punct.id; |
110 | Op::Var { name, kind, id } | ||
111 | } | ||
112 | tt::Leaf::Ident(ident) if ident.text == "crate" => { | ||
113 | // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path. | ||
114 | Op::Leaf(tt::Leaf::from(tt::Ident { text: "$crate".into(), id: ident.id })) | ||
110 | } | 115 | } |
111 | tt::Leaf::Ident(ident) => { | 116 | tt::Leaf::Ident(ident) => { |
112 | let name = ident.text.clone(); | 117 | let name = ident.text.clone(); |
113 | let kind = eat_fragment_kind(src, mode)?; | 118 | let kind = eat_fragment_kind(src, mode)?; |
114 | Op::Var { name, kind } | 119 | let id = ident.id; |
120 | Op::Var { name, kind, id } | ||
115 | } | 121 | } |
116 | tt::Leaf::Literal(lit) => { | 122 | tt::Leaf::Literal(lit) => { |
117 | if is_boolean_literal(&lit) { | 123 | if is_boolean_literal(&lit) { |
118 | let name = lit.text.clone(); | 124 | let name = lit.text.clone(); |
119 | let kind = eat_fragment_kind(src, mode)?; | 125 | let kind = eat_fragment_kind(src, mode)?; |
120 | Op::Var { name, kind } | 126 | let id = lit.id; |
127 | Op::Var { name, kind, id } | ||
121 | } else { | 128 | } else { |
122 | bail!("bad var 2"); | 129 | bail!("bad var 2"); |
123 | } | 130 | } |
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index 671036e1c..e648519f9 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs | |||
@@ -149,7 +149,7 @@ impl TokenMap { | |||
149 | } | 149 | } |
150 | 150 | ||
151 | fn remove_delim(&mut self, idx: usize) { | 151 | fn remove_delim(&mut self, idx: usize) { |
152 | // FIXME: This could be accidently quadratic | 152 | // FIXME: This could be accidentally quadratic |
153 | self.entries.remove(idx); | 153 | self.entries.remove(idx); |
154 | } | 154 | } |
155 | } | 155 | } |
@@ -476,14 +476,14 @@ impl Convertor { | |||
476 | 476 | ||
477 | #[derive(Debug)] | 477 | #[derive(Debug)] |
478 | enum SynToken { | 478 | enum SynToken { |
479 | Ordiniary(SyntaxToken), | 479 | Ordinary(SyntaxToken), |
480 | Punch(SyntaxToken, TextSize), | 480 | Punch(SyntaxToken, TextSize), |
481 | } | 481 | } |
482 | 482 | ||
483 | impl SynToken { | 483 | impl SynToken { |
484 | fn token(&self) -> &SyntaxToken { | 484 | fn token(&self) -> &SyntaxToken { |
485 | match self { | 485 | match self { |
486 | SynToken::Ordiniary(it) => it, | 486 | SynToken::Ordinary(it) => it, |
487 | SynToken::Punch(it, _) => it, | 487 | SynToken::Punch(it, _) => it, |
488 | } | 488 | } |
489 | } | 489 | } |
@@ -495,7 +495,7 @@ impl SrcToken for SynToken { | |||
495 | } | 495 | } |
496 | fn to_char(&self) -> Option<char> { | 496 | fn to_char(&self) -> Option<char> { |
497 | match self { | 497 | match self { |
498 | SynToken::Ordiniary(_) => None, | 498 | SynToken::Ordinary(_) => None, |
499 | SynToken::Punch(it, i) => it.text().chars().nth((*i).into()), | 499 | SynToken::Punch(it, i) => it.text().chars().nth((*i).into()), |
500 | } | 500 | } |
501 | } | 501 | } |
@@ -535,7 +535,7 @@ impl TokenConvertor for Convertor { | |||
535 | } else { | 535 | } else { |
536 | self.punct_offset = None; | 536 | self.punct_offset = None; |
537 | let range = curr.text_range(); | 537 | let range = curr.text_range(); |
538 | (SynToken::Ordiniary(curr), range) | 538 | (SynToken::Ordinary(curr), range) |
539 | }; | 539 | }; |
540 | 540 | ||
541 | Some(token) | 541 | Some(token) |
@@ -557,7 +557,7 @@ impl TokenConvertor for Convertor { | |||
557 | let token = if curr.kind().is_punct() { | 557 | let token = if curr.kind().is_punct() { |
558 | SynToken::Punch(curr, 0.into()) | 558 | SynToken::Punch(curr, 0.into()) |
559 | } else { | 559 | } else { |
560 | SynToken::Ordiniary(curr) | 560 | SynToken::Ordinary(curr) |
561 | }; | 561 | }; |
562 | Some(token) | 562 | Some(token) |
563 | } | 563 | } |
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs index 1d9afb4fb..bd2977ebd 100644 --- a/crates/mbe/src/tests.rs +++ b/crates/mbe/src/tests.rs | |||
@@ -1,7 +1,11 @@ | |||
1 | use std::fmt::Write; | 1 | use std::fmt::Write; |
2 | 2 | ||
3 | use ::parser::FragmentKind; | 3 | use ::parser::FragmentKind; |
4 | use syntax::{ast, AstNode, NodeOrToken, SyntaxKind::IDENT, SyntaxNode, WalkEvent, T}; | 4 | use syntax::{ |
5 | ast, AstNode, NodeOrToken, | ||
6 | SyntaxKind::{ERROR, IDENT}, | ||
7 | SyntaxNode, WalkEvent, T, | ||
8 | }; | ||
5 | use test_utils::assert_eq_text; | 9 | use test_utils::assert_eq_text; |
6 | 10 | ||
7 | use super::*; | 11 | use super::*; |
@@ -257,7 +261,6 @@ fn test_expr_order() { | |||
257 | 261 | ||
258 | let dump = format!("{:#?}", expanded); | 262 | let dump = format!("{:#?}", expanded); |
259 | assert_eq_text!( | 263 | assert_eq_text!( |
260 | dump.trim(), | ||
261 | r#"[email protected] | 264 | r#"[email protected] |
262 | [email protected] | 265 | [email protected] |
263 | [email protected] "fn" | 266 | [email protected] "fn" |
@@ -281,6 +284,7 @@ fn test_expr_order() { | |||
281 | [email protected] "2" | 284 | [email protected] "2" |
282 | [email protected] ";" | 285 | [email protected] ";" |
283 | [email protected] "}""#, | 286 | [email protected] "}""#, |
287 | dump.trim() | ||
284 | ); | 288 | ); |
285 | } | 289 | } |
286 | 290 | ||
@@ -985,7 +989,6 @@ fn test_tt_composite2() { | |||
985 | 989 | ||
986 | let res = format!("{:#?}", &node); | 990 | let res = format!("{:#?}", &node); |
987 | assert_eq_text!( | 991 | assert_eq_text!( |
988 | res.trim(), | ||
989 | r###"[email protected] | 992 | r###"[email protected] |
990 | [email protected] | 993 | [email protected] |
991 | [email protected] | 994 | [email protected] |
@@ -999,7 +1002,8 @@ fn test_tt_composite2() { | |||
999 | [email protected] ">" | 1002 | [email protected] ">" |
1000 | [email protected] " " | 1003 | [email protected] " " |
1001 | [email protected] "#" | 1004 | [email protected] "#" |
1002 | [email protected] ")""### | 1005 | [email protected] ")""###, |
1006 | res.trim() | ||
1003 | ); | 1007 | ); |
1004 | } | 1008 | } |
1005 | 1009 | ||
@@ -1080,6 +1084,19 @@ fn test_vertical_bar_with_pat() { | |||
1080 | } | 1084 | } |
1081 | 1085 | ||
1082 | #[test] | 1086 | #[test] |
1087 | fn test_dollar_crate_lhs_is_not_meta() { | ||
1088 | parse_macro( | ||
1089 | r#" | ||
1090 | macro_rules! foo { | ||
1091 | ($crate) => {}; | ||
1092 | () => {0}; | ||
1093 | } | ||
1094 | "#, | ||
1095 | ) | ||
1096 | .assert_expand_items(r#"foo!{}"#, r#"0"#); | ||
1097 | } | ||
1098 | |||
1099 | #[test] | ||
1083 | fn test_lifetime() { | 1100 | fn test_lifetime() { |
1084 | parse_macro( | 1101 | parse_macro( |
1085 | r#" | 1102 | r#" |
@@ -1181,6 +1198,23 @@ macro_rules! foo { | |||
1181 | ); | 1198 | ); |
1182 | } | 1199 | } |
1183 | 1200 | ||
1201 | #[test] | ||
1202 | fn test_expr_after_path_colons() { | ||
1203 | assert!(parse_macro( | ||
1204 | r#" | ||
1205 | macro_rules! m { | ||
1206 | ($k:expr) => { | ||
1207 | f(K::$k); | ||
1208 | } | ||
1209 | } | ||
1210 | "#, | ||
1211 | ) | ||
1212 | .expand_statements(r#"m!(C("0"))"#) | ||
1213 | .descendants() | ||
1214 | .find(|token| token.kind() == ERROR) | ||
1215 | .is_some()); | ||
1216 | } | ||
1217 | |||
1184 | // The following tests are based on real world situations | 1218 | // The following tests are based on real world situations |
1185 | #[test] | 1219 | #[test] |
1186 | fn test_vec() { | 1220 | fn test_vec() { |
@@ -1708,7 +1742,7 @@ impl MacroFixture { | |||
1708 | fn assert_expand(&self, invocation: &str, expected: &str) { | 1742 | fn assert_expand(&self, invocation: &str, expected: &str) { |
1709 | let expansion = self.expand_tt(invocation); | 1743 | let expansion = self.expand_tt(invocation); |
1710 | let actual = format!("{:?}", expansion); | 1744 | let actual = format!("{:?}", expansion); |
1711 | test_utils::assert_eq_text!(&actual.trim(), &expected.trim()); | 1745 | test_utils::assert_eq_text!(&expected.trim(), &actual.trim()); |
1712 | } | 1746 | } |
1713 | 1747 | ||
1714 | fn assert_expand_items(&self, invocation: &str, expected: &str) -> &MacroFixture { | 1748 | fn assert_expand_items(&self, invocation: &str, expected: &str) -> &MacroFixture { |
@@ -1907,7 +1941,6 @@ fn test_no_space_after_semi_colon() { | |||
1907 | 1941 | ||
1908 | let dump = format!("{:#?}", expanded); | 1942 | let dump = format!("{:#?}", expanded); |
1909 | assert_eq_text!( | 1943 | assert_eq_text!( |
1910 | dump.trim(), | ||
1911 | r###"[email protected] | 1944 | r###"[email protected] |
1912 | [email protected] | 1945 | [email protected] |
1913 | [email protected] | 1946 | [email protected] |
@@ -1947,6 +1980,7 @@ fn test_no_space_after_semi_colon() { | |||
1947 | [email protected] | 1980 | [email protected] |
1948 | [email protected] "f" | 1981 | [email protected] "f" |
1949 | [email protected] ";""###, | 1982 | [email protected] ";""###, |
1983 | dump.trim() | ||
1950 | ); | 1984 | ); |
1951 | } | 1985 | } |
1952 | 1986 | ||
@@ -1954,7 +1988,7 @@ fn test_no_space_after_semi_colon() { | |||
1954 | #[test] | 1988 | #[test] |
1955 | fn test_rustc_issue_57597() { | 1989 | fn test_rustc_issue_57597() { |
1956 | fn test_error(fixture: &str) { | 1990 | fn test_error(fixture: &str) { |
1957 | assert_eq!(parse_macro_error(fixture), ParseError::RepetitionEmtpyTokenTree); | 1991 | assert_eq!(parse_macro_error(fixture), ParseError::RepetitionEmptyTokenTree); |
1958 | } | 1992 | } |
1959 | 1993 | ||
1960 | test_error("macro_rules! foo { ($($($i:ident)?)+) => {}; }"); | 1994 | test_error("macro_rules! foo { ($($($i:ident)?)+) => {}; }"); |