Skip to content

Commit a7d4114

Browse files
committed
mbe: handle multi-character separator
1 parent 767351f commit a7d4114

File tree

3 files changed

+26
-32
lines changed

3 files changed

+26
-32
lines changed

crates/mbe/src/expander/matcher.rs

+24-18
Original file line numberDiff line numberDiff line change
@@ -321,8 +321,8 @@ struct MatchState<'t> {
321321
/// The KleeneOp of this sequence if we are in a repetition.
322322
sep_kind: Option<RepeatKind>,
323323

324-
/// Number of tokens of separator parsed
325-
sep_parsed: Option<usize>,
324+
/// Whether we already matched separator token.
325+
sep_matched: bool,
326326

327327
/// Matched meta variables bindings
328328
bindings: BindingsIdx,
@@ -387,7 +387,7 @@ fn match_loop_inner<'t>(
387387
None => {
388388
// We are at or past the end of the matcher of `item`.
389389
if let Some(up) = &item.up {
390-
if item.sep_parsed.is_none() {
390+
if !item.sep_matched {
391391
// Get the `up` matcher
392392
let mut new_pos = (**up).clone();
393393
new_pos.bindings = bindings_builder.copy(&new_pos.bindings);
@@ -401,22 +401,25 @@ fn match_loop_inner<'t>(
401401
}
402402

403403
// Check if we need a separator.
404-
// We check the separator one by one
405-
let sep_idx = item.sep_parsed.unwrap_or(0);
406-
let sep_len = item.sep.as_ref().map_or(0, Separator::tt_count);
407-
if item.sep.is_some() && sep_idx != sep_len {
404+
if item.sep.is_some() && !item.sep_matched {
408405
let sep = item.sep.as_ref().unwrap();
409-
if src.clone().expect_separator(sep, sep_idx) {
406+
let mut fork = src.clone();
407+
if fork.expect_separator(sep) {
408+
// HACK: here we use `meta_result` to pass `TtIter` back to caller because
409+
// it might have been advanced multiple times. `ValueResult` is
410+
// insignificant.
411+
item.meta_result = Some((fork, ValueResult::ok(None)));
410412
item.dot.next();
411-
item.sep_parsed = Some(sep_idx + 1);
413+
// item.sep_parsed = Some(sep_len);
414+
item.sep_matched = true;
412415
try_push!(next_items, item);
413416
}
414417
}
415418
// We don't need a separator. Move the "dot" back to the beginning of the matcher
416419
// and try to match again UNLESS we are only allowed to have _one_ repetition.
417420
else if item.sep_kind != Some(RepeatKind::ZeroOrOne) {
418421
item.dot = item.dot.reset();
419-
item.sep_parsed = None;
422+
item.sep_matched = false;
420423
bindings_builder.push_default(&mut item.bindings);
421424
cur_items.push(item);
422425
}
@@ -451,7 +454,7 @@ fn match_loop_inner<'t>(
451454
up: Some(Box::new(item)),
452455
sep: separator.clone(),
453456
sep_kind: Some(*kind),
454-
sep_parsed: None,
457+
sep_matched: false,
455458
bindings: bindings_builder.alloc(),
456459
meta_result: None,
457460
is_error: false,
@@ -592,7 +595,7 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
592595
up: None,
593596
sep: None,
594597
sep_kind: None,
595-
sep_parsed: None,
598+
sep_matched: false,
596599
bindings: bindings_builder.alloc(),
597600
is_error: false,
598601
meta_result: None,
@@ -864,26 +867,29 @@ impl<'a> Iterator for OpDelimitedIter<'a> {
864867
}
865868

866869
impl<'a> TtIter<'a> {
867-
fn expect_separator(&mut self, separator: &Separator, idx: usize) -> bool {
870+
fn expect_separator(&mut self, separator: &Separator) -> bool {
868871
let mut fork = self.clone();
869872
let ok = match separator {
870-
Separator::Ident(lhs) if idx == 0 => match fork.expect_ident_or_underscore() {
873+
Separator::Ident(lhs) => match fork.expect_ident_or_underscore() {
871874
Ok(rhs) => rhs.text == lhs.text,
872875
Err(_) => false,
873876
},
874-
Separator::Literal(lhs) if idx == 0 => match fork.expect_literal() {
877+
Separator::Literal(lhs) => match fork.expect_literal() {
875878
Ok(rhs) => match rhs {
876879
tt::Leaf::Literal(rhs) => rhs.text == lhs.text,
877880
tt::Leaf::Ident(rhs) => rhs.text == lhs.text,
878881
tt::Leaf::Punct(_) => false,
879882
},
880883
Err(_) => false,
881884
},
882-
Separator::Puncts(lhss) if idx < lhss.len() => match fork.expect_single_punct() {
883-
Ok(rhs) => rhs.char == lhss[idx].char,
885+
Separator::Puncts(lhs) => match fork.expect_glued_punct() {
886+
Ok(rhs) => {
887+
let lhs = lhs.iter().map(|it| it.char);
888+
let rhs = rhs.iter().map(|it| it.char);
889+
lhs.eq(rhs)
890+
}
884891
Err(_) => false,
885892
},
886-
_ => false,
887893
};
888894
if ok {
889895
*self = fork;

crates/mbe/src/parser.rs

-10
Original file line numberDiff line numberDiff line change
@@ -110,16 +110,6 @@ impl PartialEq for Separator {
110110
}
111111
}
112112

113-
impl Separator {
114-
pub(crate) fn tt_count(&self) -> usize {
115-
match self {
116-
Separator::Literal(_) => 1,
117-
Separator::Ident(_) => 1,
118-
Separator::Puncts(it) => it.len(),
119-
}
120-
}
121-
}
122-
123113
#[derive(Clone, Copy)]
124114
enum Mode {
125115
Pattern,

crates/mbe/src/tt_iter.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,9 @@ impl<'a> TtIter<'a> {
112112

113113
match (first.char, second.char, third.map(|it| it.char)) {
114114
('.', '.', Some('.' | '=')) | ('<', '<', Some('=')) | ('>', '>', Some('=')) => {
115-
let puncts = smallvec![first, second.clone(), third.unwrap().clone()];
116115
let _ = self.next().unwrap();
117116
let _ = self.next().unwrap();
118-
Ok(puncts)
117+
Ok(smallvec![first, second.clone(), third.unwrap().clone()])
119118
}
120119
('-' | '!' | '*' | '/' | '&' | '%' | '^' | '+' | '<' | '=' | '>' | '|', '=', _)
121120
| ('-' | '=' | '>', '>', _)
@@ -125,9 +124,8 @@ impl<'a> TtIter<'a> {
125124
| ('&', '&', _)
126125
| ('<', '<', _)
127126
| ('|', '|', _) => {
128-
let puncts = smallvec![first, second.clone()];
129127
let _ = self.next().unwrap();
130-
Ok(puncts)
128+
Ok(smallvec![first, second.clone()])
131129
}
132130
_ => Ok(smallvec![first]),
133131
}

0 commit comments

Comments
 (0)