aboutsummaryrefslogtreecommitdiff
path: root/crates/mbe
diff options
context:
space:
mode:
Diffstat (limited to 'crates/mbe')
-rw-r--r--crates/mbe/src/lib.rs4
-rw-r--r--crates/mbe/src/mbe_expander/matcher.rs4
-rw-r--r--crates/mbe/src/mbe_expander/transcriber.rs35
-rw-r--r--crates/mbe/src/parser.rs15
-rw-r--r--crates/mbe/src/syntax_bridge.rs12
-rw-r--r--crates/mbe/src/tests.rs48
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)]
25pub enum ParseError { 25pub 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
121fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> { 121fn 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)]
10pub(crate) enum Op { 10pub(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)]
478enum SynToken { 478enum SynToken {
479 Ordiniary(SyntaxToken), 479 Ordinary(SyntaxToken),
480 Punch(SyntaxToken, TextSize), 480 Punch(SyntaxToken, TextSize),
481} 481}
482 482
483impl SynToken { 483impl 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 @@
1use std::fmt::Write; 1use std::fmt::Write;
2 2
3use ::parser::FragmentKind; 3use ::parser::FragmentKind;
4use syntax::{ast, AstNode, NodeOrToken, SyntaxKind::IDENT, SyntaxNode, WalkEvent, T}; 4use syntax::{
5 ast, AstNode, NodeOrToken,
6 SyntaxKind::{ERROR, IDENT},
7 SyntaxNode, WalkEvent, T,
8};
5use test_utils::assert_eq_text; 9use test_utils::assert_eq_text;
6 10
7use super::*; 11use 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]
1087fn test_dollar_crate_lhs_is_not_meta() {
1088 parse_macro(
1089 r#"
1090macro_rules! foo {
1091 ($crate) => {};
1092 () => {0};
1093}
1094 "#,
1095 )
1096 .assert_expand_items(r#"foo!{}"#, r#"0"#);
1097}
1098
1099#[test]
1083fn test_lifetime() { 1100fn 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]
1202fn test_expr_after_path_colons() {
1203 assert!(parse_macro(
1204 r#"
1205macro_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]
1186fn test_vec() { 1220fn 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]
1955fn test_rustc_issue_57597() { 1989fn 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)?)+) => {}; }");