aboutsummaryrefslogtreecommitdiff
path: root/crates/mbe
diff options
context:
space:
mode:
Diffstat (limited to 'crates/mbe')
-rw-r--r--crates/mbe/src/lib.rs58
-rw-r--r--crates/mbe/src/mbe_expander/matcher.rs72
-rw-r--r--crates/mbe/src/mbe_expander/transcriber.rs29
-rw-r--r--crates/mbe/src/parser.rs77
-rw-r--r--crates/mbe/src/syntax_bridge.rs3
-rw-r--r--crates/mbe/src/tests.rs64
6 files changed, 196 insertions, 107 deletions
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs
index 3ad609a00..b3472879d 100644
--- a/crates/mbe/src/lib.rs
+++ b/crates/mbe/src/lib.rs
@@ -14,10 +14,10 @@ mod tests;
14 14
15use std::fmt; 15use std::fmt;
16 16
17pub use tt::{Delimiter, Punct}; 17pub use tt::{Delimiter, DelimiterKind, Punct};
18 18
19use crate::{ 19use crate::{
20 parser::{parse_pattern, Op}, 20 parser::{parse_pattern, parse_template, Op},
21 tt_iter::TtIter, 21 tt_iter::TtIter,
22}; 22};
23 23
@@ -78,8 +78,24 @@ pub struct MacroRules {
78 78
79#[derive(Clone, Debug, PartialEq, Eq)] 79#[derive(Clone, Debug, PartialEq, Eq)]
80struct Rule { 80struct Rule {
81 lhs: tt::Subtree, 81 lhs: MetaTemplate,
82 rhs: tt::Subtree, 82 rhs: MetaTemplate,
83}
84
85#[derive(Clone, Debug, PartialEq, Eq)]
86struct MetaTemplate {
87 delimiter: Option<Delimiter>,
88 tokens: Vec<Result<Op, ExpandError>>,
89}
90
91impl<'a> MetaTemplate {
92 fn iter(&self) -> impl Iterator<Item = &Result<Op, ExpandError>> {
93 self.tokens.iter()
94 }
95
96 fn delimiter_kind(&self) -> Option<DelimiterKind> {
97 self.delimiter.map(|it| it.kind)
98 }
83} 99}
84 100
85#[derive(Clone, Copy, Debug, PartialEq, Eq)] 101#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -167,7 +183,7 @@ impl MacroRules {
167 rules.push(rule); 183 rules.push(rule);
168 if let Err(()) = src.expect_char(';') { 184 if let Err(()) = src.expect_char(';') {
169 if src.len() > 0 { 185 if src.len() > 0 {
170 return Err(ParseError::Expected("expected `:`".to_string())); 186 return Err(ParseError::Expected("expected `;`".to_string()));
171 } 187 }
172 break; 188 break;
173 } 189 }
@@ -201,23 +217,23 @@ impl MacroRules {
201 217
202impl Rule { 218impl Rule {
203 fn parse(src: &mut TtIter) -> Result<Rule, ParseError> { 219 fn parse(src: &mut TtIter) -> Result<Rule, ParseError> {
204 let mut lhs = src 220 let lhs = src
205 .expect_subtree() 221 .expect_subtree()
206 .map_err(|()| ParseError::Expected("expected subtree".to_string()))? 222 .map_err(|()| ParseError::Expected("expected subtree".to_string()))?;
207 .clone();
208 lhs.delimiter = None;
209 src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?; 223 src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?;
210 src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?; 224 src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?;
211 let mut rhs = src 225 let rhs = src
212 .expect_subtree() 226 .expect_subtree()
213 .map_err(|()| ParseError::Expected("expected subtree".to_string()))? 227 .map_err(|()| ParseError::Expected("expected subtree".to_string()))?;
214 .clone(); 228
215 rhs.delimiter = None; 229 let lhs = MetaTemplate { tokens: parse_pattern(&lhs), delimiter: None };
230 let rhs = MetaTemplate { tokens: parse_template(&rhs), delimiter: None };
231
216 Ok(crate::Rule { lhs, rhs }) 232 Ok(crate::Rule { lhs, rhs })
217 } 233 }
218} 234}
219 235
220fn to_parse_error(e: ExpandError) -> ParseError { 236fn to_parse_error(e: &ExpandError) -> ParseError {
221 let msg = match e { 237 let msg = match e {
222 ExpandError::InvalidRepeat => "invalid repeat".to_string(), 238 ExpandError::InvalidRepeat => "invalid repeat".to_string(),
223 _ => "invalid macro definition".to_string(), 239 _ => "invalid macro definition".to_string(),
@@ -225,22 +241,22 @@ fn to_parse_error(e: ExpandError) -> ParseError {
225 ParseError::Expected(msg) 241 ParseError::Expected(msg)
226} 242}
227 243
228fn validate(pattern: &tt::Subtree) -> Result<(), ParseError> { 244fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> {
229 for op in parse_pattern(pattern) { 245 for op in pattern.iter() {
230 let op = op.map_err(to_parse_error)?; 246 let op = op.as_ref().map_err(|e| to_parse_error(&e))?;
231 247
232 match op { 248 match op {
233 Op::TokenTree(tt::TokenTree::Subtree(subtree)) => validate(subtree)?, 249 Op::Subtree(subtree) => validate(&subtree)?,
234 Op::Repeat { subtree, separator, .. } => { 250 Op::Repeat { subtree, separator, .. } => {
235 // Checks that no repetition which could match an empty token 251 // Checks that no repetition which could match an empty token
236 // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558 252 // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558
237 253
238 if separator.is_none() { 254 if separator.is_none() {
239 if parse_pattern(subtree).all(|child_op| { 255 if subtree.iter().all(|child_op| {
240 match child_op.map_err(to_parse_error) { 256 match child_op.as_ref().map_err(to_parse_error) {
241 Ok(Op::Var { kind, .. }) => { 257 Ok(Op::Var { kind, .. }) => {
242 // vis is optional 258 // vis is optional
243 if kind.map_or(false, |it| it == "vis") { 259 if kind.as_ref().map_or(false, |it| it == "vis") {
244 return true; 260 return true;
245 } 261 }
246 } 262 }
diff --git a/crates/mbe/src/mbe_expander/matcher.rs b/crates/mbe/src/mbe_expander/matcher.rs
index 7aeef7be5..ab5f87c48 100644
--- a/crates/mbe/src/mbe_expander/matcher.rs
+++ b/crates/mbe/src/mbe_expander/matcher.rs
@@ -2,10 +2,10 @@
2 2
3use crate::{ 3use crate::{
4 mbe_expander::{Binding, Bindings, Fragment}, 4 mbe_expander::{Binding, Bindings, Fragment},
5 parser::{parse_pattern, Op, RepeatKind, Separator}, 5 parser::{Op, RepeatKind, Separator},
6 subtree_source::SubtreeTokenSource, 6 subtree_source::SubtreeTokenSource,
7 tt_iter::TtIter, 7 tt_iter::TtIter,
8 ExpandError, 8 ExpandError, MetaTemplate,
9}; 9};
10 10
11use super::ExpandResult; 11use super::ExpandResult;
@@ -83,7 +83,7 @@ impl Match {
83// sense to try using it. Matching errors are added to the `Match`. It might 83// sense to try using it. Matching errors are added to the `Match`. It might
84// make sense to make pattern parsing a separate step? 84// make sense to make pattern parsing a separate step?
85 85
86pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Match, ExpandError> { 86pub(super) fn match_(pattern: &MetaTemplate, src: &tt::Subtree) -> Result<Match, ExpandError> {
87 assert!(pattern.delimiter == None); 87 assert!(pattern.delimiter == None);
88 88
89 let mut res = Match::default(); 89 let mut res = Match::default();
@@ -101,12 +101,12 @@ pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Match,
101 101
102fn match_subtree( 102fn match_subtree(
103 res: &mut Match, 103 res: &mut Match,
104 pattern: &tt::Subtree, 104 pattern: &MetaTemplate,
105 src: &mut TtIter, 105 src: &mut TtIter,
106) -> Result<(), ExpandError> { 106) -> Result<(), ExpandError> {
107 for op in parse_pattern(pattern) { 107 for op in pattern.iter() {
108 match op? { 108 match op.as_ref().map_err(|err| err.clone())? {
109 Op::TokenTree(tt::TokenTree::Leaf(lhs)) => { 109 Op::Leaf(lhs) => {
110 let rhs = match src.expect_leaf() { 110 let rhs = match src.expect_leaf() {
111 Ok(l) => l, 111 Ok(l) => l,
112 Err(()) => { 112 Err(()) => {
@@ -132,7 +132,7 @@ fn match_subtree(
132 } 132 }
133 } 133 }
134 } 134 }
135 Op::TokenTree(tt::TokenTree::Subtree(lhs)) => { 135 Op::Subtree(lhs) => {
136 let rhs = match src.expect_subtree() { 136 let rhs = match src.expect_subtree() {
137 Ok(s) => s, 137 Ok(s) => s,
138 Err(()) => { 138 Err(()) => {
@@ -172,7 +172,7 @@ fn match_subtree(
172 } 172 }
173 } 173 }
174 Op::Repeat { subtree, kind, separator } => { 174 Op::Repeat { subtree, kind, separator } => {
175 match_repeat(res, subtree, kind, separator, src)?; 175 match_repeat(res, subtree, *kind, separator, src)?;
176 } 176 }
177 } 177 }
178 } 178 }
@@ -240,26 +240,26 @@ impl<'a> TtIter<'a> {
240 let tt3 = self.next().unwrap().clone(); 240 let tt3 = self.next().unwrap().clone();
241 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2, tt3] }.into()) 241 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2, tt3] }.into())
242 } 242 }
243 ('-', '=', None) 243 ('-', '=', _)
244 | ('-', '>', None) 244 | ('-', '>', _)
245 | (':', ':', None) 245 | (':', ':', _)
246 | ('!', '=', None) 246 | ('!', '=', _)
247 | ('.', '.', None) 247 | ('.', '.', _)
248 | ('*', '=', None) 248 | ('*', '=', _)
249 | ('/', '=', None) 249 | ('/', '=', _)
250 | ('&', '&', None) 250 | ('&', '&', _)
251 | ('&', '=', None) 251 | ('&', '=', _)
252 | ('%', '=', None) 252 | ('%', '=', _)
253 | ('^', '=', None) 253 | ('^', '=', _)
254 | ('+', '=', None) 254 | ('+', '=', _)
255 | ('<', '<', None) 255 | ('<', '<', _)
256 | ('<', '=', None) 256 | ('<', '=', _)
257 | ('=', '=', None) 257 | ('=', '=', _)
258 | ('=', '>', None) 258 | ('=', '>', _)
259 | ('>', '=', None) 259 | ('>', '=', _)
260 | ('>', '>', None) 260 | ('>', '>', _)
261 | ('|', '=', None) 261 | ('|', '=', _)
262 | ('|', '|', None) => { 262 | ('|', '|', _) => {
263 let tt2 = self.next().unwrap().clone(); 263 let tt2 = self.next().unwrap().clone();
264 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2] }.into()) 264 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2] }.into())
265 } 265 }
@@ -372,9 +372,9 @@ impl<'a> TtIter<'a> {
372 372
373pub(super) fn match_repeat( 373pub(super) fn match_repeat(
374 res: &mut Match, 374 res: &mut Match,
375 pattern: &tt::Subtree, 375 pattern: &MetaTemplate,
376 kind: RepeatKind, 376 kind: RepeatKind,
377 separator: Option<Separator>, 377 separator: &Option<Separator>,
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.
@@ -489,12 +489,12 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragmen
489 result.map(|tt| if kind == "expr" { tt.map(Fragment::Ast) } else { tt.map(Fragment::Tokens) }) 489 result.map(|tt| if kind == "expr" { tt.map(Fragment::Ast) } else { tt.map(Fragment::Tokens) })
490} 490}
491 491
492fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &tt::Subtree) -> Result<(), ExpandError> { 492fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &MetaTemplate) -> Result<(), ExpandError> {
493 for op in parse_pattern(pattern) { 493 for op in pattern.iter() {
494 match op? { 494 match op.as_ref().map_err(|e| e.clone())? {
495 Op::Var { name, .. } => buf.push(name.clone()), 495 Op::Var { name, .. } => buf.push(name.clone()),
496 Op::TokenTree(tt::TokenTree::Leaf(_)) => (), 496 Op::Leaf(_) => (),
497 Op::TokenTree(tt::TokenTree::Subtree(subtree)) => collect_vars(buf, subtree)?, 497 Op::Subtree(subtree) => collect_vars(buf, subtree)?,
498 Op::Repeat { subtree, .. } => collect_vars(buf, subtree)?, 498 Op::Repeat { subtree, .. } => collect_vars(buf, subtree)?,
499 } 499 }
500 } 500 }
diff --git a/crates/mbe/src/mbe_expander/transcriber.rs b/crates/mbe/src/mbe_expander/transcriber.rs
index 57592dc92..720531237 100644
--- a/crates/mbe/src/mbe_expander/transcriber.rs
+++ b/crates/mbe/src/mbe_expander/transcriber.rs
@@ -6,8 +6,8 @@ use syntax::SmolStr;
6use super::ExpandResult; 6use super::ExpandResult;
7use crate::{ 7use crate::{
8 mbe_expander::{Binding, Bindings, Fragment}, 8 mbe_expander::{Binding, Bindings, Fragment},
9 parser::{parse_template, Op, RepeatKind, Separator}, 9 parser::{Op, RepeatKind, Separator},
10 ExpandError, 10 ExpandError, MetaTemplate,
11}; 11};
12 12
13impl Bindings { 13impl Bindings {
@@ -50,7 +50,10 @@ impl Bindings {
50 } 50 }
51} 51}
52 52
53pub(super) fn transcribe(template: &tt::Subtree, bindings: &Bindings) -> ExpandResult<tt::Subtree> { 53pub(super) fn transcribe(
54 template: &MetaTemplate,
55 bindings: &Bindings,
56) -> ExpandResult<tt::Subtree> {
54 assert!(template.delimiter == None); 57 assert!(template.delimiter == None);
55 let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() }; 58 let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() };
56 let mut arena: Vec<tt::TokenTree> = Vec::new(); 59 let mut arena: Vec<tt::TokenTree> = Vec::new();
@@ -76,35 +79,35 @@ struct ExpandCtx<'a> {
76 79
77fn expand_subtree( 80fn expand_subtree(
78 ctx: &mut ExpandCtx, 81 ctx: &mut ExpandCtx,
79 template: &tt::Subtree, 82 template: &MetaTemplate,
80 arena: &mut Vec<tt::TokenTree>, 83 arena: &mut Vec<tt::TokenTree>,
81) -> ExpandResult<tt::Subtree> { 84) -> ExpandResult<tt::Subtree> {
82 // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation 85 // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation
83 let start_elements = arena.len(); 86 let start_elements = arena.len();
84 let mut err = None; 87 let mut err = None;
85 for op in parse_template(template) { 88 for op in template.iter() {
86 let op = match op { 89 let op = match op {
87 Ok(op) => op, 90 Ok(op) => op,
88 Err(e) => { 91 Err(e) => {
89 err = Some(e); 92 err = Some(e.clone());
90 break; 93 break;
91 } 94 }
92 }; 95 };
93 match op { 96 match op {
94 Op::TokenTree(tt @ tt::TokenTree::Leaf(..)) => arena.push(tt.clone()), 97 Op::Leaf(tt) => arena.push(tt.clone().into()),
95 Op::TokenTree(tt::TokenTree::Subtree(tt)) => { 98 Op::Subtree(tt) => {
96 let ExpandResult { value: tt, err: e } = expand_subtree(ctx, tt, arena); 99 let ExpandResult { value: tt, err: e } = expand_subtree(ctx, &tt, arena);
97 err = err.or(e); 100 err = err.or(e);
98 arena.push(tt.into()); 101 arena.push(tt.into());
99 } 102 }
100 Op::Var { name, .. } => { 103 Op::Var { name, .. } => {
101 let ExpandResult { value: fragment, err: e } = expand_var(ctx, name); 104 let ExpandResult { value: fragment, err: e } = expand_var(ctx, &name);
102 err = err.or(e); 105 err = err.or(e);
103 push_fragment(arena, fragment); 106 push_fragment(arena, fragment);
104 } 107 }
105 Op::Repeat { subtree, kind, separator } => { 108 Op::Repeat { subtree, kind, separator } => {
106 let ExpandResult { value: fragment, err: e } = 109 let ExpandResult { value: fragment, err: e } =
107 expand_repeat(ctx, subtree, kind, separator, arena); 110 expand_repeat(ctx, subtree, *kind, separator, arena);
108 err = err.or(e); 111 err = err.or(e);
109 push_fragment(arena, fragment) 112 push_fragment(arena, fragment)
110 } 113 }
@@ -161,9 +164,9 @@ fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> {
161 164
162fn expand_repeat( 165fn expand_repeat(
163 ctx: &mut ExpandCtx, 166 ctx: &mut ExpandCtx,
164 template: &tt::Subtree, 167 template: &MetaTemplate,
165 kind: RepeatKind, 168 kind: RepeatKind,
166 separator: Option<Separator>, 169 separator: &Option<Separator>,
167 arena: &mut Vec<tt::TokenTree>, 170 arena: &mut Vec<tt::TokenTree>,
168) -> ExpandResult<Fragment> { 171) -> ExpandResult<Fragment> {
169 let mut buf: Vec<tt::TokenTree> = Vec::new(); 172 let mut buf: Vec<tt::TokenTree> = Vec::new();
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs
index c3fdd4040..2f3ebc831 100644
--- a/crates/mbe/src/parser.rs
+++ b/crates/mbe/src/parser.rs
@@ -4,16 +4,17 @@
4use smallvec::SmallVec; 4use smallvec::SmallVec;
5use syntax::SmolStr; 5use syntax::SmolStr;
6 6
7use crate::{tt_iter::TtIter, ExpandError}; 7use crate::{tt_iter::TtIter, ExpandError, MetaTemplate};
8 8
9#[derive(Debug)] 9#[derive(Clone, Debug, PartialEq, Eq)]
10pub(crate) enum Op<'a> { 10pub(crate) enum Op {
11 Var { name: &'a SmolStr, kind: Option<&'a SmolStr> }, 11 Var { name: SmolStr, kind: Option<SmolStr> },
12 Repeat { subtree: &'a tt::Subtree, kind: RepeatKind, separator: Option<Separator> }, 12 Repeat { subtree: MetaTemplate, kind: RepeatKind, separator: Option<Separator> },
13 TokenTree(&'a tt::TokenTree), 13 Leaf(tt::Leaf),
14 Subtree(MetaTemplate),
14} 15}
15 16
16#[derive(Clone, Debug, PartialEq, Eq)] 17#[derive(Copy, Clone, Debug, PartialEq, Eq)]
17pub(crate) enum RepeatKind { 18pub(crate) enum RepeatKind {
18 ZeroOrMore, 19 ZeroOrMore,
19 OneOrMore, 20 OneOrMore,
@@ -45,16 +46,12 @@ impl PartialEq for Separator {
45 } 46 }
46} 47}
47 48
48pub(crate) fn parse_template( 49pub(crate) fn parse_template(template: &tt::Subtree) -> Vec<Result<Op, ExpandError>> {
49 template: &tt::Subtree, 50 parse_inner(&template, Mode::Template)
50) -> impl Iterator<Item = Result<Op<'_>, ExpandError>> {
51 parse_inner(template, Mode::Template)
52} 51}
53 52
54pub(crate) fn parse_pattern( 53pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Vec<Result<Op, ExpandError>> {
55 pattern: &tt::Subtree, 54 parse_inner(&pattern, Mode::Pattern)
56) -> impl Iterator<Item = Result<Op<'_>, ExpandError>> {
57 parse_inner(pattern, Mode::Pattern)
58} 55}
59 56
60#[derive(Clone, Copy)] 57#[derive(Clone, Copy)]
@@ -63,12 +60,13 @@ enum Mode {
63 Template, 60 Template,
64} 61}
65 62
66fn parse_inner(src: &tt::Subtree, mode: Mode) -> impl Iterator<Item = Result<Op<'_>, ExpandError>> { 63fn parse_inner(tt: &tt::Subtree, mode: Mode) -> Vec<Result<Op, ExpandError>> {
67 let mut src = TtIter::new(src); 64 let mut src = TtIter::new(&tt);
68 std::iter::from_fn(move || { 65 std::iter::from_fn(move || {
69 let first = src.next()?; 66 let first = src.next()?;
70 Some(next_op(first, &mut src, mode)) 67 Some(next_op(first, &mut src, mode))
71 }) 68 })
69 .collect()
72} 70}
73 71
74macro_rules! err { 72macro_rules! err {
@@ -83,35 +81,41 @@ macro_rules! bail {
83 }; 81 };
84} 82}
85 83
86fn next_op<'a>( 84fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Result<Op, ExpandError> {
87 first: &'a tt::TokenTree,
88 src: &mut TtIter<'a>,
89 mode: Mode,
90) -> Result<Op<'a>, ExpandError> {
91 let res = match first { 85 let res = match first {
92 tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '$', .. })) => { 86 tt::TokenTree::Leaf(leaf @ tt::Leaf::Punct(tt::Punct { char: '$', .. })) => {
93 // Note that the '$' itself is a valid token inside macro_rules. 87 // Note that the '$' itself is a valid token inside macro_rules.
94 let second = match src.next() { 88 let second = match src.next() {
95 None => return Ok(Op::TokenTree(first)), 89 None => return Ok(Op::Leaf(leaf.clone())),
96 Some(it) => it, 90 Some(it) => it,
97 }; 91 };
98 match second { 92 match second {
99 tt::TokenTree::Subtree(subtree) => { 93 tt::TokenTree::Subtree(subtree) => {
100 let (separator, kind) = parse_repeat(src)?; 94 let (separator, kind) = parse_repeat(src)?;
95 let delimiter = subtree.delimiter;
96 let tokens = parse_inner(&subtree, mode);
97 let subtree = MetaTemplate { tokens, delimiter };
101 Op::Repeat { subtree, separator, kind } 98 Op::Repeat { subtree, separator, kind }
102 } 99 }
103 tt::TokenTree::Leaf(leaf) => match leaf { 100 tt::TokenTree::Leaf(leaf) => match leaf {
104 tt::Leaf::Punct(_) => { 101 tt::Leaf::Punct(punct) => {
105 return Err(ExpandError::UnexpectedToken); 102 static UNDERSCORE: SmolStr = SmolStr::new_inline("_");
103
104 if punct.char != '_' {
105 return Err(ExpandError::UnexpectedToken);
106 }
107 let name = UNDERSCORE.clone();
108 let kind = eat_fragment_kind(src, mode)?;
109 Op::Var { name, kind }
106 } 110 }
107 tt::Leaf::Ident(ident) => { 111 tt::Leaf::Ident(ident) => {
108 let name = &ident.text; 112 let name = ident.text.clone();
109 let kind = eat_fragment_kind(src, mode)?; 113 let kind = eat_fragment_kind(src, mode)?;
110 Op::Var { name, kind } 114 Op::Var { name, kind }
111 } 115 }
112 tt::Leaf::Literal(lit) => { 116 tt::Leaf::Literal(lit) => {
113 if is_boolean_literal(lit) { 117 if is_boolean_literal(&lit) {
114 let name = &lit.text; 118 let name = lit.text.clone();
115 let kind = eat_fragment_kind(src, mode)?; 119 let kind = eat_fragment_kind(src, mode)?;
116 Op::Var { name, kind } 120 Op::Var { name, kind }
117 } else { 121 } else {
@@ -121,19 +125,22 @@ fn next_op<'a>(
121 }, 125 },
122 } 126 }
123 } 127 }
124 tt => Op::TokenTree(tt), 128 tt::TokenTree::Leaf(tt) => Op::Leaf(tt.clone()),
129 tt::TokenTree::Subtree(subtree) => {
130 let delimiter = subtree.delimiter;
131 let tokens = parse_inner(&subtree, mode);
132 let subtree = MetaTemplate { tokens, delimiter };
133 Op::Subtree(subtree)
134 }
125 }; 135 };
126 Ok(res) 136 Ok(res)
127} 137}
128 138
129fn eat_fragment_kind<'a>( 139fn eat_fragment_kind<'a>(src: &mut TtIter<'a>, mode: Mode) -> Result<Option<SmolStr>, ExpandError> {
130 src: &mut TtIter<'a>,
131 mode: Mode,
132) -> Result<Option<&'a SmolStr>, ExpandError> {
133 if let Mode::Pattern = mode { 140 if let Mode::Pattern = mode {
134 src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?; 141 src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?;
135 let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?; 142 let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?;
136 return Ok(Some(&ident.text)); 143 return Ok(Some(ident.text.clone()));
137 }; 144 };
138 Ok(None) 145 Ok(None)
139} 146}
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index 2bec7fd49..265c0d63d 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -313,7 +313,7 @@ trait TokenConvertor {
313 return; 313 return;
314 } 314 }
315 315
316 result.push(if k.is_punct() && k != UNDERSCORE { 316 result.push(if k.is_punct() {
317 assert_eq!(range.len(), TextSize::of('.')); 317 assert_eq!(range.len(), TextSize::of('.'));
318 let delim = match k { 318 let delim = match k {
319 T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])), 319 T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])),
@@ -378,7 +378,6 @@ trait TokenConvertor {
378 let leaf: tt::Leaf = match k { 378 let leaf: tt::Leaf = match k {
379 T![true] | T![false] => make_leaf!(Ident), 379 T![true] | T![false] => make_leaf!(Ident),
380 IDENT => make_leaf!(Ident), 380 IDENT => make_leaf!(Ident),
381 UNDERSCORE => make_leaf!(Ident),
382 k if k.is_keyword() => make_leaf!(Ident), 381 k if k.is_keyword() => make_leaf!(Ident),
383 k if k.is_literal() => make_leaf!(Literal), 382 k if k.is_literal() => make_leaf!(Literal),
384 LIFETIME_IDENT => { 383 LIFETIME_IDENT => {
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs
index 451fa1456..1d9afb4fb 100644
--- a/crates/mbe/src/tests.rs
+++ b/crates/mbe/src/tests.rs
@@ -761,6 +761,18 @@ fn test_last_expr() {
761} 761}
762 762
763#[test] 763#[test]
764fn test_expr_with_attr() {
765 parse_macro(
766 r#"
767macro_rules! m {
768 ($a:expr) => {0}
769}
770"#,
771 )
772 .assert_expand_items("m!(#[allow(a)]())", "0");
773}
774
775#[test]
764fn test_ty() { 776fn test_ty() {
765 parse_macro( 777 parse_macro(
766 r#" 778 r#"
@@ -992,6 +1004,22 @@ fn test_tt_composite2() {
992} 1004}
993 1005
994#[test] 1006#[test]
1007fn test_tt_with_composite_without_space() {
1008 parse_macro(
1009 r#"
1010 macro_rules! foo {
1011 ($ op:tt, $j:path) => (
1012 0
1013 )
1014 }
1015"#,
1016 )
1017 // Test macro input without any spaces
1018 // See https://github.com/rust-analyzer/rust-analyzer/issues/6692
1019 .assert_expand_items("foo!(==,Foo::Bool)", "0");
1020}
1021
1022#[test]
995fn test_underscore() { 1023fn test_underscore() {
996 parse_macro( 1024 parse_macro(
997 r#" 1025 r#"
@@ -1004,6 +1032,42 @@ fn test_underscore() {
1004} 1032}
1005 1033
1006#[test] 1034#[test]
1035fn test_underscore_not_greedily() {
1036 parse_macro(
1037 r#"
1038macro_rules! q {
1039 ($($a:ident)* _) => {0};
1040}
1041"#,
1042 )
1043 // `_` overlaps with `$a:ident` but rustc matches it under the `_` token
1044 .assert_expand_items(r#"q![a b c d _]"#, r#"0"#);
1045
1046 parse_macro(
1047 r#"
1048macro_rules! q {
1049 ($($a:expr => $b:ident)* _ => $c:expr) => {0};
1050}
1051"#,
1052 )
1053 // `_ => ou` overlaps with `$a:expr => $b:ident` but rustc matches it under `_ => $c:expr`
1054 .assert_expand_items(r#"q![a => b c => d _ => ou]"#, r#"0"#);
1055}
1056
1057#[test]
1058fn test_underscore_as_type() {
1059 parse_macro(
1060 r#"
1061macro_rules! q {
1062 ($a:ty) => {0};
1063}
1064"#,
1065 )
1066 // Underscore is a type
1067 .assert_expand_items(r#"q![_]"#, r#"0"#);
1068}
1069
1070#[test]
1007fn test_vertical_bar_with_pat() { 1071fn test_vertical_bar_with_pat() {
1008 parse_macro( 1072 parse_macro(
1009 r#" 1073 r#"