Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/mbe/src/expander/matcher.rs')
-rw-r--r--crates/mbe/src/expander/matcher.rs165
1 files changed, 104 insertions, 61 deletions
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index b20d5579ca..e69d7d14e2 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -61,25 +61,25 @@
use std::{rc::Rc, sync::Arc};
+use intern::{sym, Symbol};
use smallvec::{smallvec, SmallVec};
use span::{Edition, Span};
-use syntax::SmolStr;
use tt::{iter::TtIter, DelimSpan};
use crate::{
expander::{Binding, Bindings, ExpandResult, Fragment},
expect_fragment,
parser::{MetaVarKind, Op, RepeatKind, Separator},
- ExpandError, MetaTemplate, ValueResult,
+ ExpandError, ExpandErrorKind, MetaTemplate, ValueResult,
};
impl Bindings {
- fn push_optional(&mut self, name: &SmolStr) {
- self.inner.insert(name.clone(), Binding::Fragment(Fragment::Empty));
+ fn push_optional(&mut self, name: Symbol) {
+ self.inner.insert(name, Binding::Fragment(Fragment::Empty));
}
- fn push_empty(&mut self, name: &SmolStr) {
- self.inner.insert(name.clone(), Binding::Empty);
+ fn push_empty(&mut self, name: Symbol) {
+ self.inner.insert(name, Binding::Empty);
}
fn bindings(&self) -> impl Iterator<Item = &Binding> {
@@ -127,10 +127,10 @@ pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree<Span>, edition:
#[derive(Debug, Clone)]
enum BindingKind {
- Empty(SmolStr),
- Optional(SmolStr),
- Fragment(SmolStr, Fragment),
- Missing(SmolStr, MetaVarKind),
+ Empty(Symbol),
+ Optional(Symbol),
+ Fragment(Symbol, Fragment),
+ Missing(Symbol, MetaVarKind),
Nested(usize, usize),
}
@@ -178,20 +178,20 @@ impl BindingsBuilder {
}
}
- fn push_empty(&mut self, idx: &mut BindingsIdx, var: &SmolStr) {
+ fn push_empty(&mut self, idx: &mut BindingsIdx, var: &Symbol) {
self.nodes[idx.0].push(LinkNode::Node(Rc::new(BindingKind::Empty(var.clone()))));
}
- fn push_optional(&mut self, idx: &mut BindingsIdx, var: &SmolStr) {
+ fn push_optional(&mut self, idx: &mut BindingsIdx, var: &Symbol) {
self.nodes[idx.0].push(LinkNode::Node(Rc::new(BindingKind::Optional(var.clone()))));
}
- fn push_fragment(&mut self, idx: &mut BindingsIdx, var: &SmolStr, fragment: Fragment) {
+ fn push_fragment(&mut self, idx: &mut BindingsIdx, var: &Symbol, fragment: Fragment) {
self.nodes[idx.0]
.push(LinkNode::Node(Rc::new(BindingKind::Fragment(var.clone(), fragment))));
}
- fn push_missing(&mut self, idx: &mut BindingsIdx, var: &SmolStr, kind: MetaVarKind) {
+ fn push_missing(&mut self, idx: &mut BindingsIdx, var: &Symbol, kind: MetaVarKind) {
self.nodes[idx.0].push(LinkNode::Node(Rc::new(BindingKind::Missing(var.clone(), kind))));
}
@@ -219,10 +219,10 @@ impl BindingsBuilder {
for cmd in nodes {
match cmd {
BindingKind::Empty(name) => {
- bindings.push_empty(name);
+ bindings.push_empty(name.clone());
}
BindingKind::Optional(name) => {
- bindings.push_optional(name);
+ bindings.push_optional(name.clone());
}
BindingKind::Fragment(name, fragment) => {
bindings.inner.insert(name.clone(), Binding::Fragment(fragment.clone()));
@@ -507,28 +507,40 @@ fn match_loop_inner<'t>(
}
OpDelimited::Op(Op::Literal(lhs)) => {
if let Ok(rhs) = src.clone().expect_leaf() {
- if matches!(rhs, tt::Leaf::Literal(it) if it.text == lhs.text) {
+ if matches!(rhs, tt::Leaf::Literal(it) if it.symbol == lhs.symbol) {
item.dot.next();
} else {
- res.add_err(ExpandError::UnexpectedToken);
+ res.add_err(ExpandError::new(
+ *rhs.span(),
+ ExpandErrorKind::UnexpectedToken,
+ ));
item.is_error = true;
}
} else {
- res.add_err(ExpandError::binding_error(format!("expected literal: `{lhs}`")));
+ res.add_err(ExpandError::binding_error(
+ src.clone().next().map_or(delim_span.close, |it| it.first_span()),
+ format!("expected literal: `{lhs}`"),
+ ));
item.is_error = true;
}
try_push!(next_items, item);
}
OpDelimited::Op(Op::Ident(lhs)) => {
if let Ok(rhs) = src.clone().expect_leaf() {
- if matches!(rhs, tt::Leaf::Ident(it) if it.text == lhs.text) {
+ if matches!(rhs, tt::Leaf::Ident(it) if it.sym == lhs.sym) {
item.dot.next();
} else {
- res.add_err(ExpandError::UnexpectedToken);
+ res.add_err(ExpandError::new(
+ *rhs.span(),
+ ExpandErrorKind::UnexpectedToken,
+ ));
item.is_error = true;
}
} else {
- res.add_err(ExpandError::binding_error(format!("expected ident: `{lhs}`")));
+ res.add_err(ExpandError::binding_error(
+ src.clone().next().map_or(delim_span.close, |it| it.first_span()),
+ format!("expected ident: `{lhs}`"),
+ ));
item.is_error = true;
}
try_push!(next_items, item);
@@ -538,8 +550,8 @@ fn match_loop_inner<'t>(
let error = if let Ok(rhs) = fork.expect_glued_punct() {
let first_is_single_quote = rhs[0].char == '\'';
let lhs = lhs.iter().map(|it| it.char);
- let rhs = rhs.iter().map(|it| it.char);
- if lhs.clone().eq(rhs) {
+ let rhs_ = rhs.iter().map(|it| it.char);
+ if lhs.clone().eq(rhs_) {
// HACK: here we use `meta_result` to pass `TtIter` back to caller because
// it might have been advanced multiple times. `ValueResult` is
// insignificant.
@@ -552,13 +564,19 @@ fn match_loop_inner<'t>(
if first_is_single_quote {
// If the first punct token is a single quote, that's a part of a lifetime
// ident, not a punct.
- ExpandError::UnexpectedToken
+ ExpandError::new(
+ rhs.get(1).map_or(rhs[0].span, |it| it.span),
+ ExpandErrorKind::UnexpectedToken,
+ )
} else {
- let lhs: SmolStr = lhs.collect();
- ExpandError::binding_error(format!("expected punct: `{lhs}`"))
+ let lhs = lhs.collect::<String>();
+ ExpandError::binding_error(rhs[0].span, format!("expected punct: `{lhs}`"))
}
} else {
- ExpandError::UnexpectedToken
+ ExpandError::new(
+ src.clone().next().map_or(delim_span.close, |it| it.first_span()),
+ ExpandErrorKind::UnexpectedToken,
+ )
};
res.add_err(error);
@@ -651,7 +669,7 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree<Span>, edition: Edition)
if let Some(item) = error_recover_item {
res.bindings = bindings_builder.build(&item);
}
- res.add_err(ExpandError::UnexpectedToken);
+ res.add_err(ExpandError::new(span.open, ExpandErrorKind::UnexpectedToken));
}
return res;
}
@@ -670,7 +688,7 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree<Span>, edition: Edition)
src = it;
res.unmatched_tts += src.len();
}
- res.add_err(ExpandError::LeftoverTokens);
+ res.add_err(ExpandError::new(span.open, ExpandErrorKind::LeftoverTokens));
if let Some(error_recover_item) = error_recover_item {
res.bindings = bindings_builder.build(&error_recover_item);
@@ -746,9 +764,10 @@ fn match_meta_var(
) -> ExpandResult<Option<Fragment>> {
let fragment = match kind {
MetaVarKind::Path => {
- return expect_fragment(input, parser::PrefixEntryPoint::Path, edition).map(|it| {
- it.map(|it| tt::TokenTree::subtree_or_wrap(it, delim_span)).map(Fragment::Path)
- });
+ return expect_fragment(input, parser::PrefixEntryPoint::Path, edition, delim_span)
+ .map(|it| {
+ it.map(|it| tt::TokenTree::subtree_or_wrap(it, delim_span)).map(Fragment::Path)
+ });
}
MetaVarKind::Expr => {
// `expr` should not match underscores, let expressions, or inline const. The latter
@@ -759,39 +778,58 @@ fn match_meta_var(
// [1]: https://github.com/rust-lang/rust/blob/f0c4da499/compiler/rustc_expand/src/mbe/macro_parser.rs#L576
match input.peek_n(0) {
Some(tt::TokenTree::Leaf(tt::Leaf::Ident(it)))
- if it.text == "_" || it.text == "let" || it.text == "const" =>
+ if it.sym == sym::underscore
+ || it.sym == sym::let_
+ || it.sym == sym::const_ =>
{
- return ExpandResult::only_err(ExpandError::NoMatchingRule)
+ return ExpandResult::only_err(ExpandError::new(
+ it.span,
+ ExpandErrorKind::NoMatchingRule,
+ ))
}
_ => {}
};
- return expect_fragment(input, parser::PrefixEntryPoint::Expr, edition).map(|tt| {
- tt.map(|tt| match tt {
- tt::TokenTree::Leaf(leaf) => tt::Subtree {
- delimiter: tt::Delimiter::invisible_spanned(*leaf.span()),
- token_trees: Box::new([leaf.into()]),
- },
- tt::TokenTree::Subtree(mut s) => {
- if s.delimiter.kind == tt::DelimiterKind::Invisible {
- s.delimiter.kind = tt::DelimiterKind::Parenthesis;
+ return expect_fragment(input, parser::PrefixEntryPoint::Expr, edition, delim_span)
+ .map(|tt| {
+ tt.map(|tt| match tt {
+ tt::TokenTree::Leaf(leaf) => tt::Subtree {
+ delimiter: tt::Delimiter::invisible_spanned(*leaf.span()),
+ token_trees: Box::new([leaf.into()]),
+ },
+ tt::TokenTree::Subtree(mut s) => {
+ if s.delimiter.kind == tt::DelimiterKind::Invisible {
+ s.delimiter.kind = tt::DelimiterKind::Parenthesis;
+ }
+ s
}
- s
- }
- })
- .map(Fragment::Expr)
- });
+ })
+ .map(Fragment::Expr)
+ });
}
MetaVarKind::Ident | MetaVarKind::Tt | MetaVarKind::Lifetime | MetaVarKind::Literal => {
+ let span = input.next_span();
let tt_result = match kind {
MetaVarKind::Ident => input
.expect_ident()
.map(|ident| tt::Leaf::from(ident.clone()).into())
- .map_err(|()| ExpandError::binding_error("expected ident")),
- MetaVarKind::Tt => {
- expect_tt(input).map_err(|()| ExpandError::binding_error("expected token tree"))
- }
- MetaVarKind::Lifetime => expect_lifetime(input)
- .map_err(|()| ExpandError::binding_error("expected lifetime")),
+ .map_err(|()| {
+ ExpandError::binding_error(
+ span.unwrap_or(delim_span.close),
+ "expected ident",
+ )
+ }),
+ MetaVarKind::Tt => expect_tt(input).map_err(|()| {
+ ExpandError::binding_error(
+ span.unwrap_or(delim_span.close),
+ "expected token tree",
+ )
+ }),
+ MetaVarKind::Lifetime => expect_lifetime(input).map_err(|()| {
+ ExpandError::binding_error(
+ span.unwrap_or(delim_span.close),
+ "expected lifetime",
+ )
+ }),
MetaVarKind::Literal => {
let neg = eat_char(input, '-');
input
@@ -806,7 +844,12 @@ fn match_meta_var(
}),
}
})
- .map_err(|()| ExpandError::binding_error("expected literal"))
+ .map_err(|()| {
+ ExpandError::binding_error(
+ span.unwrap_or(delim_span.close),
+ "expected literal",
+ )
+ })
}
_ => unreachable!(),
};
@@ -821,10 +864,10 @@ fn match_meta_var(
MetaVarKind::Item => parser::PrefixEntryPoint::Item,
MetaVarKind::Vis => parser::PrefixEntryPoint::Vis,
};
- expect_fragment(input, fragment, edition).map(|it| it.map(Fragment::Tokens))
+ expect_fragment(input, fragment, edition, delim_span).map(|it| it.map(Fragment::Tokens))
}
-fn collect_vars(collector_fun: &mut impl FnMut(SmolStr), pattern: &MetaTemplate) {
+fn collect_vars(collector_fun: &mut impl FnMut(Symbol), pattern: &MetaTemplate) {
for op in pattern.iter() {
match op {
Op::Var { name, .. } => collector_fun(name.clone()),
@@ -908,13 +951,13 @@ fn expect_separator<S: Copy>(iter: &mut TtIter<'_, S>, separator: &Separator) ->
let mut fork = iter.clone();
let ok = match separator {
Separator::Ident(lhs) => match fork.expect_ident_or_underscore() {
- Ok(rhs) => rhs.text == lhs.text,
+ Ok(rhs) => rhs.sym == lhs.sym,
Err(_) => false,
},
Separator::Literal(lhs) => match fork.expect_literal() {
Ok(rhs) => match rhs {
- tt::Leaf::Literal(rhs) => rhs.text == lhs.text,
- tt::Leaf::Ident(rhs) => rhs.text == lhs.text,
+ tt::Leaf::Literal(rhs) => rhs.symbol == lhs.symbol,
+ tt::Leaf::Ident(rhs) => rhs.sym == lhs.symbol,
tt::Leaf::Punct(_) => false,
},
Err(_) => false,