@@ -151,12 +151,7 @@ pub(crate) fn search(
151
151
// TODO: optimize by op info and skip prefix
152
152
let end = std:: cmp:: min ( end, string. char_len ( ) ) ;
153
153
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 ( ) ) {
160
155
return Some ( m) ;
161
156
}
162
157
}
@@ -294,12 +289,13 @@ impl<'a> StackDrive<'a> {
294
289
self . state
295
290
}
296
291
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 ( ) } ;
299
293
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;
303
299
self . state . context_stack . push ( child_ctx) ;
304
300
}
305
301
fn repeat_ctx_mut ( & mut self ) -> & mut RepeatContext {
@@ -571,6 +567,8 @@ impl OpcodeDispatcher {
571
567
count : -1 ,
572
568
code_position : drive. ctx ( ) . code_position ,
573
569
last_position : std:: usize:: MAX ,
570
+ mincount : drive. peek_code ( 2 ) as usize ,
571
+ maxcount : drive. peek_code ( 3 ) as usize ,
574
572
} ;
575
573
drive. state . repeat_stack . push ( repeat) ;
576
574
drive. state . string_position = drive. ctx ( ) . string_position ;
@@ -584,7 +582,7 @@ impl OpcodeDispatcher {
584
582
} ,
585
583
) ,
586
584
SreOpcode :: MAX_UNTIL => Box :: new ( OpMaxUntil :: default ( ) ) ,
587
- SreOpcode :: MIN_UNTIL => todo ! ( "min until" ) ,
585
+ SreOpcode :: MIN_UNTIL => Box :: new ( OpMinUntil :: default ( ) ) ,
588
586
SreOpcode :: REPEAT_ONE => Box :: new ( OpRepeatOne :: default ( ) ) ,
589
587
SreOpcode :: MIN_REPEAT_ONE => Box :: new ( OpMinRepeatOne :: default ( ) ) ,
590
588
SreOpcode :: GROUPREF => once ( |drive| general_op_groupref ( drive, |x| x) ) ,
@@ -996,6 +994,8 @@ struct RepeatContext {
996
994
code_position : usize ,
997
995
// zero-width match protection
998
996
last_position : usize ,
997
+ mincount : usize ,
998
+ maxcount : usize ,
999
999
}
1000
1000
1001
1001
struct OpMinRepeatOne {
@@ -1111,30 +1111,30 @@ impl OpcodeExecutor for OpMaxUntil {
1111
1111
count,
1112
1112
code_position,
1113
1113
last_position,
1114
+ mincount,
1115
+ maxcount,
1114
1116
} = * 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
+
1118
1118
drive. state . string_position = drive. ctx ( ) . string_position ;
1119
1119
self . count = count + 1 ;
1120
1120
1121
1121
if ( self . count as usize ) < mincount {
1122
1122
// not enough matches
1123
1123
drive. repeat_ctx_mut ( ) . count = self . count ;
1124
- drive. push_new_context ( 4 ) ;
1124
+ drive. push_new_context_at ( code_position + 4 ) ;
1125
1125
self . jump_id = 1 ;
1126
1126
return Some ( ( ) ) ;
1127
1127
}
1128
1128
1129
- if ( ( count as usize ) < maxcount || maxcount == MAXREPEAT )
1129
+ if ( ( self . count as usize ) < maxcount || maxcount == MAXREPEAT )
1130
1130
&& drive. state . string_position != last_position
1131
1131
{
1132
1132
// we may have enough matches, if we can match another item, do so
1133
1133
drive. repeat_ctx_mut ( ) . count = self . count ;
1134
1134
drive. state . marks_push ( ) ;
1135
1135
self . save_last_position = last_position;
1136
1136
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 ) ;
1138
1138
self . jump_id = 2 ;
1139
1139
return Some ( ( ) ) ;
1140
1140
}
@@ -1167,7 +1167,6 @@ impl OpcodeExecutor for OpMaxUntil {
1167
1167
}
1168
1168
3 => {
1169
1169
// cannot match more repeated items here. make sure the tail matches
1170
- drive. skip_code ( drive. peek_code ( 1 ) as usize + 1 ) ;
1171
1170
drive. push_new_context ( 1 ) ;
1172
1171
self . jump_id = 4 ;
1173
1172
Some ( ( ) )
@@ -1188,18 +1187,79 @@ impl OpcodeExecutor for OpMaxUntil {
1188
1187
struct OpMinUntil {
1189
1188
jump_id : usize ,
1190
1189
count : isize ,
1190
+ save_repeat : Option < RepeatContext > ,
1191
1191
}
1192
1192
impl Default for OpMinUntil {
1193
1193
fn default ( ) -> Self {
1194
1194
Self {
1195
1195
jump_id : 0 ,
1196
1196
count : 0 ,
1197
+ save_repeat : None ,
1197
1198
}
1198
1199
}
1199
1200
}
1200
1201
impl OpcodeExecutor for OpMinUntil {
1201
1202
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
+ }
1203
1263
// match self.jump_id {
1204
1264
// 0 => {
1205
1265
// drive.state.string_position = drive.ctx().string_position;
0 commit comments