mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 21:35:20 +00:00
Support the ${concat(...)}
metavariable expression
I didn't follow rustc precisely, because I think it does some things wrongly (or they are FIXME), but I only allowed more code, not less. So we're all fine.
This commit is contained in:
parent
990c48cb0d
commit
8a50aecb07
9 changed files with 304 additions and 5 deletions
|
@ -84,6 +84,10 @@ pub(crate) enum Op {
|
|||
// FIXME: `usize`` once we drop support for 1.76
|
||||
depth: Option<usize>,
|
||||
},
|
||||
Concat {
|
||||
elements: Box<[ConcatMetaVarExprElem]>,
|
||||
span: Span,
|
||||
},
|
||||
Repeat {
|
||||
tokens: MetaTemplate,
|
||||
kind: RepeatKind,
|
||||
|
@ -98,6 +102,18 @@ pub(crate) enum Op {
|
|||
Ident(tt::Ident<Span>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) enum ConcatMetaVarExprElem {
|
||||
/// There is NO preceding dollar sign, which means that this identifier should be interpreted
|
||||
/// as a literal.
|
||||
Ident(tt::Ident<Span>),
|
||||
/// There is a preceding dollar sign, which means that this identifier should be expanded
|
||||
/// and interpreted as a variable.
|
||||
Var(tt::Ident<Span>),
|
||||
/// For example, a number or a string.
|
||||
Literal(tt::Literal<Span>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) enum RepeatKind {
|
||||
ZeroOrMore,
|
||||
|
@ -384,6 +400,32 @@ fn parse_metavar_expr(src: &mut TtIter<'_, Span>) -> Result<Op, ()> {
|
|||
let depth = if try_eat_comma(&mut args) { Some(parse_depth(&mut args)?) } else { None };
|
||||
Op::Count { name: ident.sym.clone(), depth }
|
||||
}
|
||||
s if sym::concat == *s => {
|
||||
let mut elements = Vec::new();
|
||||
while let Some(next) = args.peek_n(0) {
|
||||
let element = if let tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) = next {
|
||||
args.next().expect("already peeked");
|
||||
ConcatMetaVarExprElem::Literal(lit.clone())
|
||||
} else {
|
||||
let is_var = try_eat_dollar(&mut args);
|
||||
let ident = args.expect_ident_or_underscore()?.clone();
|
||||
|
||||
if is_var {
|
||||
ConcatMetaVarExprElem::Var(ident)
|
||||
} else {
|
||||
ConcatMetaVarExprElem::Ident(ident)
|
||||
}
|
||||
};
|
||||
elements.push(element);
|
||||
if args.peek_n(0).is_some() {
|
||||
args.expect_comma()?;
|
||||
}
|
||||
}
|
||||
if elements.len() < 2 {
|
||||
return Err(());
|
||||
}
|
||||
Op::Concat { elements: elements.into_boxed_slice(), span: func.span }
|
||||
}
|
||||
_ => return Err(()),
|
||||
};
|
||||
|
||||
|
@ -414,3 +456,11 @@ fn try_eat_comma(src: &mut TtIter<'_, Span>) -> bool {
|
|||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn try_eat_dollar(src: &mut TtIter<'_, Span>) -> bool {
|
||||
if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '$', .. }))) = src.peek_n(0) {
|
||||
let _ = src.next();
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue