mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 12:29:21 +00:00
Try to support pre and post-change metavars
This commit is contained in:
parent
8753ca5360
commit
f48ecb6e09
21 changed files with 255 additions and 110 deletions
|
@ -25,23 +25,26 @@ pub(crate) struct MetaTemplate<S>(pub(crate) Box<[Op<S>]>);
|
|||
|
||||
impl<S: Span> MetaTemplate<S> {
|
||||
pub(crate) fn parse_pattern(pattern: &tt::Subtree<S>) -> Result<Self, ParseError> {
|
||||
MetaTemplate::parse(pattern, Mode::Pattern)
|
||||
MetaTemplate::parse(pattern, Mode::Pattern, false)
|
||||
}
|
||||
|
||||
pub(crate) fn parse_template(template: &tt::Subtree<S>) -> Result<Self, ParseError> {
|
||||
MetaTemplate::parse(template, Mode::Template)
|
||||
pub(crate) fn parse_template(
|
||||
template: &tt::Subtree<S>,
|
||||
new_meta_vars: bool,
|
||||
) -> Result<Self, ParseError> {
|
||||
MetaTemplate::parse(template, Mode::Template, new_meta_vars)
|
||||
}
|
||||
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = &Op<S>> {
|
||||
self.0.iter()
|
||||
}
|
||||
|
||||
fn parse(tt: &tt::Subtree<S>, mode: Mode) -> Result<Self, ParseError> {
|
||||
fn parse(tt: &tt::Subtree<S>, mode: Mode, new_meta_vars: bool) -> Result<Self, ParseError> {
|
||||
let mut src = TtIter::new(tt);
|
||||
|
||||
let mut res = Vec::new();
|
||||
while let Some(first) = src.peek_n(0) {
|
||||
let op = next_op(first, &mut src, mode)?;
|
||||
let op = next_op(first, &mut src, mode, new_meta_vars)?;
|
||||
res.push(op);
|
||||
}
|
||||
|
||||
|
@ -51,13 +54,35 @@ impl<S: Span> MetaTemplate<S> {
|
|||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) enum Op<S> {
|
||||
Var { name: SmolStr, kind: Option<MetaVarKind>, id: S },
|
||||
Ignore { name: SmolStr, id: S },
|
||||
Index { depth: usize },
|
||||
Length { depth: usize },
|
||||
Count { name: SmolStr, depth: usize },
|
||||
Repeat { tokens: MetaTemplate<S>, kind: RepeatKind, separator: Option<Separator<S>> },
|
||||
Subtree { tokens: MetaTemplate<S>, delimiter: tt::Delimiter<S> },
|
||||
Var {
|
||||
name: SmolStr,
|
||||
kind: Option<MetaVarKind>,
|
||||
id: S,
|
||||
},
|
||||
Ignore {
|
||||
name: SmolStr,
|
||||
id: S,
|
||||
},
|
||||
Index {
|
||||
depth: usize,
|
||||
},
|
||||
Length {
|
||||
depth: usize,
|
||||
},
|
||||
Count {
|
||||
name: SmolStr,
|
||||
// FIXME: `usize`` once we drop support for 1.76
|
||||
depth: Option<usize>,
|
||||
},
|
||||
Repeat {
|
||||
tokens: MetaTemplate<S>,
|
||||
kind: RepeatKind,
|
||||
separator: Option<Separator<S>>,
|
||||
},
|
||||
Subtree {
|
||||
tokens: MetaTemplate<S>,
|
||||
delimiter: tt::Delimiter<S>,
|
||||
},
|
||||
Literal(tt::Literal<S>),
|
||||
Punct(SmallVec<[tt::Punct<S>; 3]>),
|
||||
Ident(tt::Ident<S>),
|
||||
|
@ -123,6 +148,7 @@ fn next_op<S: Span>(
|
|||
first_peeked: &tt::TokenTree<S>,
|
||||
src: &mut TtIter<'_, S>,
|
||||
mode: Mode,
|
||||
new_meta_vars: bool,
|
||||
) -> Result<Op<S>, ParseError> {
|
||||
let res = match first_peeked {
|
||||
tt::TokenTree::Leaf(tt::Leaf::Punct(p @ tt::Punct { char: '$', .. })) => {
|
||||
|
@ -136,14 +162,14 @@ fn next_op<S: Span>(
|
|||
tt::TokenTree::Subtree(subtree) => match subtree.delimiter.kind {
|
||||
tt::DelimiterKind::Parenthesis => {
|
||||
let (separator, kind) = parse_repeat(src)?;
|
||||
let tokens = MetaTemplate::parse(subtree, mode)?;
|
||||
let tokens = MetaTemplate::parse(subtree, mode, new_meta_vars)?;
|
||||
Op::Repeat { tokens, separator, kind }
|
||||
}
|
||||
tt::DelimiterKind::Brace => match mode {
|
||||
Mode::Template => {
|
||||
parse_metavar_expr(&mut TtIter::new(subtree)).map_err(|()| {
|
||||
ParseError::unexpected("invalid metavariable expression")
|
||||
})?
|
||||
parse_metavar_expr(new_meta_vars, &mut TtIter::new(subtree)).map_err(
|
||||
|()| ParseError::unexpected("invalid metavariable expression"),
|
||||
)?
|
||||
}
|
||||
Mode::Pattern => {
|
||||
return Err(ParseError::unexpected(
|
||||
|
@ -207,7 +233,7 @@ fn next_op<S: Span>(
|
|||
|
||||
tt::TokenTree::Subtree(subtree) => {
|
||||
src.next().expect("first token already peeked");
|
||||
let tokens = MetaTemplate::parse(subtree, mode)?;
|
||||
let tokens = MetaTemplate::parse(subtree, mode, new_meta_vars)?;
|
||||
Op::Subtree { tokens, delimiter: subtree.delimiter }
|
||||
}
|
||||
};
|
||||
|
@ -288,7 +314,7 @@ fn parse_repeat<S: Span>(
|
|||
Err(ParseError::InvalidRepeat)
|
||||
}
|
||||
|
||||
fn parse_metavar_expr<S: Span>(src: &mut TtIter<'_, S>) -> Result<Op<S>, ()> {
|
||||
fn parse_metavar_expr<S: Span>(new_meta_vars: bool, src: &mut TtIter<'_, S>) -> Result<Op<S>, ()> {
|
||||
let func = src.expect_ident()?;
|
||||
let args = src.expect_subtree()?;
|
||||
|
||||
|
@ -300,16 +326,20 @@ fn parse_metavar_expr<S: Span>(src: &mut TtIter<'_, S>) -> Result<Op<S>, ()> {
|
|||
|
||||
let op = match &*func.text {
|
||||
"ignore" => {
|
||||
args.expect_dollar()?;
|
||||
if new_meta_vars {
|
||||
args.expect_dollar()?;
|
||||
}
|
||||
let ident = args.expect_ident()?;
|
||||
Op::Ignore { name: ident.text.clone(), id: ident.span }
|
||||
}
|
||||
"index" => Op::Index { depth: parse_depth(&mut args)? },
|
||||
"length" => Op::Length { depth: parse_depth(&mut args)? },
|
||||
"count" => {
|
||||
args.expect_dollar()?;
|
||||
if new_meta_vars {
|
||||
args.expect_dollar()?;
|
||||
}
|
||||
let ident = args.expect_ident()?;
|
||||
let depth = if try_eat_comma(&mut args) { parse_depth(&mut args)? } else { 0 };
|
||||
let depth = if try_eat_comma(&mut args) { Some(parse_depth(&mut args)?) } else { None };
|
||||
Op::Count { name: ident.text.clone(), depth }
|
||||
}
|
||||
_ => return Err(()),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue