Skip to content

Commit

Permalink
Refactor Frame.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nnethercote committed May 2, 2024
1 parent 5ac017e commit 3a3a15d
Showing 1 changed file with 50 additions and 48 deletions.
98 changes: 50 additions & 48 deletions compiler/rustc_expand/src/mbe/transcribe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,40 +39,42 @@ impl MutVisitor for Marker {
}

/// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`).
enum Frame<'a> {
Delimited {
tts: &'a [mbe::TokenTree],
idx: usize,
delim: Delimiter,
span: DelimSpan,
spacing: DelimSpacing,
},
Sequence {
tts: &'a [mbe::TokenTree],
idx: usize,
sep: Option<Token>,
kleene_op: KleeneOp,
},
struct Frame<'a> {
tts: &'a [mbe::TokenTree],
idx: usize,
kind: FrameKind,
}

enum FrameKind {
Delimited { delim: Delimiter, span: DelimSpan, spacing: DelimSpacing },
Sequence { sep: Option<Token>, kleene_op: KleeneOp },
}

impl<'a> Frame<'a> {
/// Construct a new frame around the delimited set of tokens.
fn new(src: &'a mbe::Delimited, span: DelimSpan, spacing: DelimSpacing) -> Frame<'a> {
Frame::Delimited { tts: &src.tts, idx: 0, delim: src.delim, span, spacing }
fn new_delimited(src: &'a mbe::Delimited, span: DelimSpan, spacing: DelimSpacing) -> Frame<'a> {
Frame {
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 } }
}
}

impl<'a> Iterator for Frame<'a> {
type Item = &'a mbe::TokenTree;

fn next(&mut self) -> Option<&'a mbe::TokenTree> {
match self {
Frame::Delimited { tts, idx, .. } | Frame::Sequence { tts, idx, .. } => {
let res = tts.get(*idx);
*idx += 1;
res
}
}
let res = self.tts.get(self.idx);
self.idx += 1;
res
}
}

Expand Down Expand Up @@ -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 have yet to expand/are still expanding. We start the stack off with the whole RHS. The
// choice of spacing values doesn't matter.
let mut stack: SmallVec<[Frame<'_>; 1]> =
smallvec![Frame::new(src, src_span, DelimSpacing::new(Spacing::Alone, Spacing::Alone))];
let mut stack: SmallVec<[Frame<'_>; 1]> = smallvec![Frame::new_delimited(
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.
// `repeats` keeps track of where we are in matching at each level, with the last element being
Expand Down Expand Up @@ -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,
// 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();
*repeat_idx += 1;
if repeat_idx < repeat_len {
*idx = 0;
frame.idx = 0;
if let Some(sep) = sep {
result.push(TokenTree::Token(sep.clone(), Spacing::Alone));
}
Expand All @@ -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
// different things. Note that the outermost item must be the delimited, wrapped RHS
// that was passed in originally to `transcribe`.
match stack.pop().unwrap() {
match stack.pop().unwrap().kind {
// Done with a sequence. Pop from repeats.
Frame::Sequence { .. } => {
FrameKind::Sequence { .. } => {
repeats.pop();
}

// 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
// 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.
// See discussion of the `hex-literal` crate in #114571.
if delim == Delimiter::Bracket {
Expand All @@ -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
// and the matches in `interp` have the same shape. Otherwise, either the caller or the
// macro writer has made a mistake.
seq @ mbe::TokenTree::Sequence(_, delimited) => {
seq @ mbe::TokenTree::Sequence(_, seq_rep) => {
match lockstep_iter_size(seq, interp, &repeats) {
LockstepIterSize::Unconstrained => {
return Err(cx
Expand Down Expand Up @@ -233,12 +239,11 @@ pub(super) fn transcribe<'a>(
// 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
// repeating.
stack.push(Frame::Sequence {
idx: 0,
sep: seq.separator.clone(),
tts: &delimited.tts,
kleene_op: seq.kleene.op,
});
stack.push(Frame::new_sequence(
seq_rep,
seq.separator.clone(),
seq.kleene.op,
));
}
}
}
Expand Down Expand Up @@ -294,13 +299,7 @@ pub(super) fn transcribe<'a>(
// the previous results (from outside the Delimited).
mbe::TokenTree::Delimited(mut span, spacing, delimited) => {
mut_visit::visit_delim_span(&mut span, &mut marker);
stack.push(Frame::Delimited {
tts: &delimited.tts,
delim: delimited.delim,
idx: 0,
span,
spacing: *spacing,
});
stack.push(Frame::new_delimited(delimited, span, *spacing));
result_stack.push(mem::take(&mut result));
}

Expand Down Expand Up @@ -358,10 +357,13 @@ fn maybe_use_metavar_location(
) -> TokenTree {
let undelimited_seq = matches!(
stack.last(),
Some(Frame::Sequence {
Some(Frame {
tts: [_],
sep: None,
kleene_op: KleeneOp::ZeroOrMore | KleeneOp::OneOrMore,
kind: FrameKind::Sequence {
sep: None,
kleene_op: KleeneOp::ZeroOrMore | KleeneOp::OneOrMore,
..
},
..
})
);
Expand Down

0 comments on commit 3a3a15d

Please sign in to comment.