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.rs36
1 files changed, 30 insertions, 6 deletions
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs
index fd3d64719a..7a143e7466 100644
--- a/crates/mbe/src/parser.rs
+++ b/crates/mbe/src/parser.rs
@@ -20,7 +20,7 @@ use crate::{tt, tt_iter::TtIter, ParseError};
/// Stuff to the right is a [`MetaTemplate`] template which is used to produce
/// output.
#[derive(Clone, Debug, PartialEq, Eq)]
-pub(crate) struct MetaTemplate(pub(crate) Vec<Op>);
+pub(crate) struct MetaTemplate(pub(crate) Box<[Op]>);
impl MetaTemplate {
pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Result<MetaTemplate, ParseError> {
@@ -44,7 +44,7 @@ impl MetaTemplate {
res.push(op);
}
- Ok(MetaTemplate(res))
+ Ok(MetaTemplate(res.into_boxed_slice()))
}
}
@@ -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
+}