Refactor `Frame`.

It is currently an enum and the `tts` and `idx` fields are repeated
across the two variants.

This commit splits it into a struct `Frame` and an enum `FrameKind`, to
factor out the duplication. The commit also renames `Frame::new` as
`Frame::new_delimited` and adds `Frame::new_sequence`. I.e. both
variants now have a constructor.
This commit is contained in:
Nicholas Nethercote 2024-05-02 10:35:23 +10:00
parent 5ac017e772
commit 3a3a15d753
1 changed files with 50 additions and 48 deletions

View File

@ -39,26 +39,32 @@ impl MutVisitor for Marker {
} }
/// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`). /// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`).
enum Frame<'a> { struct Frame<'a> {
Delimited { tts: &'a [mbe::TokenTree],
tts: &'a [mbe::TokenTree], idx: usize,
idx: usize, kind: FrameKind,
delim: Delimiter, }
span: DelimSpan,
spacing: DelimSpacing, enum FrameKind {
}, Delimited { delim: Delimiter, span: DelimSpan, spacing: DelimSpacing },
Sequence { Sequence { sep: Option<Token>, kleene_op: KleeneOp },
tts: &'a [mbe::TokenTree],
idx: usize,
sep: Option<Token>,
kleene_op: KleeneOp,
},
} }
impl<'a> Frame<'a> { impl<'a> Frame<'a> {
/// Construct a new frame around the delimited set of tokens. fn new_delimited(src: &'a mbe::Delimited, span: DelimSpan, spacing: DelimSpacing) -> Frame<'a> {
fn new(src: &'a mbe::Delimited, span: DelimSpan, spacing: DelimSpacing) -> Frame<'a> { Frame {
Frame::Delimited { tts: &src.tts, idx: 0, delim: src.delim, span, spacing } tts: &src.tts,
idx: 0,
kind: FrameKind::Delimited { delim: src.delim, span, spacing },
}
}
fn new_sequence(
src: &'a mbe::SequenceRepetition,
sep: Option<Token>,
kleene_op: KleeneOp,
) -> Frame<'a> {
Frame { tts: &src.tts, idx: 0, kind: FrameKind::Sequence { sep, kleene_op } }
} }
} }
@ -66,13 +72,9 @@ impl<'a> Iterator for Frame<'a> {
type Item = &'a mbe::TokenTree; type Item = &'a mbe::TokenTree;
fn next(&mut self) -> Option<&'a mbe::TokenTree> { fn next(&mut self) -> Option<&'a mbe::TokenTree> {
match self { let res = self.tts.get(self.idx);
Frame::Delimited { tts, idx, .. } | Frame::Sequence { tts, idx, .. } => { self.idx += 1;
let res = tts.get(*idx); res
*idx += 1;
res
}
}
} }
} }
@ -111,8 +113,11 @@ pub(super) fn transcribe<'a>(
// We descend into the RHS (`src`), expanding things as we go. This stack contains the things // We descend into the RHS (`src`), expanding things as we go. This stack contains the things
// we have yet to expand/are still expanding. We start the stack off with the whole RHS. The // we have yet to expand/are still expanding. We start the stack off with the whole RHS. The
// choice of spacing values doesn't matter. // choice of spacing values doesn't matter.
let mut stack: SmallVec<[Frame<'_>; 1]> = let mut stack: SmallVec<[Frame<'_>; 1]> = smallvec![Frame::new_delimited(
smallvec![Frame::new(src, src_span, DelimSpacing::new(Spacing::Alone, Spacing::Alone))]; src,
src_span,
DelimSpacing::new(Spacing::Alone, Spacing::Alone)
)];
// As we descend in the RHS, we will need to be able to match nested sequences of matchers. // As we descend in the RHS, we will need to be able to match nested sequences of matchers.
// `repeats` keeps track of where we are in matching at each level, with the last element being // `repeats` keeps track of where we are in matching at each level, with the last element being
@ -142,11 +147,12 @@ pub(super) fn transcribe<'a>(
// Otherwise, if we have just reached the end of a sequence and we can keep repeating, // Otherwise, if we have just reached the end of a sequence and we can keep repeating,
// go back to the beginning of the sequence. // go back to the beginning of the sequence.
if let Frame::Sequence { idx, sep, .. } = stack.last_mut().unwrap() { let frame = stack.last_mut().unwrap();
if let FrameKind::Sequence { sep, .. } = &frame.kind {
let (repeat_idx, repeat_len) = repeats.last_mut().unwrap(); let (repeat_idx, repeat_len) = repeats.last_mut().unwrap();
*repeat_idx += 1; *repeat_idx += 1;
if repeat_idx < repeat_len { if repeat_idx < repeat_len {
*idx = 0; frame.idx = 0;
if let Some(sep) = sep { if let Some(sep) = sep {
result.push(TokenTree::Token(sep.clone(), Spacing::Alone)); result.push(TokenTree::Token(sep.clone(), Spacing::Alone));
} }
@ -157,16 +163,16 @@ pub(super) fn transcribe<'a>(
// We are done with the top of the stack. Pop it. Depending on what it was, we do // We are done with the top of the stack. Pop it. Depending on what it was, we do
// different things. Note that the outermost item must be the delimited, wrapped RHS // different things. Note that the outermost item must be the delimited, wrapped RHS
// that was passed in originally to `transcribe`. // that was passed in originally to `transcribe`.
match stack.pop().unwrap() { match stack.pop().unwrap().kind {
// Done with a sequence. Pop from repeats. // Done with a sequence. Pop from repeats.
Frame::Sequence { .. } => { FrameKind::Sequence { .. } => {
repeats.pop(); repeats.pop();
} }
// We are done processing a Delimited. If this is the top-level delimited, we are // We are done processing a Delimited. If this is the top-level delimited, we are
// done. Otherwise, we unwind the result_stack to append what we have produced to // done. Otherwise, we unwind the result_stack to append what we have produced to
// any previous results. // any previous results.
Frame::Delimited { delim, span, mut spacing, .. } => { FrameKind::Delimited { delim, span, mut spacing, .. } => {
// Hack to force-insert a space after `]` in certain case. // Hack to force-insert a space after `]` in certain case.
// See discussion of the `hex-literal` crate in #114571. // See discussion of the `hex-literal` crate in #114571.
if delim == Delimiter::Bracket { if delim == Delimiter::Bracket {
@ -192,7 +198,7 @@ pub(super) fn transcribe<'a>(
// We are descending into a sequence. We first make sure that the matchers in the RHS // We are descending into a sequence. We first make sure that the matchers in the RHS
// and the matches in `interp` have the same shape. Otherwise, either the caller or the // and the matches in `interp` have the same shape. Otherwise, either the caller or the
// macro writer has made a mistake. // macro writer has made a mistake.
seq @ mbe::TokenTree::Sequence(_, delimited) => { seq @ mbe::TokenTree::Sequence(_, seq_rep) => {
match lockstep_iter_size(seq, interp, &repeats) { match lockstep_iter_size(seq, interp, &repeats) {
LockstepIterSize::Unconstrained => { LockstepIterSize::Unconstrained => {
return Err(cx return Err(cx
@ -233,12 +239,11 @@ pub(super) fn transcribe<'a>(
// The first time we encounter the sequence we push it to the stack. It // The first time we encounter the sequence we push it to the stack. It
// then gets reused (see the beginning of the loop) until we are done // then gets reused (see the beginning of the loop) until we are done
// repeating. // repeating.
stack.push(Frame::Sequence { stack.push(Frame::new_sequence(
idx: 0, seq_rep,
sep: seq.separator.clone(), seq.separator.clone(),
tts: &delimited.tts, seq.kleene.op,
kleene_op: seq.kleene.op, ));
});
} }
} }
} }
@ -294,13 +299,7 @@ pub(super) fn transcribe<'a>(
// the previous results (from outside the Delimited). // the previous results (from outside the Delimited).
mbe::TokenTree::Delimited(mut span, spacing, delimited) => { mbe::TokenTree::Delimited(mut span, spacing, delimited) => {
mut_visit::visit_delim_span(&mut span, &mut marker); mut_visit::visit_delim_span(&mut span, &mut marker);
stack.push(Frame::Delimited { stack.push(Frame::new_delimited(delimited, span, *spacing));
tts: &delimited.tts,
delim: delimited.delim,
idx: 0,
span,
spacing: *spacing,
});
result_stack.push(mem::take(&mut result)); result_stack.push(mem::take(&mut result));
} }
@ -358,10 +357,13 @@ fn maybe_use_metavar_location(
) -> TokenTree { ) -> TokenTree {
let undelimited_seq = matches!( let undelimited_seq = matches!(
stack.last(), stack.last(),
Some(Frame::Sequence { Some(Frame {
tts: [_], tts: [_],
sep: None, kind: FrameKind::Sequence {
kleene_op: KleeneOp::ZeroOrMore | KleeneOp::OneOrMore, sep: None,
kleene_op: KleeneOp::ZeroOrMore | KleeneOp::OneOrMore,
..
},
.. ..
}) })
); );