Skip to content
This repository was archived by the owner on Mar 22, 2024. It is now read-only.

Commit 817eb66

Browse files
committed
fix OpMinUntil
1 parent f05f6cb commit 817eb66

File tree

1 file changed

+80
-20
lines changed

1 file changed

+80
-20
lines changed

interp.rs

Lines changed: 80 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,7 @@ pub(crate) fn search(
151151
// TODO: optimize by op info and skip prefix
152152
let end = std::cmp::min(end, string.char_len());
153153
for i in start..end {
154-
if let Some(m) = pymatch(
155-
string.clone(),
156-
i,
157-
end,
158-
pattern.clone(),
159-
) {
154+
if let Some(m) = pymatch(string.clone(), i, end, pattern.clone()) {
160155
return Some(m);
161156
}
162157
}
@@ -294,12 +289,13 @@ impl<'a> StackDrive<'a> {
294289
self.state
295290
}
296291
fn push_new_context(&mut self, pattern_offset: usize) {
297-
let ctx = self.ctx();
298-
let mut child_ctx = MatchContext { ..*ctx };
292+
let mut child_ctx = MatchContext { ..*self.ctx() };
299293
child_ctx.code_position += pattern_offset;
300-
if child_ctx.code_position > self.state.pattern_codes.len() {
301-
child_ctx.code_position = self.state.pattern_codes.len();
302-
}
294+
self.state.context_stack.push(child_ctx);
295+
}
296+
fn push_new_context_at(&mut self, code_position: usize) {
297+
let mut child_ctx = MatchContext { ..*self.ctx() };
298+
child_ctx.code_position = code_position;
303299
self.state.context_stack.push(child_ctx);
304300
}
305301
fn repeat_ctx_mut(&mut self) -> &mut RepeatContext {
@@ -571,6 +567,8 @@ impl OpcodeDispatcher {
571567
count: -1,
572568
code_position: drive.ctx().code_position,
573569
last_position: std::usize::MAX,
570+
mincount: drive.peek_code(2) as usize,
571+
maxcount: drive.peek_code(3) as usize,
574572
};
575573
drive.state.repeat_stack.push(repeat);
576574
drive.state.string_position = drive.ctx().string_position;
@@ -584,7 +582,7 @@ impl OpcodeDispatcher {
584582
},
585583
),
586584
SreOpcode::MAX_UNTIL => Box::new(OpMaxUntil::default()),
587-
SreOpcode::MIN_UNTIL => todo!("min until"),
585+
SreOpcode::MIN_UNTIL => Box::new(OpMinUntil::default()),
588586
SreOpcode::REPEAT_ONE => Box::new(OpRepeatOne::default()),
589587
SreOpcode::MIN_REPEAT_ONE => Box::new(OpMinRepeatOne::default()),
590588
SreOpcode::GROUPREF => once(|drive| general_op_groupref(drive, |x| x)),
@@ -996,6 +994,8 @@ struct RepeatContext {
996994
code_position: usize,
997995
// zero-width match protection
998996
last_position: usize,
997+
mincount: usize,
998+
maxcount: usize,
999999
}
10001000

10011001
struct OpMinRepeatOne {
@@ -1111,30 +1111,30 @@ impl OpcodeExecutor for OpMaxUntil {
11111111
count,
11121112
code_position,
11131113
last_position,
1114+
mincount,
1115+
maxcount,
11141116
} = *drive.repeat_ctx();
1115-
drive.ctx_mut().code_position = code_position;
1116-
let mincount = drive.peek_code(2) as usize;
1117-
let maxcount = drive.peek_code(3) as usize;
1117+
11181118
drive.state.string_position = drive.ctx().string_position;
11191119
self.count = count + 1;
11201120

11211121
if (self.count as usize) < mincount {
11221122
// not enough matches
11231123
drive.repeat_ctx_mut().count = self.count;
1124-
drive.push_new_context(4);
1124+
drive.push_new_context_at(code_position + 4);
11251125
self.jump_id = 1;
11261126
return Some(());
11271127
}
11281128

1129-
if ((count as usize) < maxcount || maxcount == MAXREPEAT)
1129+
if ((self.count as usize) < maxcount || maxcount == MAXREPEAT)
11301130
&& drive.state.string_position != last_position
11311131
{
11321132
// we may have enough matches, if we can match another item, do so
11331133
drive.repeat_ctx_mut().count = self.count;
11341134
drive.state.marks_push();
11351135
self.save_last_position = last_position;
11361136
drive.repeat_ctx_mut().last_position = drive.state.string_position;
1137-
drive.push_new_context(4);
1137+
drive.push_new_context_at(code_position + 4);
11381138
self.jump_id = 2;
11391139
return Some(());
11401140
}
@@ -1167,7 +1167,6 @@ impl OpcodeExecutor for OpMaxUntil {
11671167
}
11681168
3 => {
11691169
// cannot match more repeated items here. make sure the tail matches
1170-
drive.skip_code(drive.peek_code(1) as usize + 1);
11711170
drive.push_new_context(1);
11721171
self.jump_id = 4;
11731172
Some(())
@@ -1188,18 +1187,79 @@ impl OpcodeExecutor for OpMaxUntil {
11881187
struct OpMinUntil {
11891188
jump_id: usize,
11901189
count: isize,
1190+
save_repeat: Option<RepeatContext>,
11911191
}
11921192
impl Default for OpMinUntil {
11931193
fn default() -> Self {
11941194
Self {
11951195
jump_id: 0,
11961196
count: 0,
1197+
save_repeat: None,
11971198
}
11981199
}
11991200
}
12001201
impl OpcodeExecutor for OpMinUntil {
12011202
fn next(&mut self, drive: &mut StackDrive) -> Option<()> {
1202-
None
1203+
match self.jump_id {
1204+
0 => {
1205+
let RepeatContext {
1206+
count,
1207+
code_position,
1208+
last_position: _,
1209+
mincount,
1210+
maxcount: _,
1211+
} = *drive.repeat_ctx();
1212+
drive.state.string_position = drive.ctx().string_position;
1213+
self.count = count + 1;
1214+
1215+
if (self.count as usize) < mincount {
1216+
// not enough matches
1217+
drive.repeat_ctx_mut().count = self.count;
1218+
drive.push_new_context_at(code_position + 4);
1219+
self.jump_id = 1;
1220+
return Some(());
1221+
}
1222+
1223+
// see if the tail matches
1224+
drive.state.marks_push();
1225+
self.save_repeat = drive.state.repeat_stack.pop();
1226+
drive.push_new_context(1);
1227+
self.jump_id = 2;
1228+
Some(())
1229+
}
1230+
1 => {
1231+
let child_ctx = drive.state.popped_context.unwrap();
1232+
drive.ctx_mut().has_matched = child_ctx.has_matched;
1233+
if drive.ctx().has_matched != Some(true) {
1234+
drive.repeat_ctx_mut().count = self.count - 1;
1235+
drive.state.string_position = drive.ctx().string_position;
1236+
}
1237+
None
1238+
}
1239+
2 => {
1240+
let child_ctx = drive.state.popped_context.unwrap();
1241+
if child_ctx.has_matched == Some(true) {
1242+
drive.ctx_mut().has_matched = Some(true);
1243+
return None;
1244+
}
1245+
drive.state.repeat_stack.push(self.save_repeat.unwrap());
1246+
drive.state.string_position = drive.ctx().string_position;
1247+
drive.state.marks_pop();
1248+
1249+
// match more unital tail matches
1250+
let maxcount = drive.repeat_ctx().maxcount;
1251+
let code_position = drive.repeat_ctx().code_position;
1252+
if self.count as usize >= maxcount && maxcount != MAXREPEAT {
1253+
drive.ctx_mut().has_matched = Some(false);
1254+
return None;
1255+
}
1256+
drive.repeat_ctx_mut().count = self.count;
1257+
drive.push_new_context_at(code_position + 4);
1258+
self.jump_id = 1;
1259+
Some(())
1260+
}
1261+
_ => unreachable!(),
1262+
}
12031263
// match self.jump_id {
12041264
// 0 => {
12051265
// drive.state.string_position = drive.ctx().string_position;

0 commit comments

Comments
 (0)