Remove `ext::tt::transcribe::tt_next_token`.
This commit is contained in:
parent
abdc68973e
commit
8c4960bfde
|
@ -7,7 +7,6 @@
|
|||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
use self::LockstepIterSize::*;
|
||||
|
||||
use ast::Ident;
|
||||
use errors::Handler;
|
||||
|
@ -41,6 +40,13 @@ enum Frame {
|
|||
},
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
fn new(tts: Vec<TokenTree>) -> Frame {
|
||||
let forest = Rc::new(tokenstream::Delimited { delim: token::NoDelim, tts: tts });
|
||||
Frame::Delimited { forest: forest, idx: 0, span: DUMMY_SP }
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Frame {
|
||||
type Item = TokenTree;
|
||||
|
||||
|
@ -75,17 +81,6 @@ impl Iterator for Frame {
|
|||
}
|
||||
}
|
||||
|
||||
struct TtReader<'a> {
|
||||
sp_diag: &'a Handler,
|
||||
/// the unzipped tree:
|
||||
stack: SmallVector<Frame>,
|
||||
/* for MBE-style macro transcription */
|
||||
interpolations: HashMap<Ident, Rc<NamedMatch>>,
|
||||
|
||||
repeat_idx: Vec<usize>,
|
||||
repeat_len: Vec<usize>,
|
||||
}
|
||||
|
||||
/// This can do Macro-By-Example transcription. On the other hand, if
|
||||
/// `src` contains no `TokenTree::Sequence`s, `MatchNt`s or `SubstNt`s, `interp` can
|
||||
/// (and should) be None.
|
||||
|
@ -93,125 +88,35 @@ pub fn transcribe(sp_diag: &Handler,
|
|||
interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
|
||||
src: Vec<tokenstream::TokenTree>)
|
||||
-> Vec<TokenTree> {
|
||||
let mut r = TtReader {
|
||||
sp_diag: sp_diag,
|
||||
stack: SmallVector::one(Frame::Delimited {
|
||||
forest: Rc::new(tokenstream::Delimited { delim: token::NoDelim, tts: src }),
|
||||
idx: 0,
|
||||
span: DUMMY_SP,
|
||||
}),
|
||||
interpolations: match interp { /* just a convenience */
|
||||
None => HashMap::new(),
|
||||
Some(x) => x,
|
||||
},
|
||||
repeat_idx: Vec::new(),
|
||||
repeat_len: Vec::new(),
|
||||
};
|
||||
let mut stack = SmallVector::one(Frame::new(src));
|
||||
let interpolations = interp.unwrap_or_else(HashMap::new); /* just a convenience */
|
||||
let mut repeat_idx = Vec::new();
|
||||
let mut repeat_len = Vec::new();
|
||||
let mut result = Vec::new();
|
||||
|
||||
let mut tts = Vec::new();
|
||||
let mut prev_span = DUMMY_SP;
|
||||
while let Some(tt) = tt_next_token(&mut r, prev_span) {
|
||||
prev_span = tt.span();
|
||||
tts.push(tt);
|
||||
}
|
||||
tts
|
||||
}
|
||||
|
||||
fn lookup_cur_matched_by_matched(r: &TtReader, start: Rc<NamedMatch>) -> Rc<NamedMatch> {
|
||||
r.repeat_idx.iter().fold(start, |ad, idx| {
|
||||
match *ad {
|
||||
MatchedNonterminal(_) => {
|
||||
// end of the line; duplicate henceforth
|
||||
ad.clone()
|
||||
}
|
||||
MatchedSeq(ref ads, _) => ads[*idx].clone()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn lookup_cur_matched(r: &TtReader, name: Ident) -> Option<Rc<NamedMatch>> {
|
||||
let matched_opt = r.interpolations.get(&name).cloned();
|
||||
matched_opt.map(|s| lookup_cur_matched_by_matched(r, s))
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum LockstepIterSize {
|
||||
LisUnconstrained,
|
||||
LisConstraint(usize, Ident),
|
||||
LisContradiction(String),
|
||||
}
|
||||
|
||||
impl Add for LockstepIterSize {
|
||||
type Output = LockstepIterSize;
|
||||
|
||||
fn add(self, other: LockstepIterSize) -> LockstepIterSize {
|
||||
match self {
|
||||
LisUnconstrained => other,
|
||||
LisContradiction(_) => self,
|
||||
LisConstraint(l_len, ref l_id) => match other {
|
||||
LisUnconstrained => self.clone(),
|
||||
LisContradiction(_) => other,
|
||||
LisConstraint(r_len, _) if l_len == r_len => self.clone(),
|
||||
LisConstraint(r_len, r_id) => {
|
||||
LisContradiction(format!("inconsistent lockstep iteration: \
|
||||
'{}' has {} items, but '{}' has {}",
|
||||
l_id, l_len, r_id, r_len))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lockstep_iter_size(t: &TokenTree, r: &TtReader) -> LockstepIterSize {
|
||||
match *t {
|
||||
TokenTree::Delimited(_, ref delimed) => {
|
||||
delimed.tts.iter().fold(LisUnconstrained, |size, tt| {
|
||||
size + lockstep_iter_size(tt, r)
|
||||
})
|
||||
},
|
||||
TokenTree::Sequence(_, ref seq) => {
|
||||
seq.tts.iter().fold(LisUnconstrained, |size, tt| {
|
||||
size + lockstep_iter_size(tt, r)
|
||||
})
|
||||
},
|
||||
TokenTree::Token(_, SubstNt(name)) | TokenTree::Token(_, MatchNt(name, _)) =>
|
||||
match lookup_cur_matched(r, name) {
|
||||
Some(matched) => match *matched {
|
||||
MatchedNonterminal(_) => LisUnconstrained,
|
||||
MatchedSeq(ref ads, _) => LisConstraint(ads.len(), name),
|
||||
},
|
||||
_ => LisUnconstrained
|
||||
},
|
||||
TokenTree::Token(..) => LisUnconstrained,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the next token from the TtReader.
|
||||
/// EFFECT: advances the reader's token field
|
||||
fn tt_next_token(r: &mut TtReader, prev_span: Span) -> Option<TokenTree> {
|
||||
loop {
|
||||
let tree = match r.stack.last_mut() {
|
||||
Some(frame) => frame.next(),
|
||||
None => return None,
|
||||
};
|
||||
|
||||
let tree = if let Some(tree) = tree {
|
||||
let tree = if let Some(tree) = stack.last_mut().unwrap().next() {
|
||||
tree
|
||||
} else {
|
||||
if let Frame::Sequence { ref mut idx, ref sep, .. } = *r.stack.last_mut().unwrap() {
|
||||
if *r.repeat_idx.last().unwrap() < *r.repeat_len.last().unwrap() - 1 {
|
||||
*r.repeat_idx.last_mut().unwrap() += 1;
|
||||
if let Frame::Sequence { ref mut idx, ref sep, .. } = *stack.last_mut().unwrap() {
|
||||
if *repeat_idx.last().unwrap() < *repeat_len.last().unwrap() - 1 {
|
||||
*repeat_idx.last_mut().unwrap() += 1;
|
||||
*idx = 0;
|
||||
if let Some(sep) = sep.clone() {
|
||||
return Some(TokenTree::Token(prev_span, sep)); // repeat same span, I guess
|
||||
// repeat same span, I guess
|
||||
let prev_span = result.last().map(TokenTree::span).unwrap_or(DUMMY_SP);
|
||||
result.push(TokenTree::Token(prev_span, sep));
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if let Frame::Sequence { .. } = r.stack.pop().unwrap() {
|
||||
r.repeat_idx.pop();
|
||||
r.repeat_len.pop();
|
||||
if let Frame::Sequence { .. } = stack.pop().unwrap() {
|
||||
repeat_idx.pop();
|
||||
repeat_len.pop();
|
||||
}
|
||||
if stack.is_empty() {
|
||||
return result;
|
||||
}
|
||||
continue
|
||||
};
|
||||
|
@ -220,73 +125,143 @@ fn tt_next_token(r: &mut TtReader, prev_span: Span) -> Option<TokenTree> {
|
|||
TokenTree::Sequence(sp, seq) => {
|
||||
// FIXME(pcwalton): Bad copy.
|
||||
match lockstep_iter_size(&TokenTree::Sequence(sp, seq.clone()),
|
||||
r) {
|
||||
LisUnconstrained => {
|
||||
panic!(r.sp_diag.span_fatal(
|
||||
&interpolations,
|
||||
&repeat_idx) {
|
||||
LockstepIterSize::Unconstrained => {
|
||||
panic!(sp_diag.span_fatal(
|
||||
sp.clone(), /* blame macro writer */
|
||||
"attempted to repeat an expression \
|
||||
containing no syntax \
|
||||
variables matched as repeating at this depth"));
|
||||
}
|
||||
LisContradiction(ref msg) => {
|
||||
LockstepIterSize::Contradiction(ref msg) => {
|
||||
// FIXME #2887 blame macro invoker instead
|
||||
panic!(r.sp_diag.span_fatal(sp.clone(), &msg[..]));
|
||||
panic!(sp_diag.span_fatal(sp.clone(), &msg[..]));
|
||||
}
|
||||
LisConstraint(len, _) => {
|
||||
LockstepIterSize::Constraint(len, _) => {
|
||||
if len == 0 {
|
||||
if seq.op == tokenstream::KleeneOp::OneOrMore {
|
||||
// FIXME #2887 blame invoker
|
||||
panic!(r.sp_diag.span_fatal(sp.clone(),
|
||||
"this must repeat at least once"));
|
||||
panic!(sp_diag.span_fatal(sp.clone(),
|
||||
"this must repeat at least once"));
|
||||
}
|
||||
|
||||
return tt_next_token(r, prev_span);
|
||||
} else {
|
||||
repeat_len.push(len);
|
||||
repeat_idx.push(0);
|
||||
stack.push(Frame::Sequence {
|
||||
idx: 0,
|
||||
sep: seq.separator.clone(),
|
||||
forest: seq,
|
||||
});
|
||||
}
|
||||
r.repeat_len.push(len);
|
||||
r.repeat_idx.push(0);
|
||||
r.stack.push(Frame::Sequence {
|
||||
idx: 0,
|
||||
sep: seq.separator.clone(),
|
||||
forest: seq,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// FIXME #2887: think about span stuff here
|
||||
TokenTree::Token(sp, SubstNt(ident)) => {
|
||||
match lookup_cur_matched(r, ident) {
|
||||
None => {
|
||||
return Some(TokenTree::Token(sp, SubstNt(ident)));
|
||||
// this can't be 0 length, just like TokenTree::Delimited
|
||||
}
|
||||
match lookup_cur_matched(ident, &interpolations, &repeat_idx) {
|
||||
None => result.push(TokenTree::Token(sp, SubstNt(ident))),
|
||||
Some(cur_matched) => if let MatchedNonterminal(ref nt) = *cur_matched {
|
||||
match **nt {
|
||||
// sidestep the interpolation tricks for ident because
|
||||
// (a) idents can be in lots of places, so it'd be a pain
|
||||
// (b) we actually can, since it's a token.
|
||||
NtIdent(ref sn) => {
|
||||
return Some(TokenTree::Token(sn.span, token::Ident(sn.node)));
|
||||
result.push(TokenTree::Token(sn.span, token::Ident(sn.node)));
|
||||
}
|
||||
NtTT(ref tt) => return Some(tt.clone()),
|
||||
NtTT(ref tt) => result.push(tt.clone()),
|
||||
_ => {
|
||||
// FIXME(pcwalton): Bad copy
|
||||
return Some(TokenTree::Token(sp, token::Interpolated(nt.clone())));
|
||||
result.push(TokenTree::Token(sp, token::Interpolated(nt.clone())));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!(r.sp_diag.span_fatal(
|
||||
panic!(sp_diag.span_fatal(
|
||||
sp, /* blame the macro writer */
|
||||
&format!("variable '{}' is still repeating at this depth", ident)));
|
||||
}
|
||||
}
|
||||
}
|
||||
TokenTree::Delimited(span, delimited) => {
|
||||
r.stack.push(Frame::Delimited { forest: delimited, idx: 0, span: span });
|
||||
stack.push(Frame::Delimited { forest: delimited, idx: 0, span: span });
|
||||
}
|
||||
TokenTree::Token(span, MatchNt(name, kind)) => {
|
||||
r.stack.push(Frame::MatchNt { name: name, kind: kind, idx: 0, span: span });
|
||||
stack.push(Frame::MatchNt { name: name, kind: kind, idx: 0, span: span });
|
||||
}
|
||||
tt @ TokenTree::Token(..) => return Some(tt),
|
||||
tt @ TokenTree::Token(..) => result.push(tt),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_cur_matched(ident: Ident,
|
||||
interpolations: &HashMap<Ident, Rc<NamedMatch>>,
|
||||
repeat_idx: &[usize])
|
||||
-> Option<Rc<NamedMatch>> {
|
||||
interpolations.get(&ident).map(|matched| {
|
||||
repeat_idx.iter().fold(matched.clone(), |ad, idx| {
|
||||
match *ad {
|
||||
MatchedNonterminal(_) => {
|
||||
// end of the line; duplicate henceforth
|
||||
ad.clone()
|
||||
}
|
||||
MatchedSeq(ref ads, _) => ads[*idx].clone()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum LockstepIterSize {
|
||||
Unconstrained,
|
||||
Constraint(usize, Ident),
|
||||
Contradiction(String),
|
||||
}
|
||||
|
||||
impl Add for LockstepIterSize {
|
||||
type Output = LockstepIterSize;
|
||||
|
||||
fn add(self, other: LockstepIterSize) -> LockstepIterSize {
|
||||
match self {
|
||||
LockstepIterSize::Unconstrained => other,
|
||||
LockstepIterSize::Contradiction(_) => self,
|
||||
LockstepIterSize::Constraint(l_len, ref l_id) => match other {
|
||||
LockstepIterSize::Unconstrained => self.clone(),
|
||||
LockstepIterSize::Contradiction(_) => other,
|
||||
LockstepIterSize::Constraint(r_len, _) if l_len == r_len => self.clone(),
|
||||
LockstepIterSize::Constraint(r_len, r_id) => {
|
||||
let msg = format!("inconsistent lockstep iteration: \
|
||||
'{}' has {} items, but '{}' has {}",
|
||||
l_id, l_len, r_id, r_len);
|
||||
LockstepIterSize::Contradiction(msg)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lockstep_iter_size(tree: &TokenTree,
|
||||
interpolations: &HashMap<Ident, Rc<NamedMatch>>,
|
||||
repeat_idx: &[usize])
|
||||
-> LockstepIterSize {
|
||||
match *tree {
|
||||
TokenTree::Delimited(_, ref delimed) => {
|
||||
delimed.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| {
|
||||
size + lockstep_iter_size(tt, interpolations, repeat_idx)
|
||||
})
|
||||
},
|
||||
TokenTree::Sequence(_, ref seq) => {
|
||||
seq.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| {
|
||||
size + lockstep_iter_size(tt, interpolations, repeat_idx)
|
||||
})
|
||||
},
|
||||
TokenTree::Token(_, SubstNt(name)) | TokenTree::Token(_, MatchNt(name, _)) =>
|
||||
match lookup_cur_matched(name, interpolations, repeat_idx) {
|
||||
Some(matched) => match *matched {
|
||||
MatchedNonterminal(_) => LockstepIterSize::Unconstrained,
|
||||
MatchedSeq(ref ads, _) => LockstepIterSize::Constraint(ads.len(), name),
|
||||
},
|
||||
_ => LockstepIterSize::Unconstrained
|
||||
},
|
||||
TokenTree::Token(..) => LockstepIterSize::Unconstrained,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue