9
9
//! even on targets that do not support AVX2 SIMD operations.
10
10
#[ cfg( feature = "head-skip" ) ]
11
11
use super :: head_skipping:: { CanHeadSkip , HeadSkip } ;
12
- use super :: Compiler ;
12
+ use super :: { Compiler , FIRST_ITEM_INDEX } ;
13
13
#[ cfg( feature = "head-skip" ) ]
14
14
use crate :: classification:: ResumeClassifierState ;
15
15
use crate :: debug;
@@ -20,7 +20,7 @@ use crate::engine::tail_skipping::TailSkip;
20
20
use crate :: engine:: { Engine , Input } ;
21
21
use crate :: query:: automaton:: { Automaton , State } ;
22
22
use crate :: query:: error:: CompilerError ;
23
- use crate :: query:: { JsonPathQuery , Label } ;
23
+ use crate :: query:: { JsonPathQuery , Label , NonNegativeArrayIndex } ;
24
24
use crate :: result:: QueryResult ;
25
25
use crate :: BLOCK_SIZE ;
26
26
use crate :: {
@@ -105,6 +105,7 @@ struct Executor<'q, 'b, I: Input> {
105
105
bytes : & ' b I ,
106
106
next_event : Option < Structural > ,
107
107
is_list : bool ,
108
+ array_count : NonNegativeArrayIndex ,
108
109
}
109
110
110
111
fn query_executor < ' q , ' b , I : Input > (
@@ -119,6 +120,7 @@ fn query_executor<'q, 'b, I: Input>(
119
120
bytes,
120
121
next_event : None ,
121
122
is_list : false ,
123
+ array_count : FIRST_ITEM_INDEX ,
122
124
}
123
125
}
124
126
@@ -247,14 +249,35 @@ impl<'q, 'b, I: Input> Executor<'q, 'b, I> {
247
249
S : StructuralIterator < ' b , I , Q , BLOCK_SIZE > ,
248
250
R : QueryResult ,
249
251
{
252
+ debug ! ( "array_count = {}" , self . array_count) ;
250
253
self . next_event = classifier. next ( ) ;
251
254
let is_next_opening = self . next_event . map_or ( false , |s| s. is_opening ( ) ) ;
252
255
253
256
if !is_next_opening {
254
- let fallback_state = self . automaton [ self . state ] . fallback_state ( ) ;
255
- if self . is_list && self . automaton . is_accepting ( fallback_state) {
257
+ let fallback_accepting = self
258
+ . automaton
259
+ . is_accepting ( self . automaton [ self . state ] . fallback_state ( ) ) ;
260
+
261
+ if self . is_list && fallback_accepting {
256
262
result. report ( idx) ;
257
263
}
264
+
265
+ self . array_count = self . array_count . increment ( ) ;
266
+
267
+ if let Ok ( array_id) = self . array_count . try_into ( ) {
268
+ let match_index = self
269
+ . automaton
270
+ . has_array_index_transition_to_accepting ( self . state , & array_id) ;
271
+
272
+ let accepting_list = self . automaton . is_accepting_list_item ( self . state ) ;
273
+
274
+ let is_accepting_list_item = self . is_list && accepting_list;
275
+
276
+ if is_accepting_list_item && match_index {
277
+ debug ! ( "Accepting on list item." ) ;
278
+ result. report ( idx) ;
279
+ }
280
+ }
258
281
}
259
282
260
283
Ok ( ( ) )
@@ -278,7 +301,24 @@ impl<'q, 'b, I: Input> Executor<'q, 'b, I> {
278
301
if let Some ( colon_idx) = self . find_preceding_colon ( idx) {
279
302
for & ( label, target) in self . automaton [ self . state ] . transitions ( ) {
280
303
match label {
281
- TransitionLabel :: ArrayIndex ( _) => { }
304
+ TransitionLabel :: ArrayIndex ( _i) => {
305
+ // TODO: should this really be a no-op?
306
+ // if let Ok(array_id) = self.array_count.try_into() {
307
+ // if self.is_list
308
+ // && self
309
+ // .automaton
310
+ // .has_accepting_list_item_at_index(self.state, &array_id)
311
+ // {
312
+ // any_matched = true;
313
+ // if self.automaton.is_accepting(target) {
314
+ // debug!("Accept Array Index {i}");
315
+ // debug!("Accept {idx}");
316
+ // result.report(idx);
317
+ // }
318
+ // break;
319
+ // }
320
+ // }
321
+ }
282
322
TransitionLabel :: ObjectMember ( label) => {
283
323
if self . is_match ( colon_idx, label) ? {
284
324
any_matched = true ;
@@ -316,9 +356,17 @@ impl<'q, 'b, I: Input> Executor<'q, 'b, I> {
316
356
self . is_list = true ;
317
357
318
358
let fallback = self . automaton [ self . state ] . fallback_state ( ) ;
319
- if self . automaton . is_accepting ( fallback) {
320
- classifier. turn_commas_on ( idx) ;
359
+ let is_fallback_accepting = self . automaton . is_accepting ( fallback) ;
360
+ let wants_first_item = is_fallback_accepting
361
+ || self
362
+ . automaton
363
+ . has_first_array_index_transition_to_accepting ( self . state ) ;
364
+
365
+ classifier. turn_commas_on ( idx) ;
366
+
367
+ if wants_first_item {
321
368
self . next_event = classifier. next ( ) ;
369
+
322
370
match self . next_event {
323
371
Some ( Structural :: Closing ( _, close_idx) ) => {
324
372
if let Some ( ( next_idx, _) ) = self . bytes . seek_non_whitespace_forward ( idx + 1 )
@@ -372,6 +420,7 @@ impl<'q, 'b, I: Input> Executor<'q, 'b, I> {
372
420
if let Some ( stack_frame) = self . stack . pop_if_at_or_below ( * self . depth ) {
373
421
self . state = stack_frame. state ;
374
422
self . is_list = stack_frame. is_list ;
423
+ self . array_count = stack_frame. array_count ;
375
424
376
425
if self . automaton . is_unitary ( self . state ) {
377
426
let bracket_type = self . current_node_bracket_type ( ) ;
@@ -420,10 +469,12 @@ impl<'q, 'b, I: Input> Executor<'q, 'b, I> {
420
469
"push {}, goto {target}, is_list = {target_is_list}" ,
421
470
self . state
422
471
) ;
472
+
423
473
self . stack . push ( StackFrame {
424
474
depth : * self . depth ,
425
475
state : self . state ,
426
476
is_list : self . is_list ,
477
+ array_count : self . array_count ,
427
478
} ) ;
428
479
self . state = target;
429
480
}
@@ -480,6 +531,7 @@ struct StackFrame {
480
531
depth : u8 ,
481
532
state : State ,
482
533
is_list : bool ,
534
+ array_count : NonNegativeArrayIndex ,
483
535
}
484
536
485
537
#[ derive( Debug ) ]
0 commit comments