Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/mbe/src/parser.rs')
-rw-r--r--crates/mbe/src/parser.rs32
1 files changed, 28 insertions, 4 deletions
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs
index 0fbf832b06..7a143e7466 100644
--- a/crates/mbe/src/parser.rs
+++ b/crates/mbe/src/parser.rs
@@ -52,7 +52,8 @@ impl MetaTemplate {
pub(crate) enum Op {
Var { name: SmolStr, kind: Option<MetaVarKind>, id: tt::TokenId },
Ignore { name: SmolStr, id: tt::TokenId },
- Index { depth: u32 },
+ Index { depth: usize },
+ Count { name: SmolStr, depth: Option<usize> },
Repeat { tokens: MetaTemplate, kind: RepeatKind, separator: Option<Separator> },
Subtree { tokens: MetaTemplate, delimiter: tt::Delimiter },
Literal(tt::Literal),
@@ -295,9 +296,13 @@ fn parse_metavar_expr(src: &mut TtIter<'_>) -> Result<Op, ()> {
let ident = args.expect_ident()?;
Op::Ignore { name: ident.text.clone(), id: ident.span }
}
- "index" => {
- let depth = if args.len() == 0 { 0 } else { args.expect_u32_literal()? };
- Op::Index { depth }
+ "index" => Op::Index { depth: parse_depth(&mut args)? },
+ "count" => {
+ let ident = args.expect_ident()?;
+ // `${count(t)}` and `${count(t,)}` have different meanings. Not sure if this is a bug
+ // but that's how it's implemented in rustc as of this writing. See rust-lang/rust#111904.
+ let depth = if try_eat_comma(&mut args) { Some(parse_depth(&mut args)?) } else { None };
+ Op::Count { name: ident.text.clone(), depth }
}
_ => return Err(()),
};
@@ -308,3 +313,22 @@ fn parse_metavar_expr(src: &mut TtIter<'_>) -> Result<Op, ()> {
Ok(op)
}
+
+fn parse_depth(src: &mut TtIter<'_>) -> Result<usize, ()> {
+ if src.len() == 0 {
+ Ok(0)
+ } else if let tt::Leaf::Literal(lit) = src.expect_literal()? {
+ // Suffixes are not allowed.
+ lit.text.parse().map_err(|_| ())
+ } else {
+ Err(())
+ }
+}
+
+fn try_eat_comma(src: &mut TtIter<'_>) -> bool {
+ if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', .. }))) = src.peek_n(0) {
+ let _ = src.next();
+ return true;
+ }
+ false
+}