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.rs243
1 files changed, 100 insertions, 143 deletions
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index 95641abc0f..b7f25aa380 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -64,7 +64,10 @@ use std::{rc::Rc, sync::Arc};
use intern::{sym, Symbol};
use smallvec::{smallvec, SmallVec};
use span::{Edition, Span};
-use tt::{iter::TtIter, DelimSpan};
+use tt::{
+ iter::{TtElement, TtIter},
+ DelimSpan,
+};
use crate::{
expander::{Binding, Bindings, ExpandResult, Fragment},
@@ -73,7 +76,7 @@ use crate::{
ExpandError, ExpandErrorKind, MetaTemplate, ValueResult,
};
-impl Bindings {
+impl<'a> Bindings<'a> {
fn push_optional(&mut self, name: Symbol) {
self.inner.insert(name, Binding::Fragment(Fragment::Empty));
}
@@ -82,14 +85,14 @@ impl Bindings {
self.inner.insert(name, Binding::Empty);
}
- fn bindings(&self) -> impl Iterator<Item = &Binding> {
+ fn bindings(&self) -> impl Iterator<Item = &Binding<'a>> {
self.inner.values()
}
}
-#[derive(Clone, Default, Debug, PartialEq, Eq)]
-pub(super) struct Match {
- pub(super) bindings: Bindings,
+#[derive(Clone, Default, Debug)]
+pub(super) struct Match<'a> {
+ pub(super) bindings: Bindings<'a>,
/// We currently just keep the first error and count the rest to compare matches.
pub(super) err: Option<ExpandError>,
pub(super) err_count: usize,
@@ -99,7 +102,7 @@ pub(super) struct Match {
pub(super) bound_count: usize,
}
-impl Match {
+impl Match<'_> {
fn add_err(&mut self, err: ExpandError) {
let prev_err = self.err.take();
self.err = prev_err.or(Some(err));
@@ -108,12 +111,16 @@ impl Match {
}
/// Matching errors are added to the `Match`.
-pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree<Span>, edition: Edition) -> Match {
+pub(super) fn match_<'t>(
+ pattern: &'t MetaTemplate,
+ input: &'t tt::TopSubtree<Span>,
+ edition: Edition,
+) -> Match<'t> {
let mut res = match_loop(pattern, input, edition);
res.bound_count = count(res.bindings.bindings());
return res;
- fn count<'a>(bindings: impl Iterator<Item = &'a Binding>) -> usize {
+ fn count<'a>(bindings: impl Iterator<Item = &'a Binding<'a>>) -> usize {
bindings
.map(|it| match it {
Binding::Fragment(_) => 1,
@@ -126,10 +133,10 @@ pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree<Span>, edition:
}
#[derive(Debug, Clone)]
-enum BindingKind {
+enum BindingKind<'a> {
Empty(Symbol),
Optional(Symbol),
- Fragment(Symbol, Fragment),
+ Fragment(Symbol, Fragment<'a>),
Missing(Symbol, MetaVarKind),
Nested(usize, usize),
}
@@ -144,12 +151,12 @@ enum LinkNode<T> {
}
#[derive(Default)]
-struct BindingsBuilder {
- nodes: Vec<Vec<LinkNode<Rc<BindingKind>>>>,
+struct BindingsBuilder<'a> {
+ nodes: Vec<Vec<LinkNode<Rc<BindingKind<'a>>>>>,
nested: Vec<Vec<LinkNode<usize>>>,
}
-impl BindingsBuilder {
+impl<'a> BindingsBuilder<'a> {
fn alloc(&mut self) -> BindingsIdx {
let idx = self.nodes.len();
self.nodes.push(Vec::new());
@@ -186,7 +193,7 @@ impl BindingsBuilder {
self.nodes[idx.0].push(LinkNode::Node(Rc::new(BindingKind::Optional(var.clone()))));
}
- fn push_fragment(&mut self, idx: &mut BindingsIdx, var: &Symbol, fragment: Fragment) {
+ fn push_fragment(&mut self, idx: &mut BindingsIdx, var: &Symbol, fragment: Fragment<'a>) {
self.nodes[idx.0]
.push(LinkNode::Node(Rc::new(BindingKind::Fragment(var.clone(), fragment))));
}
@@ -207,11 +214,11 @@ impl BindingsBuilder {
idx.0 = new_idx;
}
- fn build(self, idx: &BindingsIdx) -> Bindings {
+ fn build(self, idx: &BindingsIdx) -> Bindings<'a> {
self.build_inner(&self.nodes[idx.0])
}
- fn build_inner(&self, link_nodes: &[LinkNode<Rc<BindingKind>>]) -> Bindings {
+ fn build_inner(&self, link_nodes: &[LinkNode<Rc<BindingKind<'a>>>]) -> Bindings<'a> {
let mut bindings = Bindings::default();
let mut nodes = Vec::new();
self.collect_nodes(link_nodes, &mut nodes);
@@ -257,11 +264,11 @@ impl BindingsBuilder {
bindings
}
- fn collect_nested_ref<'a>(
- &'a self,
+ fn collect_nested_ref<'b>(
+ &'b self,
id: usize,
len: usize,
- nested_refs: &mut Vec<&'a [LinkNode<Rc<BindingKind>>]>,
+ nested_refs: &mut Vec<&'b [LinkNode<Rc<BindingKind<'a>>>]>,
) {
self.nested[id].iter().take(len).for_each(|it| match it {
LinkNode::Node(id) => nested_refs.push(&self.nodes[*id]),
@@ -269,7 +276,7 @@ impl BindingsBuilder {
});
}
- fn collect_nested(&self, idx: usize, nested_idx: usize, nested: &mut Vec<Bindings>) {
+ fn collect_nested(&self, idx: usize, nested_idx: usize, nested: &mut Vec<Bindings<'a>>) {
let last = &self.nodes[idx];
let mut nested_refs: Vec<&[_]> = Vec::new();
self.nested[nested_idx].iter().for_each(|it| match *it {
@@ -280,17 +287,22 @@ impl BindingsBuilder {
nested.extend(nested_refs.into_iter().map(|iter| self.build_inner(iter)));
}
- fn collect_nodes_ref<'a>(&'a self, id: usize, len: usize, nodes: &mut Vec<&'a BindingKind>) {
+ fn collect_nodes_ref<'b>(
+ &'b self,
+ id: usize,
+ len: usize,
+ nodes: &mut Vec<&'b BindingKind<'a>>,
+ ) {
self.nodes[id].iter().take(len).for_each(|it| match it {
LinkNode::Node(it) => nodes.push(it),
LinkNode::Parent { idx, len } => self.collect_nodes_ref(*idx, *len, nodes),
});
}
- fn collect_nodes<'a>(
- &'a self,
- link_nodes: &'a [LinkNode<Rc<BindingKind>>],
- nodes: &mut Vec<&'a BindingKind>,
+ fn collect_nodes<'b>(
+ &'b self,
+ link_nodes: &'b [LinkNode<Rc<BindingKind<'a>>>],
+ nodes: &mut Vec<&'b BindingKind<'a>>,
) {
link_nodes.iter().for_each(|it| match it {
LinkNode::Node(it) => nodes.push(it),
@@ -327,7 +339,7 @@ struct MatchState<'t> {
bindings: BindingsIdx,
/// Cached result of meta variable parsing
- meta_result: Option<(TtIter<'t, Span>, ExpandResult<Option<Fragment>>)>,
+ meta_result: Option<(TtIter<'t, Span>, ExpandResult<Option<Fragment<'t>>>)>,
/// Is error occurred in this state, will `poised` to "parent"
is_error: bool,
@@ -355,8 +367,8 @@ struct MatchState<'t> {
fn match_loop_inner<'t>(
src: TtIter<'t, Span>,
stack: &[TtIter<'t, Span>],
- res: &mut Match,
- bindings_builder: &mut BindingsBuilder,
+ res: &mut Match<'t>,
+ bindings_builder: &mut BindingsBuilder<'t>,
cur_items: &mut SmallVec<[MatchState<'t>; 1]>,
bb_items: &mut SmallVec<[MatchState<'t>; 1]>,
next_items: &mut Vec<MatchState<'t>>,
@@ -463,7 +475,7 @@ fn match_loop_inner<'t>(
})
}
OpDelimited::Op(Op::Subtree { tokens, delimiter }) => {
- if let Ok(subtree) = src.clone().expect_subtree() {
+ if let Ok((subtree, _)) = src.clone().expect_subtree() {
if subtree.delimiter.kind == delimiter.kind {
item.stack.push(item.dot);
item.dot = tokens.iter_delimited_with(*delimiter);
@@ -478,8 +490,8 @@ fn match_loop_inner<'t>(
match match_res.err {
None => {
// Some meta variables are optional (e.g. vis)
- if match_res.value.is_some() {
- item.meta_result = Some((fork, match_res));
+ if !match_res.value.is_empty() {
+ item.meta_result = Some((fork, match_res.map(Some)));
try_push!(bb_items, item);
} else {
bindings_builder.push_optional(&mut item.bindings, name);
@@ -489,15 +501,14 @@ fn match_loop_inner<'t>(
}
Some(err) => {
res.add_err(err);
- match match_res.value {
- Some(fragment) => bindings_builder.push_fragment(
+ if !match_res.value.is_empty() {
+ bindings_builder.push_fragment(
&mut item.bindings,
name,
- fragment,
- ),
- None => {
- bindings_builder.push_missing(&mut item.bindings, name, kind)
- }
+ match_res.value,
+ )
+ } else {
+ bindings_builder.push_missing(&mut item.bindings, name, kind)
}
item.is_error = true;
error_items.push(item);
@@ -593,13 +604,13 @@ fn match_loop_inner<'t>(
stdx::never!("metavariable expression in lhs found");
}
OpDelimited::Open => {
- if matches!(src.peek_n(0), Some(tt::TokenTree::Subtree(..))) {
+ if matches!(src.peek(), Some(TtElement::Subtree(..))) {
item.dot.next();
try_push!(next_items, item);
}
}
OpDelimited::Close => {
- let is_delim_closed = src.peek_n(0).is_none() && !stack.is_empty();
+ let is_delim_closed = src.is_empty() && !stack.is_empty();
if is_delim_closed {
item.dot.next();
try_push!(next_items, item);
@@ -609,9 +620,13 @@ fn match_loop_inner<'t>(
}
}
-fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree<Span>, edition: Edition) -> Match {
- let span = src.delimiter.delim_span();
- let mut src = TtIter::new(src);
+fn match_loop<'t>(
+ pattern: &'t MetaTemplate,
+ src: &'t tt::TopSubtree<Span>,
+ edition: Edition,
+) -> Match<'t> {
+ let span = src.top_subtree().delimiter.delim_span();
+ let mut src = src.iter();
let mut stack: SmallVec<[TtIter<'_, Span>; 1]> = SmallVec::new();
let mut res = Match::default();
let mut error_recover_item = None;
@@ -663,7 +678,7 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree<Span>, edition: Edition)
// We need to do some post processing after the `match_loop_inner`.
// If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise,
// either the parse is ambiguous (which should never happen) or there is a syntax error.
- if src.peek_n(0).is_none() && stack.is_empty() {
+ if src.is_empty() && stack.is_empty() {
if let [state] = &*eof_items {
// remove all errors, because it is the correct answer !
res = Match::default();
@@ -687,11 +702,7 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree<Span>, edition: Edition)
|| !(bb_items.is_empty() || next_items.is_empty())
|| bb_items.len() > 1;
if has_leftover_tokens {
- res.unmatched_tts += src.len();
- while let Some(it) = stack.pop() {
- src = it;
- res.unmatched_tts += src.len();
- }
+ res.unmatched_tts += src.remaining().flat_tokens().len();
res.add_err(ExpandError::new(span.open, ExpandErrorKind::LeftoverTokens));
if let Some(error_recover_item) = error_recover_item {
@@ -714,9 +725,9 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree<Span>, edition: Edition)
}
} else {
match src.next() {
- Some(tt::TokenTree::Subtree(subtree)) => {
+ Some(TtElement::Subtree(_, subtree_iter)) => {
stack.push(src.clone());
- src = TtIter::new(subtree);
+ src = subtree_iter;
}
None => {
if let Some(iter) = stack.pop() {
@@ -760,18 +771,16 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree<Span>, edition: Edition)
}
}
-fn match_meta_var(
+fn match_meta_var<'t>(
kind: MetaVarKind,
- input: &mut TtIter<'_, Span>,
+ input: &mut TtIter<'t, Span>,
delim_span: DelimSpan<Span>,
edition: Edition,
-) -> ExpandResult<Option<Fragment>> {
+) -> ExpandResult<Fragment<'t>> {
let fragment = match kind {
MetaVarKind::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)
- });
+ .map(Fragment::Path);
}
MetaVarKind::Expr(expr) => {
// `expr_2021` should not match underscores, let expressions, or inline const.
@@ -782,8 +791,8 @@ fn match_meta_var(
// rustc [explicitly checks the next token][1].
// [0]: https://github.com/rust-lang/rust/issues/86730
// [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))) => {
+ match input.peek() {
+ Some(TtElement::Leaf(tt::Leaf::Ident(it))) => {
let is_err = if it.is_raw.no() && matches!(expr, ExprKind::Expr2021) {
it.sym == sym::underscore || it.sym == sym::let_ || it.sym == sym::const_
} else {
@@ -799,34 +808,15 @@ fn match_meta_var(
_ => {}
};
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
- }
- })
- .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(
- span.unwrap_or(delim_span.close),
- "expected ident",
- )
- }),
+ let savepoint = input.savepoint();
+ let err = match kind {
+ MetaVarKind::Ident => input.expect_ident().map(drop).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),
@@ -840,29 +830,19 @@ fn match_meta_var(
)
}),
MetaVarKind::Literal => {
- let neg = eat_char(input, '-');
- input
- .expect_literal()
- .map(|literal| {
- let lit = literal.clone();
- match neg {
- None => lit.into(),
- Some(neg) => tt::TokenTree::Subtree(tt::Subtree {
- delimiter: tt::Delimiter::invisible_spanned(*literal.span()),
- token_trees: Box::new([neg, lit.into()]),
- }),
- }
- })
- .map_err(|()| {
- ExpandError::binding_error(
- span.unwrap_or(delim_span.close),
- "expected literal",
- )
- })
+ eat_char(input, '-');
+ input.expect_literal().map(drop).map_err(|()| {
+ ExpandError::binding_error(
+ span.unwrap_or(delim_span.close),
+ "expected literal",
+ )
+ })
}
_ => unreachable!(),
- };
- return tt_result.map(|it| Some(Fragment::Tokens(it))).into();
+ }
+ .err();
+ let tt_result = input.from_savepoint(savepoint);
+ return ValueResult { value: Fragment::Tokens(tt_result), err };
}
MetaVarKind::Ty => parser::PrefixEntryPoint::Ty,
MetaVarKind::Pat => parser::PrefixEntryPoint::PatTop,
@@ -873,7 +853,7 @@ fn match_meta_var(
MetaVarKind::Item => parser::PrefixEntryPoint::Item,
MetaVarKind::Vis => parser::PrefixEntryPoint::Vis,
};
- expect_fragment(input, fragment, edition, delim_span).map(|it| it.map(Fragment::Tokens))
+ expect_fragment(input, fragment, edition, delim_span).map(Fragment::Tokens)
}
fn collect_vars(collector_fun: &mut impl FnMut(Symbol), pattern: &MetaTemplate) {
@@ -990,54 +970,31 @@ fn expect_separator<S: Copy>(iter: &mut TtIter<'_, S>, separator: &Separator) ->
ok
}
-fn expect_tt<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<tt::TokenTree<S>, ()> {
- if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = iter.peek_n(0) {
+fn expect_tt<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<(), ()> {
+ if let Some(TtElement::Leaf(tt::Leaf::Punct(punct))) = iter.peek() {
if punct.char == '\'' {
- expect_lifetime(iter)
+ expect_lifetime(iter)?;
} else {
- let puncts = iter.expect_glued_punct()?;
- let delimiter = tt::Delimiter {
- open: puncts.first().unwrap().span,
- close: puncts.last().unwrap().span,
- kind: tt::DelimiterKind::Invisible,
- };
- let token_trees = puncts.into_iter().map(|p| tt::Leaf::Punct(p).into()).collect();
- Ok(tt::TokenTree::Subtree(tt::Subtree { delimiter, token_trees }))
+ iter.expect_glued_punct()?;
}
} else {
- iter.next().ok_or(()).cloned()
+ iter.next().ok_or(())?;
}
+ Ok(())
}
-fn expect_lifetime<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<tt::TokenTree<S>, ()> {
+fn expect_lifetime<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<(), ()> {
let punct = iter.expect_single_punct()?;
if punct.char != '\'' {
return Err(());
}
- let ident = iter.expect_ident_or_underscore()?;
-
- Ok(tt::Subtree {
- delimiter: tt::Delimiter {
- open: punct.span,
- close: ident.span,
- kind: tt::DelimiterKind::Invisible,
- },
- token_trees: Box::new([
- tt::Leaf::Punct(*punct).into(),
- tt::Leaf::Ident(ident.clone()).into(),
- ]),
- }
- .into())
+ iter.expect_ident_or_underscore()?;
+ Ok(())
}
-fn eat_char<S: Copy>(iter: &mut TtIter<'_, S>, c: char) -> Option<tt::TokenTree<S>> {
- let mut fork = iter.clone();
- match fork.expect_char(c) {
- Ok(_) => {
- let tt = iter.next().cloned();
- *iter = fork;
- tt
- }
- Err(_) => None,
+fn eat_char<S: Copy>(iter: &mut TtIter<'_, S>, c: char) {
+ if matches!(iter.peek(), Some(TtElement::Leaf(tt::Leaf::Punct(tt::Punct { char, .. }))) if *char == c)
+ {
+ iter.next().expect("already peeked");
}
}