1use std::sync::Arc;
5
6use arrayvec::ArrayVec;
7use intern::{Symbol, sym};
8use span::{Edition, Span, SyntaxContext};
9use tt::{
10 MAX_GLUED_PUNCT_LEN,
11 iter::{TtElement, TtIter},
12};
13
14use crate::{MacroCallStyle, ParseError};
15
16pub(crate) fn parse_rule_style(src: &mut TtIter<'_, Span>) -> Result<MacroCallStyle, ParseError> {
17 if let Some(TtElement::Leaf(tt::Leaf::Ident(ident))) = src.peek()
20 && ident.sym == sym::unsafe_
21 {
22 src.next().expect("already peeked");
23 }
24
25 let kind = match src.peek() {
26 Some(TtElement::Leaf(tt::Leaf::Ident(ident))) if ident.sym == sym::attr => {
27 src.next().expect("already peeked");
28 src.expect_subtree().map_err(|_| ParseError::expected("expected `()`"))?;
31 MacroCallStyle::Attr
32 }
33 Some(TtElement::Leaf(tt::Leaf::Ident(ident))) if ident.sym == sym::derive => {
34 src.next().expect("already peeked");
35 src.expect_subtree().map_err(|_| ParseError::expected("expected `()`"))?;
36 MacroCallStyle::Derive
37 }
38 _ => MacroCallStyle::FnLike,
39 };
40 Ok(kind)
41}
42
43#[derive(Clone, Debug, PartialEq, Eq)]
57pub(crate) struct MetaTemplate(pub(crate) Box<[Op]>);
58
59impl MetaTemplate {
60 pub(crate) fn parse_pattern(
61 edition: impl Copy + Fn(SyntaxContext) -> Edition,
62 pattern: TtIter<'_, Span>,
63 ) -> Result<Self, ParseError> {
64 MetaTemplate::parse(edition, pattern, Mode::Pattern)
65 }
66
67 pub(crate) fn parse_template(
68 edition: impl Copy + Fn(SyntaxContext) -> Edition,
69 template: TtIter<'_, Span>,
70 ) -> Result<Self, ParseError> {
71 MetaTemplate::parse(edition, template, Mode::Template)
72 }
73
74 pub(crate) fn iter(&self) -> impl Iterator<Item = &Op> {
75 self.0.iter()
76 }
77
78 fn parse(
79 edition: impl Copy + Fn(SyntaxContext) -> Edition,
80 mut src: TtIter<'_, Span>,
81 mode: Mode,
82 ) -> Result<Self, ParseError> {
83 let mut res = Vec::new();
84 while let Some(first) = src.peek() {
85 let op = next_op(edition, first, &mut src, mode)?;
86 res.push(op);
87 }
88
89 Ok(MetaTemplate(res.into_boxed_slice()))
90 }
91}
92
93#[derive(Clone, Debug, PartialEq, Eq)]
94pub(crate) enum Op {
95 Var {
96 name: Symbol,
97 kind: Option<MetaVarKind>,
98 id: Span,
99 },
100 Ignore {
101 name: Symbol,
102 id: Span,
103 },
104 Index {
105 depth: usize,
106 },
107 Len {
108 depth: usize,
109 },
110 Count {
111 name: Symbol,
112 depth: Option<usize>,
114 },
115 Concat {
116 elements: Box<[ConcatMetaVarExprElem]>,
117 span: Span,
118 },
119 Repeat {
120 tokens: MetaTemplate,
121 kind: RepeatKind,
122 separator: Option<Arc<Separator>>,
123 },
124 Subtree {
125 tokens: MetaTemplate,
126 delimiter: tt::Delimiter<Span>,
127 },
128 Literal(tt::Literal<Span>),
129 Punct(Box<ArrayVec<tt::Punct<Span>, MAX_GLUED_PUNCT_LEN>>),
130 Ident(tt::Ident<Span>),
131}
132
133#[derive(Clone, Debug, PartialEq, Eq)]
134pub(crate) enum ConcatMetaVarExprElem {
135 Ident(tt::Ident<Span>),
138 Var(tt::Ident<Span>),
141 Literal(tt::Literal<Span>),
143}
144
145#[derive(Copy, Clone, Debug, PartialEq, Eq)]
146pub(crate) enum RepeatKind {
147 ZeroOrMore,
148 OneOrMore,
149 ZeroOrOne,
150}
151
152#[derive(Copy, Clone, Debug, PartialEq, Eq)]
153pub(crate) enum ExprKind {
154 Expr,
157 Expr2021,
160}
161
162#[derive(Copy, Clone, Debug, PartialEq, Eq)]
163pub(crate) enum MetaVarKind {
164 Path,
165 Ty,
166 Pat,
167 PatParam,
168 Stmt,
169 Block,
170 Meta,
171 Item,
172 Vis,
173 Expr(ExprKind),
174 Ident,
175 Tt,
176 Lifetime,
177 Literal,
178}
179
180#[derive(Clone, Debug, Eq)]
181pub(crate) enum Separator {
182 Literal(tt::Literal<Span>),
183 Ident(tt::Ident<Span>),
184 Puncts(ArrayVec<tt::Punct<Span>, MAX_GLUED_PUNCT_LEN>),
185 Lifetime(tt::Punct<Span>, tt::Ident<Span>),
186}
187
188impl PartialEq for Separator {
190 fn eq(&self, other: &Separator) -> bool {
191 use Separator::*;
192
193 match (self, other) {
194 (Ident(a), Ident(b)) => a.sym == b.sym,
195 (Literal(a), Literal(b)) => a.symbol == b.symbol,
196 (Puncts(a), Puncts(b)) if a.len() == b.len() => {
197 let a_iter = a.iter().map(|a| a.char);
198 let b_iter = b.iter().map(|b| b.char);
199 a_iter.eq(b_iter)
200 }
201 (Lifetime(_, a), Lifetime(_, b)) => a.sym == b.sym,
202 _ => false,
203 }
204 }
205}
206
207#[derive(Clone, Copy)]
208enum Mode {
209 Pattern,
210 Template,
211}
212
213fn next_op(
214 edition: impl Copy + Fn(SyntaxContext) -> Edition,
215 first_peeked: TtElement<'_, Span>,
216 src: &mut TtIter<'_, Span>,
217 mode: Mode,
218) -> Result<Op, ParseError> {
219 let res = match first_peeked {
220 TtElement::Leaf(tt::Leaf::Punct(p @ tt::Punct { char: '$', .. })) => {
221 src.next().expect("first token already peeked");
222 let second = match src.next() {
224 None => {
225 return Ok(Op::Punct({
226 let mut res = ArrayVec::new();
227 res.push(*p);
228 Box::new(res)
229 }));
230 }
231 Some(it) => it,
232 };
233 match second {
234 TtElement::Subtree(subtree, mut subtree_iter) => match subtree.delimiter.kind {
235 tt::DelimiterKind::Parenthesis => {
236 let (separator, kind) = parse_repeat(src)?;
237 let tokens = MetaTemplate::parse(edition, subtree_iter, mode)?;
238 Op::Repeat { tokens, separator: separator.map(Arc::new), kind }
239 }
240 tt::DelimiterKind::Brace => match mode {
241 Mode::Template => parse_metavar_expr(&mut subtree_iter).map_err(|()| {
242 ParseError::unexpected("invalid metavariable expression")
243 })?,
244 Mode::Pattern => {
245 return Err(ParseError::unexpected(
246 "`${}` metavariable expressions are not allowed in matchers",
247 ));
248 }
249 },
250 _ => {
251 return Err(ParseError::expected(
252 "expected `$()` repetition or `${}` expression",
253 ));
254 }
255 },
256 TtElement::Leaf(leaf) => match leaf {
257 tt::Leaf::Ident(ident) if ident.sym == sym::crate_ => {
258 Op::Ident(tt::Ident {
260 sym: sym::dollar_crate,
261 span: ident.span,
262 is_raw: tt::IdentIsRaw::No,
263 })
264 }
265 tt::Leaf::Ident(ident) => {
266 let kind = eat_fragment_kind(edition, src, mode)?;
267 let name = ident.sym.clone();
268 let id = ident.span;
269 Op::Var { name, kind, id }
270 }
271 tt::Leaf::Literal(lit) if is_boolean_literal(lit) => {
272 let kind = eat_fragment_kind(edition, src, mode)?;
273 let name = lit.symbol.clone();
274 let id = lit.span;
275 Op::Var { name, kind, id }
276 }
277 tt::Leaf::Punct(punct @ tt::Punct { char: '$', .. }) => match mode {
278 Mode::Pattern => {
279 return Err(ParseError::unexpected(
280 "`$$` is not allowed on the pattern side",
281 ));
282 }
283 Mode::Template => Op::Punct({
284 let mut res = ArrayVec::new();
285 res.push(*punct);
286 Box::new(res)
287 }),
288 },
289 tt::Leaf::Punct(_) | tt::Leaf::Literal(_) => {
290 return Err(ParseError::expected("expected ident"));
291 }
292 },
293 }
294 }
295
296 TtElement::Leaf(tt::Leaf::Literal(it)) => {
297 src.next().expect("first token already peeked");
298 Op::Literal(it.clone())
299 }
300
301 TtElement::Leaf(tt::Leaf::Ident(it)) => {
302 src.next().expect("first token already peeked");
303 Op::Ident(it.clone())
304 }
305
306 TtElement::Leaf(tt::Leaf::Punct(_)) => {
307 let puncts = src.expect_glued_punct().unwrap();
309 Op::Punct(Box::new(puncts))
310 }
311
312 TtElement::Subtree(subtree, subtree_iter) => {
313 src.next().expect("first token already peeked");
314 let tokens = MetaTemplate::parse(edition, subtree_iter, mode)?;
315 Op::Subtree { tokens, delimiter: subtree.delimiter }
316 }
317 };
318 Ok(res)
319}
320
321fn eat_fragment_kind(
322 edition: impl Copy + Fn(SyntaxContext) -> Edition,
323 src: &mut TtIter<'_, Span>,
324 mode: Mode,
325) -> Result<Option<MetaVarKind>, ParseError> {
326 if let Mode::Pattern = mode {
327 src.expect_char(':').map_err(|()| ParseError::unexpected("missing fragment specifier"))?;
328 let ident = src
329 .expect_ident()
330 .map_err(|()| ParseError::unexpected("missing fragment specifier"))?;
331 let kind = match ident.sym.as_str() {
332 "path" => MetaVarKind::Path,
333 "ty" => MetaVarKind::Ty,
334 "pat" => {
335 if edition(ident.span.ctx).at_least_2021() {
336 MetaVarKind::Pat
337 } else {
338 MetaVarKind::PatParam
339 }
340 }
341 "pat_param" => MetaVarKind::PatParam,
342 "stmt" => MetaVarKind::Stmt,
343 "block" => MetaVarKind::Block,
344 "meta" => MetaVarKind::Meta,
345 "item" => MetaVarKind::Item,
346 "vis" => MetaVarKind::Vis,
347 "expr" => {
348 if edition(ident.span.ctx).at_least_2024() {
349 MetaVarKind::Expr(ExprKind::Expr)
350 } else {
351 MetaVarKind::Expr(ExprKind::Expr2021)
352 }
353 }
354 "expr_2021" => MetaVarKind::Expr(ExprKind::Expr2021),
355 "ident" => MetaVarKind::Ident,
356 "tt" => MetaVarKind::Tt,
357 "lifetime" => MetaVarKind::Lifetime,
358 "literal" => MetaVarKind::Literal,
359 _ => return Ok(None),
360 };
361 return Ok(Some(kind));
362 };
363 Ok(None)
364}
365
366fn is_boolean_literal(lit: &tt::Literal<Span>) -> bool {
367 matches!(lit.symbol.as_str(), "true" | "false")
368}
369
370fn parse_repeat(src: &mut TtIter<'_, Span>) -> Result<(Option<Separator>, RepeatKind), ParseError> {
371 let mut separator = Separator::Puncts(ArrayVec::new());
372 for tt in src {
373 let tt = match tt {
374 TtElement::Leaf(leaf) => leaf,
375 TtElement::Subtree(..) => return Err(ParseError::InvalidRepeat),
376 };
377 let has_sep = match &separator {
378 Separator::Puncts(puncts) => !puncts.is_empty(),
379 _ => true,
380 };
381 match tt {
382 tt::Leaf::Ident(ident) => match separator {
383 Separator::Puncts(puncts) if puncts.is_empty() => {
384 separator = Separator::Ident(ident.clone());
385 }
386 Separator::Puncts(puncts) => match puncts.as_slice() {
387 [tt::Punct { char: '\'', .. }] => {
388 separator = Separator::Lifetime(puncts[0], ident.clone());
389 }
390 _ => return Err(ParseError::InvalidRepeat),
391 },
392 _ => return Err(ParseError::InvalidRepeat),
393 },
394 tt::Leaf::Literal(_) if has_sep => return Err(ParseError::InvalidRepeat),
395 tt::Leaf::Literal(lit) => separator = Separator::Literal(lit.clone()),
396 tt::Leaf::Punct(punct) => {
397 let repeat_kind = match punct.char {
398 '*' => RepeatKind::ZeroOrMore,
399 '+' => RepeatKind::OneOrMore,
400 '?' => RepeatKind::ZeroOrOne,
401 _ => match &mut separator {
402 Separator::Puncts(puncts) if puncts.len() < 3 => {
403 puncts.push(*punct);
404 continue;
405 }
406 _ => return Err(ParseError::InvalidRepeat),
407 },
408 };
409 return Ok((has_sep.then_some(separator), repeat_kind));
410 }
411 }
412 }
413 Err(ParseError::InvalidRepeat)
414}
415
416fn parse_metavar_expr(src: &mut TtIter<'_, Span>) -> Result<Op, ()> {
417 let func = src.expect_ident()?;
418 let (args, mut args_iter) = src.expect_subtree()?;
419
420 if args.delimiter.kind != tt::DelimiterKind::Parenthesis {
421 return Err(());
422 }
423
424 let op = match &func.sym {
425 s if sym::ignore == *s => {
426 args_iter.expect_dollar()?;
427 let ident = args_iter.expect_ident()?;
428 Op::Ignore { name: ident.sym.clone(), id: ident.span }
429 }
430 s if sym::index == *s => Op::Index { depth: parse_depth(&mut args_iter)? },
431 s if sym::len == *s => Op::Len { depth: parse_depth(&mut args_iter)? },
432 s if sym::count == *s => {
433 args_iter.expect_dollar()?;
434 let ident = args_iter.expect_ident()?;
435 let depth = if try_eat_comma(&mut args_iter) {
436 Some(parse_depth(&mut args_iter)?)
437 } else {
438 None
439 };
440 Op::Count { name: ident.sym.clone(), depth }
441 }
442 s if sym::concat == *s => {
443 let mut elements = Vec::new();
444 while let Some(next) = args_iter.peek() {
445 let element = if let TtElement::Leaf(tt::Leaf::Literal(lit)) = next {
446 args_iter.next().expect("already peeked");
447 ConcatMetaVarExprElem::Literal(lit.clone())
448 } else {
449 let is_var = try_eat_dollar(&mut args_iter);
450 let ident = args_iter.expect_ident_or_underscore()?.clone();
451
452 if is_var {
453 ConcatMetaVarExprElem::Var(ident)
454 } else {
455 ConcatMetaVarExprElem::Ident(ident)
456 }
457 };
458 elements.push(element);
459 if !args_iter.is_empty() {
460 args_iter.expect_comma()?;
461 }
462 }
463 if elements.len() < 2 {
464 return Err(());
465 }
466 Op::Concat { elements: elements.into_boxed_slice(), span: func.span }
467 }
468 _ => return Err(()),
469 };
470
471 if args_iter.next().is_some() {
472 return Err(());
473 }
474
475 Ok(op)
476}
477
478fn parse_depth(src: &mut TtIter<'_, Span>) -> Result<usize, ()> {
479 if src.is_empty() {
480 Ok(0)
481 } else if let tt::Leaf::Literal(tt::Literal { symbol: text, suffix: None, .. }) =
482 src.expect_literal()?
483 {
484 text.as_str().parse().map_err(|_| ())
486 } else {
487 Err(())
488 }
489}
490
491fn try_eat_comma(src: &mut TtIter<'_, Span>) -> bool {
492 if let Some(TtElement::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', .. }))) = src.peek() {
493 let _ = src.next();
494 return true;
495 }
496 false
497}
498
499fn try_eat_dollar(src: &mut TtIter<'_, Span>) -> bool {
500 if let Some(TtElement::Leaf(tt::Leaf::Punct(tt::Punct { char: '$', .. }))) = src.peek() {
501 let _ = src.next();
502 return true;
503 }
504 false
505}