yeptris 0.6.26.2-arm-linux-eabihf → 0.6.28.1-arm-linux-eabihf
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/yeptris.rb +1 -1
- data/libyeptris.so +0 -0
- data/vendor/libyeptris/CMakeLists.txt +1 -1
- data/vendor/libyeptris/src/yeptris/dom/ytape.c +1382 -19
- data/vendor/libyeptris/src/yeptris/dom/ytape.h +20 -1
- data/vendor/libyeptris/src/yeptris/parse.c +26 -2
- data/vendor/libyeptris/src/yeptris/scan/json.c +10 -7
- data/vendor/libyeptris/src/yeptris/tape.c +724 -395
- data/vendor/libyeptris/src/yeptris/tape_in.h +2 -1
- metadata +1 -1
|
@@ -140,11 +140,12 @@ static int tape_put_root_scalar(tape_ctx* c, const char* p, size_t len, size_t a
|
|
|
140
140
|
/* The punctuation inline (the simdjson tape-builder lesson): after a
|
|
141
141
|
* value or a key, the next token is a comma/colon or the close —
|
|
142
142
|
* consume it inline instead of paying a full loop iteration for a
|
|
143
|
-
* one-byte state flip. Anything else (close, garbage
|
|
144
|
-
*
|
|
143
|
+
* one-byte state flip. Anything else (close, garbage) falls through
|
|
144
|
+
* with the cursor parked for the main loop to judge. Whitespace here
|
|
145
|
+
* is RFC 8259's set — tab included. */
|
|
145
146
|
static inline uint8_t tape_inline_punct(const char* p, size_t len, size_t* i, uint8_t want) {
|
|
146
147
|
size_t j = *i;
|
|
147
|
-
while (j < len && (p[j] == ' ' || p[j] == '\n' || p[j] == '\r')) {
|
|
148
|
+
while (j < len && (p[j] == ' ' || p[j] == '\t' || p[j] == '\n' || p[j] == '\r')) {
|
|
148
149
|
j++;
|
|
149
150
|
}
|
|
150
151
|
if (j < len && (uint8_t)p[j] == want) {
|
|
@@ -186,10 +187,10 @@ static YeptrisStatus tape_walk(const char* p, size_t len, size_t open, yeptris_j
|
|
|
186
187
|
|
|
187
188
|
size_t i = open + 1;
|
|
188
189
|
for (;;) {
|
|
189
|
-
while (i < len && (p[i] == ' ' || p[i] == '\n' || p[i] == '\r')) {
|
|
190
|
+
while (i < len && (p[i] == ' ' || p[i] == '\t' || p[i] == '\n' || p[i] == '\r')) {
|
|
190
191
|
i++;
|
|
191
192
|
}
|
|
192
|
-
if (i >= len
|
|
193
|
+
if (i >= len) {
|
|
193
194
|
goto reject;
|
|
194
195
|
}
|
|
195
196
|
size_t at = i;
|
|
@@ -329,8 +330,8 @@ static YeptrisStatus tape_walk(const char* p, size_t len, size_t open, yeptris_j
|
|
|
329
330
|
}
|
|
330
331
|
if (at + wl < len) {
|
|
331
332
|
char z = p[at + wl];
|
|
332
|
-
if (z != ' ' && z != '\
|
|
333
|
-
z != ':') {
|
|
333
|
+
if (z != ' ' && z != '\t' && z != '\n' && z != '\r' && z != ',' && z != ']' &&
|
|
334
|
+
z != '}' && z != ':') {
|
|
334
335
|
goto reject;
|
|
335
336
|
}
|
|
336
337
|
}
|
|
@@ -546,70 +547,663 @@ static YEP_UNUSED_FN YeptrisStatus tape_walk_idx(const char* p, size_t len, size
|
|
|
546
547
|
}
|
|
547
548
|
if (at + wl < len) {
|
|
548
549
|
char z = p[at + wl];
|
|
549
|
-
if (z != ' ' && z != '\
|
|
550
|
-
z != ':') {
|
|
550
|
+
if (z != ' ' && z != '\t' && z != '\n' && z != '\r' && z != ',' && z != ']' &&
|
|
551
|
+
z != '}' && z != ':') {
|
|
551
552
|
goto reject;
|
|
552
553
|
}
|
|
553
554
|
}
|
|
554
|
-
kinds[count] = c == 'n' ? YEP_T_NULL : (c == 't' ? YEP_T_TRUE : YEP_T_FALSE);
|
|
555
|
-
offs[count] = (uint32_t)at;
|
|
556
|
-
lens[count] = (uint32_t)wl;
|
|
557
|
-
count++;
|
|
558
|
-
prev_end = at + wl;
|
|
559
|
-
top_expect = JW_COMMA_OR_CLOSE;
|
|
560
|
-
key_slot = 0;
|
|
561
|
-
continue;
|
|
555
|
+
kinds[count] = c == 'n' ? YEP_T_NULL : (c == 't' ? YEP_T_TRUE : YEP_T_FALSE);
|
|
556
|
+
offs[count] = (uint32_t)at;
|
|
557
|
+
lens[count] = (uint32_t)wl;
|
|
558
|
+
count++;
|
|
559
|
+
prev_end = at + wl;
|
|
560
|
+
top_expect = JW_COMMA_OR_CLOSE;
|
|
561
|
+
key_slot = 0;
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
goto reject;
|
|
565
|
+
}
|
|
566
|
+
/* trailing whitespace only */
|
|
567
|
+
while (prev_end < len && (p[prev_end] == ' ' || p[prev_end] == '\t' || p[prev_end] == '\n' ||
|
|
568
|
+
p[prev_end] == '\r')) {
|
|
569
|
+
prev_end++;
|
|
570
|
+
}
|
|
571
|
+
if (prev_end != len) {
|
|
572
|
+
goto reject;
|
|
573
|
+
}
|
|
574
|
+
if (count > len + 2) {
|
|
575
|
+
goto mem;
|
|
576
|
+
}
|
|
577
|
+
t->count = count;
|
|
578
|
+
t->_src = p;
|
|
579
|
+
t->_srclen = len;
|
|
580
|
+
return YEPTRIS_OK;
|
|
581
|
+
|
|
582
|
+
mem:
|
|
583
|
+
yeptris_tape_free(t);
|
|
584
|
+
return YEPTRIS_ERROR_MEMORY;
|
|
585
|
+
reject:
|
|
586
|
+
yeptris_tape_free(t);
|
|
587
|
+
return YEPTRIS_ERROR_PARSE;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/* The LENIENT token walk (the simdjson deferred contract): stage-1
|
|
591
|
+
* positions consumed with the grammar arms removed. Structural
|
|
592
|
+
* alternation mirrors tape_walk_idx state for state — bracket
|
|
593
|
+
* matching, key/value placement, literals (packed compares), and
|
|
594
|
+
* string closes/escapes (yep_json_string) all stay parse-time
|
|
595
|
+
* checks; NUMBER grammar does not — the arm records the scalar-run
|
|
596
|
+
* span (start to the next token's position, trailing ws trimmed)
|
|
597
|
+
* as YEP_T_NUM and yeptris_tape_convert owns validation and the
|
|
598
|
+
* int/float split. A malformed number ("12ab") therefore rejects at
|
|
599
|
+
* drain, not parse. */
|
|
600
|
+
/* The fused LENIENT walk: the strict walk's byte loop with the number
|
|
601
|
+
* grammar deferred — the arm records the run to its natural delimiter
|
|
602
|
+
* (the classify scan carries no accept/reject structure) and
|
|
603
|
+
* yeptris_tape_convert owns validation. Everything else matches
|
|
604
|
+
* tape_walk state for state. */
|
|
605
|
+
/* LNUM_RUN — the initial digit run of a number span: SWAR words, eight
|
|
606
|
+
* bytes per pass, with the byte loop below as tail and classifier.
|
|
607
|
+
* digit iff 0x30-0x39: a lane flags when (c+0x46) carries into bit7
|
|
608
|
+
* (c > '9'), when ((c|0x80)-0xB0) goes negative (c < '0'), or when the
|
|
609
|
+
* byte is non-ASCII — and since the all-digit prefix never borrows
|
|
610
|
+
* across lanes, the flags are exact up to the first non-digit, where
|
|
611
|
+
* the scan stops and the byte loop classifies what follows (the
|
|
612
|
+
* consumed-only digits_only law is untouched: the run sets saw_digit,
|
|
613
|
+
* nothing else). */
|
|
614
|
+
#define LNUM_RUN \
|
|
615
|
+
do { \
|
|
616
|
+
size_t ks_ = k; \
|
|
617
|
+
while (k + 8 <= len) { \
|
|
618
|
+
uint64_t w_; \
|
|
619
|
+
memcpy(&w_, p + k, 8); \
|
|
620
|
+
uint64_t nd_ = \
|
|
621
|
+
((w_ + 0x4646464646464646ull) & 0x8080808080808080ull) | \
|
|
622
|
+
(((w_ | 0x8080808080808080ull) - 0xB0B0B0B0B0B0B0B0ull) & 0x8080808080808080ull) | \
|
|
623
|
+
(w_ & 0x8080808080808080ull); \
|
|
624
|
+
if (nd_ != 0) { \
|
|
625
|
+
k += (size_t)yep_ctz64(nd_) >> 3; \
|
|
626
|
+
break; \
|
|
627
|
+
} \
|
|
628
|
+
k += 8; \
|
|
629
|
+
} \
|
|
630
|
+
if (k > ks_) { \
|
|
631
|
+
saw_digit = 1; \
|
|
632
|
+
} \
|
|
633
|
+
} while (0)
|
|
634
|
+
|
|
635
|
+
/* The strict RFC 8259 number check over one number-ish run — the
|
|
636
|
+
* in-walk float/exp validator (the out-of-line number_shape call +
|
|
637
|
+
* rescan was 13% of json-doc; the digits-only case never gets here).
|
|
638
|
+
* One pass, no state machine words: sign, digits (leading-zero rule),
|
|
639
|
+
* optional .digits, optional e[+-]digits, consume exactly len.
|
|
640
|
+
* always_inline: the spans are 3-8 bytes and the out-of-line call was
|
|
641
|
+
* the cost (the rescan itself is nothing). */
|
|
642
|
+
#if defined(__GNUC__)
|
|
643
|
+
#define TAPE_NUM_OK_INLINE __attribute__((always_inline)) inline
|
|
644
|
+
#else
|
|
645
|
+
#define TAPE_NUM_OK_INLINE
|
|
646
|
+
#endif
|
|
647
|
+
static TAPE_NUM_OK_INLINE int tape_num_ok(const char* p, size_t len) {
|
|
648
|
+
size_t k = 0;
|
|
649
|
+
if (k < len && p[k] == '-') {
|
|
650
|
+
k++;
|
|
651
|
+
}
|
|
652
|
+
size_t int_start = k;
|
|
653
|
+
while (k < len && (unsigned)(unsigned char)p[k] - '0' <= 9u) {
|
|
654
|
+
k++;
|
|
655
|
+
}
|
|
656
|
+
if (k == int_start) {
|
|
657
|
+
return 0; /* no integer part */
|
|
658
|
+
}
|
|
659
|
+
if (k - int_start > 1 && p[int_start] == '0') {
|
|
660
|
+
return 0; /* leading zero */
|
|
661
|
+
}
|
|
662
|
+
if (k < len && p[k] == '.') {
|
|
663
|
+
k++;
|
|
664
|
+
size_t frac = k;
|
|
665
|
+
while (k < len && (unsigned)(unsigned char)p[k] - '0' <= 9u) {
|
|
666
|
+
k++;
|
|
667
|
+
}
|
|
668
|
+
if (k == frac) {
|
|
669
|
+
return 0;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
if (k < len && (p[k] == 'e' || p[k] == 'E')) {
|
|
673
|
+
k++;
|
|
674
|
+
if (k < len && (p[k] == '+' || p[k] == '-')) {
|
|
675
|
+
k++;
|
|
676
|
+
}
|
|
677
|
+
size_t exp = k;
|
|
678
|
+
while (k < len && (unsigned)(unsigned char)p[k] - '0' <= 9u) {
|
|
679
|
+
k++;
|
|
680
|
+
}
|
|
681
|
+
if (k == exp) {
|
|
682
|
+
return 0;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
return k == len;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open,
|
|
689
|
+
yeptris_json_tape* t, int strict_nums, int clean_only,
|
|
690
|
+
int reuse_block) {
|
|
691
|
+
/* reuse_block: the caller owns the struct and zeroed it (the flow
|
|
692
|
+
* recorder's scratch) — a prior walk's block may be reused through
|
|
693
|
+
* the _srclen watermark. Consumer structs carry untrustworthy
|
|
694
|
+
* fields and always carve fresh. */
|
|
695
|
+
if (reuse_block && t->_block != NULL && t->recs != NULL && t->_rec_primary &&
|
|
696
|
+
t->_srclen >= len + 2) {
|
|
697
|
+
t->_cols_ready = 0;
|
|
698
|
+
t->_rec_primary = 1;
|
|
699
|
+
} else if (tape_carve(t, len) != YEPTRIS_OK) {
|
|
700
|
+
return YEPTRIS_ERROR_MEMORY;
|
|
701
|
+
}
|
|
702
|
+
t->_rec_primary = 1;
|
|
703
|
+
/* the interleaved records are the primary storage (item 07); the
|
|
704
|
+
* columns materialize lazily via yeptris_tape_columns */
|
|
705
|
+
t->_rec_primary = 1;
|
|
706
|
+
yeptris_tape_rec* recs = t->recs;
|
|
707
|
+
uint32_t open_at[YEP_JSON_WALK_DEPTH];
|
|
708
|
+
uint8_t kind[YEP_JSON_WALK_DEPTH];
|
|
709
|
+
|
|
710
|
+
recs[0] = ((uint64_t)0 << 32) | ((uint64_t)0 << 8) | YEP_T_DOC;
|
|
711
|
+
|
|
712
|
+
uint8_t top_kind = p[open] == '[' ? 0 : 1;
|
|
713
|
+
recs[1] =
|
|
714
|
+
((uint64_t)0 << 32) | ((uint64_t)0 << 8) | (top_kind ? YEP_T_MAP_OPEN : YEP_T_SEQ_OPEN);
|
|
715
|
+
size_t count = 2;
|
|
716
|
+
int depth = 1;
|
|
717
|
+
open_at[0] = 1;
|
|
718
|
+
kind[0] = top_kind;
|
|
719
|
+
|
|
720
|
+
size_t i = open + 1;
|
|
721
|
+
/* clean_only (parse_json's route): tabs and non-ASCII bytes REJECT
|
|
722
|
+
* — the caller falls to the strict sequence, which owns the pinned
|
|
723
|
+
* error precedences those inputs carry (the tab reject, the UTF-8
|
|
724
|
+
* gate). This replaces the entry's full-input gate_scan +
|
|
725
|
+
* tab-memchr pre-passes: same routing by construction, zero scans
|
|
726
|
+
* before the walk. */
|
|
727
|
+
int cl = clean_only;
|
|
728
|
+
if (top_kind) {
|
|
729
|
+
goto lmap1;
|
|
730
|
+
}
|
|
731
|
+
goto lseq1;
|
|
732
|
+
|
|
733
|
+
/* strict_nums: the parse_json route's contract is RFC 8259 AT
|
|
734
|
+
* parse time, so its number arms validate the run in-place (the
|
|
735
|
+
* settle pass disappears — the span is cache-warm here); the
|
|
736
|
+
* standalone lenient entry keeps its deferred contract (0: the
|
|
737
|
+
* run records unvalidated, yeptris_tape_convert owns it). */
|
|
738
|
+
|
|
739
|
+
/* The specialized member loops (the #342 dispatch-chain cut): once
|
|
740
|
+
* inside a container the grammar is a 2-state cycle — member or
|
|
741
|
+
* separator — so the general chain's expect/key_slot machine and
|
|
742
|
+
* its per-token re-dispatch are replaced by direct loops per kind.
|
|
743
|
+
* Acceptance is IDENTICAL to the chain (the pinning suites hold:
|
|
744
|
+
* Tape suite, LenientMatchesStrict, ErrorParity, the json corpora).
|
|
745
|
+
*
|
|
746
|
+
* lmap / lseq: positioned at a member (or the container's closer).
|
|
747
|
+
* lvalue: scans one value (string/number/literal/container).
|
|
748
|
+
* lafter: positioned after a complete value — ',' or the closer.
|
|
749
|
+
* A close pops the frame; depth 0 ends the walk. */
|
|
750
|
+
|
|
751
|
+
#define LWS() \
|
|
752
|
+
do { \
|
|
753
|
+
while (i < len && \
|
|
754
|
+
(p[i] == ' ' || p[i] == '\n' || p[i] == '\r' || (p[i] == '\t' && !cl))) { \
|
|
755
|
+
i++; \
|
|
756
|
+
} \
|
|
757
|
+
if (i >= len) { \
|
|
758
|
+
goto lreject; \
|
|
759
|
+
} \
|
|
760
|
+
} while (0)
|
|
761
|
+
|
|
762
|
+
#define LPUSH(k) \
|
|
763
|
+
do { \
|
|
764
|
+
if (depth >= YEP_JSON_WALK_DEPTH) { \
|
|
765
|
+
goto lreject; \
|
|
766
|
+
} \
|
|
767
|
+
recs[count] = ((uint64_t)0 << 32) | ((uint64_t)0 << 8) | \
|
|
768
|
+
(uint64_t)((k) ? YEP_T_MAP_OPEN : YEP_T_SEQ_OPEN); \
|
|
769
|
+
kind[depth] = (k); \
|
|
770
|
+
open_at[depth] = (uint32_t)count; \
|
|
771
|
+
count++; \
|
|
772
|
+
depth++; \
|
|
773
|
+
i++; \
|
|
774
|
+
} while (0)
|
|
775
|
+
|
|
776
|
+
#define LCLOSE() \
|
|
777
|
+
do { \
|
|
778
|
+
uint32_t lo_ = open_at[depth - 1]; \
|
|
779
|
+
recs[count] = ((uint64_t)lo_ << 32) | ((uint64_t)0 << 8) | YEP_T_CLOSE; \
|
|
780
|
+
recs[lo_] = \
|
|
781
|
+
(recs[lo_] & ~(uint64_t)0xFFFFFFFF00000000u) | ((uint64_t)(uint32_t)count << 32); \
|
|
782
|
+
count++; \
|
|
783
|
+
i++; \
|
|
784
|
+
depth--; \
|
|
785
|
+
if (depth == 0) { \
|
|
786
|
+
goto ldone; \
|
|
787
|
+
} \
|
|
788
|
+
if (kind[depth - 1]) { \
|
|
789
|
+
goto lmapafter; \
|
|
790
|
+
} \
|
|
791
|
+
goto lseqafter; \
|
|
792
|
+
} while (0)
|
|
793
|
+
|
|
794
|
+
/* LSTR_SCAN(after) — the fused string arm, positioned at p[i] == '"'.
|
|
795
|
+
* One SWAR round settles the common short span; quote_scan (the SIMD
|
|
796
|
+
* close scan) settles longer no-escape spans, with a c0 sweep over the
|
|
797
|
+
* content (quote_scan never tests control bytes); the kernel runs only
|
|
798
|
+
* when escapes appear — its grammar authority covers the escape rules
|
|
799
|
+
* quote_scan skips. `after` names the post-member label. */
|
|
800
|
+
#define LSTR_SCAN(after) \
|
|
801
|
+
do { \
|
|
802
|
+
size_t j_ = i + 1; \
|
|
803
|
+
int esc_ = 0; \
|
|
804
|
+
if (j_ + 8 <= len) { \
|
|
805
|
+
uint64_t w_; \
|
|
806
|
+
memcpy(&w_, p + j_, 8); \
|
|
807
|
+
uint64_t qm_ = (w_ ^ 0x2222222222222222ull); \
|
|
808
|
+
uint64_t bm_ = (w_ ^ 0x5C5C5C5C5C5C5C5Cull); \
|
|
809
|
+
qm_ = (qm_ - 0x0101010101010101ull) & ~qm_ & 0x8080808080808080ull; \
|
|
810
|
+
bm_ = (bm_ - 0x0101010101010101ull) & ~bm_ & 0x8080808080808080ull; \
|
|
811
|
+
uint64_t c0_ = (w_ - 0x2020202020202020ull) & ~w_ & 0x8080808080808080ull; \
|
|
812
|
+
uint64_t hi_ = cl ? (w_ & 0x8080808080808080ull) : 0; \
|
|
813
|
+
if (qm_ != 0 && ((bm_ | c0_ | hi_) & (qm_ - 1)) == 0) { \
|
|
814
|
+
size_t cl_ = j_ + (size_t)yep_ctz64(qm_) / 8; \
|
|
815
|
+
recs[count] = ((uint64_t)((uint32_t)j_) << 32) | \
|
|
816
|
+
((uint64_t)((uint32_t)(cl_ - j_)) << 8) | (uint64_t)(YEP_T_STR); \
|
|
817
|
+
count++; \
|
|
818
|
+
i = cl_ + 1; \
|
|
819
|
+
goto after; \
|
|
820
|
+
} \
|
|
821
|
+
/* rounds 2-4 (up to 32 bytes inline): the email-class strings \
|
|
822
|
+
* close here without the quote_scan call and its redundant \
|
|
823
|
+
* content re-sweep; reached only when round 1 had no close, \
|
|
824
|
+
* so the short-string case pays nothing */ \
|
|
825
|
+
if ((qm_ | bm_ | c0_ | hi_) == 0) { \
|
|
826
|
+
size_t nr_ = (len - j_) >> 3; \
|
|
827
|
+
if (nr_ > 4) { \
|
|
828
|
+
nr_ = 4; \
|
|
829
|
+
} \
|
|
830
|
+
for (size_t r_ = 1; r_ < nr_; r_++) { \
|
|
831
|
+
size_t b2_ = j_ + (r_ << 3); \
|
|
832
|
+
memcpy(&w_, p + b2_, 8); \
|
|
833
|
+
qm_ = (w_ ^ 0x2222222222222222ull); \
|
|
834
|
+
bm_ = (w_ ^ 0x5C5C5C5C5C5C5C5Cull); \
|
|
835
|
+
qm_ = (qm_ - 0x0101010101010101ull) & ~qm_ & 0x8080808080808080ull; \
|
|
836
|
+
bm_ = (bm_ - 0x0101010101010101ull) & ~bm_ & 0x8080808080808080ull; \
|
|
837
|
+
c0_ = (w_ - 0x2020202020202020ull) & ~w_ & 0x8080808080808080ull; \
|
|
838
|
+
hi_ = cl ? (w_ & 0x8080808080808080ull) : 0; \
|
|
839
|
+
if (qm_ != 0 && ((bm_ | c0_ | hi_) & (qm_ - 1)) == 0) { \
|
|
840
|
+
size_t cl_ = b2_ + (size_t)yep_ctz64(qm_) / 8; \
|
|
841
|
+
recs[count] = ((uint64_t)((uint32_t)j_) << 32) | \
|
|
842
|
+
((uint64_t)((uint32_t)(cl_ - j_)) << 8) | \
|
|
843
|
+
(uint64_t)(YEP_T_STR); \
|
|
844
|
+
count++; \
|
|
845
|
+
i = cl_ + 1; \
|
|
846
|
+
goto after; \
|
|
847
|
+
} \
|
|
848
|
+
if ((qm_ | bm_ | c0_ | hi_) != 0) { \
|
|
849
|
+
break; /* escape, c0 or hi: kernel authority */ \
|
|
850
|
+
} \
|
|
851
|
+
} \
|
|
852
|
+
} \
|
|
853
|
+
} \
|
|
854
|
+
{ \
|
|
855
|
+
const yep_text_kernels* kk_ = yep_text_active(); \
|
|
856
|
+
ptrdiff_t r_ = kk_->quote_scan(p + j_, len - j_, '"', &esc_); \
|
|
857
|
+
if (r_ >= 0 && esc_ == 0) { \
|
|
858
|
+
size_t cl_ = j_ + (size_t)r_; \
|
|
859
|
+
for (size_t b_ = j_; b_ < cl_;) { \
|
|
860
|
+
size_t room_ = cl_ - b_; \
|
|
861
|
+
if (room_ >= 8) { \
|
|
862
|
+
uint64_t v_; \
|
|
863
|
+
memcpy(&v_, p + b_, 8); \
|
|
864
|
+
uint64_t bad_ = \
|
|
865
|
+
(v_ - 0x2020202020202020ull) & ~v_ & 0x8080808080808080ull; \
|
|
866
|
+
if (cl) { \
|
|
867
|
+
bad_ |= v_ & 0x8080808080808080ull; \
|
|
868
|
+
} \
|
|
869
|
+
if (bad_) { \
|
|
870
|
+
goto lreject; \
|
|
871
|
+
} \
|
|
872
|
+
b_ += 8; \
|
|
873
|
+
} else { \
|
|
874
|
+
if ((unsigned char)p[b_] < 0x20 || (cl && (unsigned char)p[b_] >= 0x80)) { \
|
|
875
|
+
goto lreject; \
|
|
876
|
+
} \
|
|
877
|
+
b_++; \
|
|
878
|
+
} \
|
|
879
|
+
} \
|
|
880
|
+
recs[count] = ((uint64_t)((uint32_t)j_) << 32) | \
|
|
881
|
+
((uint64_t)((uint32_t)(cl_ - j_)) << 8) | (uint64_t)(YEP_T_STR); \
|
|
882
|
+
count++; \
|
|
883
|
+
i = cl_ + 1; \
|
|
884
|
+
goto after; \
|
|
885
|
+
} \
|
|
886
|
+
} \
|
|
887
|
+
{ \
|
|
888
|
+
size_t at_ = i; \
|
|
889
|
+
size_t cl_ = 0; \
|
|
890
|
+
if (!yep_json_string(p, len, &i, &cl_, &esc_)) { \
|
|
891
|
+
goto lreject; \
|
|
892
|
+
} \
|
|
893
|
+
if (cl) { /* escaped strings skip the sweeps above: the \
|
|
894
|
+
* clean route still owes the strict sequence's \
|
|
895
|
+
* byte guarantees over the content */ \
|
|
896
|
+
for (size_t b_ = at_ + 1; b_ < cl_; b_++) { \
|
|
897
|
+
unsigned char uc_ = (unsigned char)p[b_]; \
|
|
898
|
+
if (uc_ < 0x20 || uc_ >= 0x80) { \
|
|
899
|
+
goto lreject; \
|
|
900
|
+
} \
|
|
901
|
+
} \
|
|
902
|
+
} \
|
|
903
|
+
recs[count] = ((uint64_t)((uint32_t)(at_ + 1)) << 32) | \
|
|
904
|
+
((uint64_t)((uint32_t)(cl_ - at_ - 1)) << 8) | (uint64_t)(YEP_T_STR); \
|
|
905
|
+
count++; \
|
|
906
|
+
i = cl_ + 1; \
|
|
907
|
+
} \
|
|
908
|
+
goto after; \
|
|
909
|
+
} while (0)
|
|
910
|
+
|
|
911
|
+
/* The map member cycle — ONE contiguous region (the json-doc lesson:
|
|
912
|
+
* a goto web across value/key/after regions scattered the hot path and
|
|
913
|
+
* cost 2.7x on the flat-map shape). Values scan inline; only nested
|
|
914
|
+
* containers, literals, and the kernel string fallback leave the
|
|
915
|
+
* cycle. Acceptance is the chain's: no trailing commas, string keys
|
|
916
|
+
* only, `:` required, closers only in first-member position. */
|
|
917
|
+
lmap1: /* {} closes here */
|
|
918
|
+
LWS();
|
|
919
|
+
if (p[i] == '}') {
|
|
920
|
+
LCLOSE();
|
|
921
|
+
}
|
|
922
|
+
if (p[i] != '"') {
|
|
923
|
+
goto lreject;
|
|
924
|
+
}
|
|
925
|
+
goto lmapkey;
|
|
926
|
+
|
|
927
|
+
lmap: /* a member MUST follow (after ','): JW_KEY — a closer rejects */
|
|
928
|
+
/* compact fast path: the byte is the key's quote already — LWS's
|
|
929
|
+
* loop would examine it once and exit */
|
|
930
|
+
if (i < len && p[i] == '"') {
|
|
931
|
+
goto lmapkey;
|
|
932
|
+
}
|
|
933
|
+
LWS();
|
|
934
|
+
if (p[i] != '"') {
|
|
935
|
+
goto lreject;
|
|
936
|
+
}
|
|
937
|
+
lmapkey: { LSTR_SCAN(lmapcolon); }
|
|
938
|
+
lmapcolon:
|
|
939
|
+
if (i < len && p[i] == ':') {
|
|
940
|
+
i++;
|
|
941
|
+
/* compact fast path: the value byte follows the colon with no
|
|
942
|
+
* whitespace — one load dispatches it (the ws test below is
|
|
943
|
+
* what LWS would run anyway) */
|
|
944
|
+
if (i < len) {
|
|
945
|
+
char v = p[i];
|
|
946
|
+
if (v != ' ' && v != '\n' && v != '\r' && (cl || v != '\t')) {
|
|
947
|
+
goto lmapval;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
LWS();
|
|
951
|
+
goto lmapval;
|
|
952
|
+
}
|
|
953
|
+
LWS();
|
|
954
|
+
if (p[i] != ':') {
|
|
955
|
+
goto lreject;
|
|
956
|
+
}
|
|
957
|
+
i++;
|
|
958
|
+
LWS();
|
|
959
|
+
lmapval: {
|
|
960
|
+
char c = p[i];
|
|
961
|
+
if (c == '"') {
|
|
962
|
+
LSTR_SCAN(lmapafter);
|
|
963
|
+
}
|
|
964
|
+
if ((unsigned)(c - '0') <= 9u || c == '-') {
|
|
965
|
+
size_t k = i + 1;
|
|
966
|
+
/* the digits-only tracking makes the pure-integer case a
|
|
967
|
+
* 3-cycle leading-zero check — number_shape (a call + a
|
|
968
|
+
* rescan, 13% of json-doc) runs only for dot/exp spans */
|
|
969
|
+
int digits_only = 1, saw_digit = (c != '-');
|
|
970
|
+
LNUM_RUN;
|
|
971
|
+
while (k < len) {
|
|
972
|
+
char d = p[k];
|
|
973
|
+
if ((unsigned)(d - '0') <= 9u) {
|
|
974
|
+
k++;
|
|
975
|
+
saw_digit = 1;
|
|
976
|
+
continue;
|
|
977
|
+
}
|
|
978
|
+
/* the flag clears only on a CONSUMED byte: the run's
|
|
979
|
+
* terminator (',', '}', ']', whitespace) must leave
|
|
980
|
+
* digits_only intact, or every plain integer followed
|
|
981
|
+
* by a delimiter falls into the full validator */
|
|
982
|
+
if (d == '-' || d == '+' || d == '.' || d == 'e' || d == 'E') {
|
|
983
|
+
digits_only = 0;
|
|
984
|
+
k++;
|
|
985
|
+
continue;
|
|
986
|
+
}
|
|
987
|
+
break;
|
|
988
|
+
}
|
|
989
|
+
if (strict_nums) {
|
|
990
|
+
int ok;
|
|
991
|
+
if (digits_only && saw_digit) {
|
|
992
|
+
size_t d0 = (c == '-') ? i + 1 : i;
|
|
993
|
+
ok = (k - d0 == 1) || p[d0] != '0';
|
|
994
|
+
} else {
|
|
995
|
+
ok = tape_num_ok(p + i, (size_t)(k - i));
|
|
996
|
+
}
|
|
997
|
+
if (!ok) {
|
|
998
|
+
goto lreject;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
recs[count] =
|
|
1002
|
+
((uint64_t)((uint32_t)i) << 32) | ((uint64_t)((uint32_t)(k - i)) << 8) |
|
|
1003
|
+
(uint64_t)(strict_nums ? ((digits_only && saw_digit) ? YEP_T_INT : YEP_T_FLOAT)
|
|
1004
|
+
: (uint64_t)(YEP_T_NUM));
|
|
1005
|
+
count++;
|
|
1006
|
+
i = k;
|
|
1007
|
+
goto lmapafter;
|
|
1008
|
+
}
|
|
1009
|
+
if (c == 't' || c == 'f' || c == 'n') {
|
|
1010
|
+
size_t wl = c == 'f' ? 5 : 4;
|
|
1011
|
+
if (i + wl > len) {
|
|
1012
|
+
goto lreject;
|
|
1013
|
+
}
|
|
1014
|
+
uint32_t got4;
|
|
1015
|
+
memcpy(&got4, p + i, 4);
|
|
1016
|
+
if (got4 != (c == 't' ? 0x65757274u /* "true" */
|
|
1017
|
+
: c == 'n' ? 0x6C6C756Eu /* "null" */
|
|
1018
|
+
: 0x736C6166u /* "fals" */) ||
|
|
1019
|
+
(c == 'f' && p[i + 4] != 'e')) {
|
|
1020
|
+
goto lreject;
|
|
1021
|
+
}
|
|
1022
|
+
if (i + wl < len) {
|
|
1023
|
+
char z = p[i + wl];
|
|
1024
|
+
if (z != ' ' && z != '\t' && z != '\n' && z != '\r' && z != ',' && z != ']' &&
|
|
1025
|
+
z != '}' && z != ':') {
|
|
1026
|
+
goto lreject;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
recs[count] = ((uint64_t)((uint32_t)i) << 32) | ((uint64_t)((uint32_t)wl) << 8) |
|
|
1030
|
+
(uint64_t)(c == 'n' ? YEP_T_NULL : (c == 't' ? YEP_T_TRUE : YEP_T_FALSE));
|
|
1031
|
+
count++;
|
|
1032
|
+
i += wl;
|
|
1033
|
+
goto lmapafter;
|
|
1034
|
+
}
|
|
1035
|
+
if (c == '{') {
|
|
1036
|
+
LPUSH(1);
|
|
1037
|
+
goto lmap1;
|
|
1038
|
+
}
|
|
1039
|
+
if (c == '[') {
|
|
1040
|
+
LPUSH(0);
|
|
1041
|
+
goto lseq1;
|
|
1042
|
+
}
|
|
1043
|
+
goto lreject;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
lmapafter:
|
|
1047
|
+
/* compact fast path: value ',' key directly — the two LWS hops the
|
|
1048
|
+
* general form runs both exit on byte one here */
|
|
1049
|
+
if (i < len && p[i] == ',') {
|
|
1050
|
+
i++;
|
|
1051
|
+
if (i < len && p[i] == '"') {
|
|
1052
|
+
goto lmapkey;
|
|
1053
|
+
}
|
|
1054
|
+
goto lmap;
|
|
1055
|
+
}
|
|
1056
|
+
LWS();
|
|
1057
|
+
if (p[i] == ',') {
|
|
1058
|
+
i++;
|
|
1059
|
+
goto lmap;
|
|
1060
|
+
}
|
|
1061
|
+
if (p[i] == '}') {
|
|
1062
|
+
LCLOSE();
|
|
1063
|
+
}
|
|
1064
|
+
goto lreject;
|
|
1065
|
+
|
|
1066
|
+
/* The sequence member cycle — the same single-region shape. */
|
|
1067
|
+
lseq1: /* [] closes here */
|
|
1068
|
+
LWS();
|
|
1069
|
+
if (p[i] == ']') {
|
|
1070
|
+
LCLOSE();
|
|
1071
|
+
}
|
|
1072
|
+
goto lseqval;
|
|
1073
|
+
|
|
1074
|
+
lseq: /* a member MUST follow (after ','): JW_VALUE */
|
|
1075
|
+
LWS();
|
|
1076
|
+
lseqval: {
|
|
1077
|
+
char c = p[i];
|
|
1078
|
+
if (c == '"') {
|
|
1079
|
+
LSTR_SCAN(lseqafter);
|
|
1080
|
+
}
|
|
1081
|
+
if ((unsigned)(c - '0') <= 9u || c == '-') {
|
|
1082
|
+
size_t k = i + 1;
|
|
1083
|
+
int digits_only = 1, saw_digit = (c != '-');
|
|
1084
|
+
LNUM_RUN;
|
|
1085
|
+
while (k < len) {
|
|
1086
|
+
char d = p[k];
|
|
1087
|
+
if ((unsigned)(d - '0') <= 9u) {
|
|
1088
|
+
k++;
|
|
1089
|
+
saw_digit = 1;
|
|
1090
|
+
continue;
|
|
1091
|
+
}
|
|
1092
|
+
/* consumed-only clearing: see the map arm's comment */
|
|
1093
|
+
if (d == '-' || d == '+' || d == '.' || d == 'e' || d == 'E') {
|
|
1094
|
+
digits_only = 0;
|
|
1095
|
+
k++;
|
|
1096
|
+
continue;
|
|
1097
|
+
}
|
|
1098
|
+
break;
|
|
1099
|
+
}
|
|
1100
|
+
if (strict_nums) {
|
|
1101
|
+
int ok;
|
|
1102
|
+
if (digits_only && saw_digit) {
|
|
1103
|
+
size_t d0 = (c == '-') ? i + 1 : i;
|
|
1104
|
+
ok = (k - d0 == 1) || p[d0] != '0';
|
|
1105
|
+
} else {
|
|
1106
|
+
ok = tape_num_ok(p + i, (size_t)(k - i));
|
|
1107
|
+
}
|
|
1108
|
+
if (!ok) {
|
|
1109
|
+
goto lreject;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
recs[count] =
|
|
1113
|
+
((uint64_t)((uint32_t)i) << 32) | ((uint64_t)((uint32_t)(k - i)) << 8) |
|
|
1114
|
+
(uint64_t)(strict_nums ? ((digits_only && saw_digit) ? YEP_T_INT : YEP_T_FLOAT)
|
|
1115
|
+
: (uint64_t)(YEP_T_NUM));
|
|
1116
|
+
count++;
|
|
1117
|
+
i = k;
|
|
1118
|
+
goto lseqafter;
|
|
1119
|
+
}
|
|
1120
|
+
if (c == 't' || c == 'f' || c == 'n') {
|
|
1121
|
+
size_t wl = c == 'f' ? 5 : 4;
|
|
1122
|
+
if (i + wl > len) {
|
|
1123
|
+
goto lreject;
|
|
1124
|
+
}
|
|
1125
|
+
uint32_t got4;
|
|
1126
|
+
memcpy(&got4, p + i, 4);
|
|
1127
|
+
if (got4 != (c == 't' ? 0x65757274u /* "true" */
|
|
1128
|
+
: c == 'n' ? 0x6C6C756Eu /* "null" */
|
|
1129
|
+
: 0x736C6166u /* "fals" */) ||
|
|
1130
|
+
(c == 'f' && p[i + 4] != 'e')) {
|
|
1131
|
+
goto lreject;
|
|
1132
|
+
}
|
|
1133
|
+
if (i + wl < len) {
|
|
1134
|
+
char z = p[i + wl];
|
|
1135
|
+
if (z != ' ' && z != '\t' && z != '\n' && z != '\r' && z != ',' && z != ']' &&
|
|
1136
|
+
z != '}' && z != ':') {
|
|
1137
|
+
goto lreject;
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
recs[count] = ((uint64_t)((uint32_t)i) << 32) | ((uint64_t)((uint32_t)wl) << 8) |
|
|
1141
|
+
(uint64_t)(c == 'n' ? YEP_T_NULL : (c == 't' ? YEP_T_TRUE : YEP_T_FALSE));
|
|
1142
|
+
count++;
|
|
1143
|
+
i += wl;
|
|
1144
|
+
goto lseqafter;
|
|
1145
|
+
}
|
|
1146
|
+
if (c == '{') {
|
|
1147
|
+
LPUSH(1);
|
|
1148
|
+
goto lmap1;
|
|
1149
|
+
}
|
|
1150
|
+
if (c == '[') {
|
|
1151
|
+
LPUSH(0);
|
|
1152
|
+
goto lseq1;
|
|
1153
|
+
}
|
|
1154
|
+
goto lreject;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
lseqafter:
|
|
1158
|
+
/* compact fast path: value ',' value directly — both LWS hops exit
|
|
1159
|
+
* on byte one here */
|
|
1160
|
+
if (i < len && p[i] == ',') {
|
|
1161
|
+
i++;
|
|
1162
|
+
if (i < len) {
|
|
1163
|
+
char v = p[i];
|
|
1164
|
+
if (v != ' ' && v != '\n' && v != '\r' && (cl || v != '\t')) {
|
|
1165
|
+
goto lseqval;
|
|
1166
|
+
}
|
|
562
1167
|
}
|
|
563
|
-
goto
|
|
1168
|
+
goto lseq;
|
|
564
1169
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
1170
|
+
LWS();
|
|
1171
|
+
if (p[i] == ',') {
|
|
1172
|
+
i++;
|
|
1173
|
+
goto lseq;
|
|
569
1174
|
}
|
|
570
|
-
if (
|
|
571
|
-
|
|
1175
|
+
if (p[i] == ']') {
|
|
1176
|
+
LCLOSE();
|
|
572
1177
|
}
|
|
573
|
-
|
|
574
|
-
|
|
1178
|
+
goto lreject;
|
|
1179
|
+
|
|
1180
|
+
ldone:
|
|
1181
|
+
#undef LWS
|
|
1182
|
+
#undef LNUM_RUN
|
|
1183
|
+
#undef LPUSH
|
|
1184
|
+
#undef LCLOSE
|
|
1185
|
+
#undef LSTR_SCAN
|
|
1186
|
+
|
|
1187
|
+
{
|
|
1188
|
+
size_t tail = i;
|
|
1189
|
+
while (tail < len &&
|
|
1190
|
+
(p[tail] == ' ' || p[tail] == '\n' || p[tail] == '\r' || (p[tail] == '\t' && !cl))) {
|
|
1191
|
+
tail++;
|
|
1192
|
+
}
|
|
1193
|
+
if (tail != len) {
|
|
1194
|
+
goto lreject;
|
|
575
1195
|
}
|
|
1196
|
+
}
|
|
576
1197
|
t->count = count;
|
|
577
1198
|
t->_src = p;
|
|
578
1199
|
t->_srclen = len;
|
|
579
1200
|
return YEPTRIS_OK;
|
|
580
1201
|
|
|
581
|
-
|
|
582
|
-
yeptris_tape_free(t);
|
|
583
|
-
return YEPTRIS_ERROR_MEMORY;
|
|
584
|
-
reject:
|
|
1202
|
+
lreject:
|
|
585
1203
|
yeptris_tape_free(t);
|
|
586
1204
|
return YEPTRIS_ERROR_PARSE;
|
|
587
1205
|
}
|
|
588
1206
|
|
|
589
|
-
/* The LENIENT token walk (the simdjson deferred contract): stage-1
|
|
590
|
-
* positions consumed with the grammar arms removed. Structural
|
|
591
|
-
* alternation mirrors tape_walk_idx state for state — bracket
|
|
592
|
-
* matching, key/value placement, literals (packed compares), and
|
|
593
|
-
* string closes/escapes (yep_json_string) all stay parse-time
|
|
594
|
-
* checks; NUMBER grammar does not — the arm records the scalar-run
|
|
595
|
-
* span (start to the next token's position, trailing ws trimmed)
|
|
596
|
-
* as YEP_T_NUM and yeptris_tape_convert owns validation and the
|
|
597
|
-
* int/float split. A malformed number ("12ab") therefore rejects at
|
|
598
|
-
* drain, not parse. */
|
|
599
|
-
/* The fused LENIENT walk: the strict walk's byte loop with the number
|
|
600
|
-
* grammar deferred — the arm records the run to its natural delimiter
|
|
601
|
-
* (the classify scan carries no accept/reject structure) and
|
|
602
|
-
* yeptris_tape_convert owns validation. Everything else matches
|
|
603
|
-
* tape_walk state for state. */
|
|
604
|
-
/* LNUM_RUN — the initial digit run of a number span: SWAR words, eight
|
|
605
|
-
* bytes per pass, with the byte loop below as tail and classifier.
|
|
606
|
-
* digit iff 0x30-0x39: a lane flags when (c+0x46) carries into bit7
|
|
607
|
-
* (c > '9'), when ((c|0x80)-0xB0) goes negative (c < '0'), or when the
|
|
608
|
-
* byte is non-ASCII — and since the all-digit prefix never borrows
|
|
609
|
-
* across lanes, the flags are exact up to the first non-digit, where
|
|
610
|
-
* the scan stops and the byte loop classifies what follows (the
|
|
611
|
-
* consumed-only digits_only law is untouched: the run sets saw_digit,
|
|
612
|
-
* nothing else). */
|
|
613
1207
|
#define LNUM_RUN \
|
|
614
1208
|
do { \
|
|
615
1209
|
size_t ks_ = k; \
|
|
@@ -630,77 +1224,33 @@ reject:
|
|
|
630
1224
|
saw_digit = 1; \
|
|
631
1225
|
} \
|
|
632
1226
|
} while (0)
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
#else
|
|
644
|
-
#define TAPE_NUM_OK_INLINE
|
|
645
|
-
#endif
|
|
646
|
-
static TAPE_NUM_OK_INLINE int tape_num_ok(const char* p, size_t len) {
|
|
647
|
-
size_t k = 0;
|
|
648
|
-
if (k < len && p[k] == '-') {
|
|
649
|
-
k++;
|
|
650
|
-
}
|
|
651
|
-
size_t int_start = k;
|
|
652
|
-
while (k < len && (unsigned)(unsigned char)p[k] - '0' <= 9u) {
|
|
653
|
-
k++;
|
|
654
|
-
}
|
|
655
|
-
if (k == int_start) {
|
|
656
|
-
return 0; /* no integer part */
|
|
657
|
-
}
|
|
658
|
-
if (k - int_start > 1 && p[int_start] == '0') {
|
|
659
|
-
return 0; /* leading zero */
|
|
660
|
-
}
|
|
661
|
-
if (k < len && p[k] == '.') {
|
|
662
|
-
k++;
|
|
663
|
-
size_t frac = k;
|
|
664
|
-
while (k < len && (unsigned)(unsigned char)p[k] - '0' <= 9u) {
|
|
665
|
-
k++;
|
|
666
|
-
}
|
|
667
|
-
if (k == frac) {
|
|
668
|
-
return 0;
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
if (k < len && (p[k] == 'e' || p[k] == 'E')) {
|
|
672
|
-
k++;
|
|
673
|
-
if (k < len && (p[k] == '+' || p[k] == '-')) {
|
|
674
|
-
k++;
|
|
675
|
-
}
|
|
676
|
-
size_t exp = k;
|
|
677
|
-
while (k < len && (unsigned)(unsigned char)p[k] - '0' <= 9u) {
|
|
678
|
-
k++;
|
|
679
|
-
}
|
|
680
|
-
if (k == exp) {
|
|
681
|
-
return 0;
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
return k == len;
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open,
|
|
688
|
-
yeptris_json_tape* t, int strict_nums, int clean_only) {
|
|
1227
|
+
static YeptrisStatus yep_tape_walk_columns_fused(const char* p, size_t len, size_t open,
|
|
1228
|
+
yeptris_json_tape* t, int strict_nums,
|
|
1229
|
+
int clean_only) {
|
|
1230
|
+
/* The columns-primary edition of the record walk below: the same
|
|
1231
|
+
* arms (specialized member cycles, LSTR_SCAN, the digits law)
|
|
1232
|
+
* emitting the three columns directly — one pass, no records, no
|
|
1233
|
+
* materialization pass. The strict route's columns-eager contract
|
|
1234
|
+
* at the lenient lane's memory traffic. The record walk stays
|
|
1235
|
+
* byte-identical beside it; the differential suites pin the
|
|
1236
|
+
* equivalence. */
|
|
689
1237
|
if (tape_carve(t, len) != YEPTRIS_OK) {
|
|
690
1238
|
return YEPTRIS_ERROR_MEMORY;
|
|
691
1239
|
}
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
yeptris_tape_rec* recs = t->recs;
|
|
1240
|
+
uint8_t* kinds = t->kinds;
|
|
1241
|
+
uint32_t* offs = t->offs;
|
|
1242
|
+
uint32_t* lens = t->lens;
|
|
696
1243
|
uint32_t open_at[YEP_JSON_WALK_DEPTH];
|
|
697
1244
|
uint8_t kind[YEP_JSON_WALK_DEPTH];
|
|
698
1245
|
|
|
699
|
-
|
|
1246
|
+
kinds[0] = (uint8_t)YEP_T_DOC;
|
|
1247
|
+
offs[0] = 0;
|
|
1248
|
+
lens[0] = 0;
|
|
700
1249
|
|
|
701
1250
|
uint8_t top_kind = p[open] == '[' ? 0 : 1;
|
|
702
|
-
|
|
703
|
-
|
|
1251
|
+
kinds[1] = top_kind ? (uint8_t)YEP_T_MAP_OPEN : (uint8_t)YEP_T_SEQ_OPEN;
|
|
1252
|
+
offs[1] = 0;
|
|
1253
|
+
lens[1] = 0;
|
|
704
1254
|
size_t count = 2;
|
|
705
1255
|
int depth = 1;
|
|
706
1256
|
open_at[0] = 1;
|
|
@@ -753,8 +1303,9 @@ YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open
|
|
|
753
1303
|
if (depth >= YEP_JSON_WALK_DEPTH) { \
|
|
754
1304
|
goto lreject; \
|
|
755
1305
|
} \
|
|
756
|
-
|
|
757
|
-
|
|
1306
|
+
kinds[count] = (k) ? (uint8_t)YEP_T_MAP_OPEN : (uint8_t)YEP_T_SEQ_OPEN; \
|
|
1307
|
+
offs[count] = 0; \
|
|
1308
|
+
lens[count] = 0; \
|
|
758
1309
|
kind[depth] = (k); \
|
|
759
1310
|
open_at[depth] = (uint32_t)count; \
|
|
760
1311
|
count++; \
|
|
@@ -765,9 +1316,10 @@ YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open
|
|
|
765
1316
|
#define LCLOSE() \
|
|
766
1317
|
do { \
|
|
767
1318
|
uint32_t lo_ = open_at[depth - 1]; \
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
1319
|
+
kinds[count] = (uint8_t)YEP_T_CLOSE; \
|
|
1320
|
+
offs[count] = lo_; \
|
|
1321
|
+
lens[count] = 0; \
|
|
1322
|
+
offs[lo_] = (uint32_t)count; \
|
|
771
1323
|
count++; \
|
|
772
1324
|
i++; \
|
|
773
1325
|
depth--; \
|
|
@@ -801,8 +1353,9 @@ YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open
|
|
|
801
1353
|
uint64_t hi_ = cl ? (w_ & 0x8080808080808080ull) : 0; \
|
|
802
1354
|
if (qm_ != 0 && ((bm_ | c0_ | hi_) & (qm_ - 1)) == 0) { \
|
|
803
1355
|
size_t cl_ = j_ + (size_t)yep_ctz64(qm_) / 8; \
|
|
804
|
-
|
|
805
|
-
|
|
1356
|
+
kinds[count] = (uint8_t)YEP_T_STR; \
|
|
1357
|
+
offs[count] = (uint32_t)(j_); \
|
|
1358
|
+
lens[count] = (uint32_t)((cl_ - j_)); \
|
|
806
1359
|
count++; \
|
|
807
1360
|
i = cl_ + 1; \
|
|
808
1361
|
goto after; \
|
|
@@ -827,9 +1380,9 @@ YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open
|
|
|
827
1380
|
hi_ = cl ? (w_ & 0x8080808080808080ull) : 0; \
|
|
828
1381
|
if (qm_ != 0 && ((bm_ | c0_ | hi_) & (qm_ - 1)) == 0) { \
|
|
829
1382
|
size_t cl_ = b2_ + (size_t)yep_ctz64(qm_) / 8; \
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
1383
|
+
kinds[count] = (uint8_t)YEP_T_STR; \
|
|
1384
|
+
offs[count] = (uint32_t)(j_); \
|
|
1385
|
+
lens[count] = (uint32_t)((cl_ - j_)); \
|
|
833
1386
|
count++; \
|
|
834
1387
|
i = cl_ + 1; \
|
|
835
1388
|
goto after; \
|
|
@@ -866,8 +1419,9 @@ YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open
|
|
|
866
1419
|
b_++; \
|
|
867
1420
|
} \
|
|
868
1421
|
} \
|
|
869
|
-
|
|
870
|
-
|
|
1422
|
+
kinds[count] = (uint8_t)YEP_T_STR; \
|
|
1423
|
+
offs[count] = (uint32_t)(j_); \
|
|
1424
|
+
lens[count] = (uint32_t)((cl_ - j_)); \
|
|
871
1425
|
count++; \
|
|
872
1426
|
i = cl_ + 1; \
|
|
873
1427
|
goto after; \
|
|
@@ -889,8 +1443,9 @@ YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open
|
|
|
889
1443
|
} \
|
|
890
1444
|
} \
|
|
891
1445
|
} \
|
|
892
|
-
|
|
893
|
-
|
|
1446
|
+
kinds[count] = (uint8_t)YEP_T_STR; \
|
|
1447
|
+
offs[count] = (uint32_t)((at_ + 1)); \
|
|
1448
|
+
lens[count] = (uint32_t)((cl_ - at_ - 1)); \
|
|
894
1449
|
count++; \
|
|
895
1450
|
i = cl_ + 1; \
|
|
896
1451
|
} \
|
|
@@ -987,8 +1542,11 @@ lmapval: {
|
|
|
987
1542
|
goto lreject;
|
|
988
1543
|
}
|
|
989
1544
|
}
|
|
990
|
-
|
|
991
|
-
|
|
1545
|
+
kinds[count] =
|
|
1546
|
+
strict_nums ? ((digits_only && saw_digit) ? (uint8_t)YEP_T_INT : (uint8_t)YEP_T_FLOAT)
|
|
1547
|
+
: (uint8_t)YEP_T_NUM;
|
|
1548
|
+
offs[count] = (uint32_t)i;
|
|
1549
|
+
lens[count] = (uint32_t)(k - i);
|
|
992
1550
|
count++;
|
|
993
1551
|
i = k;
|
|
994
1552
|
goto lmapafter;
|
|
@@ -1013,8 +1571,10 @@ lmapval: {
|
|
|
1013
1571
|
goto lreject;
|
|
1014
1572
|
}
|
|
1015
1573
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1574
|
+
kinds[count] = c == 'n' ? (uint8_t)YEP_T_NULL
|
|
1575
|
+
: (c == 't' ? (uint8_t)YEP_T_TRUE : (uint8_t)YEP_T_FALSE);
|
|
1576
|
+
offs[count] = (uint32_t)i;
|
|
1577
|
+
lens[count] = (uint32_t)wl;
|
|
1018
1578
|
count++;
|
|
1019
1579
|
i += wl;
|
|
1020
1580
|
goto lmapafter;
|
|
@@ -1096,8 +1656,11 @@ lseqval: {
|
|
|
1096
1656
|
goto lreject;
|
|
1097
1657
|
}
|
|
1098
1658
|
}
|
|
1099
|
-
|
|
1100
|
-
|
|
1659
|
+
kinds[count] =
|
|
1660
|
+
strict_nums ? ((digits_only && saw_digit) ? (uint8_t)YEP_T_INT : (uint8_t)YEP_T_FLOAT)
|
|
1661
|
+
: (uint8_t)YEP_T_NUM;
|
|
1662
|
+
offs[count] = (uint32_t)i;
|
|
1663
|
+
lens[count] = (uint32_t)(k - i);
|
|
1101
1664
|
count++;
|
|
1102
1665
|
i = k;
|
|
1103
1666
|
goto lseqafter;
|
|
@@ -1122,8 +1685,10 @@ lseqval: {
|
|
|
1122
1685
|
goto lreject;
|
|
1123
1686
|
}
|
|
1124
1687
|
}
|
|
1125
|
-
|
|
1126
|
-
|
|
1688
|
+
kinds[count] = c == 'n' ? (uint8_t)YEP_T_NULL
|
|
1689
|
+
: (c == 't' ? (uint8_t)YEP_T_TRUE : (uint8_t)YEP_T_FALSE);
|
|
1690
|
+
offs[count] = (uint32_t)i;
|
|
1691
|
+
lens[count] = (uint32_t)wl;
|
|
1127
1692
|
count++;
|
|
1128
1693
|
i += wl;
|
|
1129
1694
|
goto lseqafter;
|
|
@@ -1182,6 +1747,7 @@ ldone:
|
|
|
1182
1747
|
t->count = count;
|
|
1183
1748
|
t->_src = p;
|
|
1184
1749
|
t->_srclen = len;
|
|
1750
|
+
t->_cols_ready = 1;
|
|
1185
1751
|
return YEPTRIS_OK;
|
|
1186
1752
|
|
|
1187
1753
|
lreject:
|
|
@@ -1411,243 +1977,6 @@ reject:
|
|
|
1411
1977
|
return YEPTRIS_ERROR_PARSE;
|
|
1412
1978
|
}
|
|
1413
1979
|
|
|
1414
|
-
/* The span walk, single-pass edition: the classifier writes per-block
|
|
1415
|
-
* masks (no idx array, no emission loop), and this walk derives each
|
|
1416
|
-
* block's token mask in registers and dispatches straight off the set
|
|
1417
|
-
* bits. Numbers/keywords have no entry — a pending scalar occupies
|
|
1418
|
-
* [val_start, next token) and is recorded (with its charset
|
|
1419
|
-
* validation) when the next token arrives. String closes come from a
|
|
1420
|
-
* backward quote scan over a few bytes. Escape-carrying documents
|
|
1421
|
-
* never reach here (the route sends them to the validating fused
|
|
1422
|
-
* walk), so the fast path never scans string content. Same
|
|
1423
|
-
* accept/reject contract as the fused lenient walk (the differential
|
|
1424
|
-
* suite pins both). */
|
|
1425
|
-
static YEP_UNUSED_FN YeptrisStatus tape_walk_lnt_span(const char* p, size_t len, size_t open,
|
|
1426
|
-
const struct yep_s1_block* blocks,
|
|
1427
|
-
size_t nblocks, yeptris_json_tape* t) {
|
|
1428
|
-
if (tape_carve(t, len) != YEPTRIS_OK) {
|
|
1429
|
-
return YEPTRIS_ERROR_MEMORY;
|
|
1430
|
-
}
|
|
1431
|
-
t->_rec_primary = 1;
|
|
1432
|
-
yeptris_tape_rec* recs = t->recs;
|
|
1433
|
-
uint32_t open_at[YEP_JSON_WALK_DEPTH];
|
|
1434
|
-
uint8_t kind[YEP_JSON_WALK_DEPTH];
|
|
1435
|
-
|
|
1436
|
-
recs[0] = ((uint64_t)0 << 32) | ((uint64_t)0 << 8) | YEP_T_DOC;
|
|
1437
|
-
uint8_t top_kind = p[open] == '[' ? 0 : 1;
|
|
1438
|
-
recs[1] =
|
|
1439
|
-
((uint64_t)0 << 32) | ((uint64_t)0 << 8) | (top_kind ? YEP_T_MAP_OPEN : YEP_T_SEQ_OPEN);
|
|
1440
|
-
uint32_t top_open = 1;
|
|
1441
|
-
size_t count = 2;
|
|
1442
|
-
uint8_t top_expect = top_kind ? JW_KEY_OR_CLOSE : JW_VALUE_OR_CLOSE;
|
|
1443
|
-
int key_slot = top_kind ? 1 : 0;
|
|
1444
|
-
int depth = 1;
|
|
1445
|
-
open_at[0] = top_open;
|
|
1446
|
-
kind[0] = top_kind;
|
|
1447
|
-
|
|
1448
|
-
size_t bi = 0;
|
|
1449
|
-
uint64_t tokens = 0;
|
|
1450
|
-
size_t off = 0;
|
|
1451
|
-
size_t val_start = open + 1;
|
|
1452
|
-
size_t pos = 0;
|
|
1453
|
-
for (;;) {
|
|
1454
|
-
while (tokens == 0) {
|
|
1455
|
-
if (bi >= nblocks) {
|
|
1456
|
-
goto reject; /* EOF mid-structure (the root never closed) */
|
|
1457
|
-
}
|
|
1458
|
-
off = (size_t)bi * 64;
|
|
1459
|
-
tokens = blocks[bi].tokens;
|
|
1460
|
-
bi++;
|
|
1461
|
-
}
|
|
1462
|
-
pos = off + (size_t)yep_ctz64(tokens);
|
|
1463
|
-
tokens &= tokens - 1;
|
|
1464
|
-
if (pos == open) {
|
|
1465
|
-
continue; /* the root opener: recs[1] already carries it */
|
|
1466
|
-
}
|
|
1467
|
-
|
|
1468
|
-
/* the pending scalar (numbers/keywords only — a quote would be
|
|
1469
|
-
* a token): [val_start, pos) with trailing ws trimmed. All-ws
|
|
1470
|
-
* residue is harmless; a required value/key is satisfied by a
|
|
1471
|
-
* quote entry (the string arm) or a container. */
|
|
1472
|
-
if (val_start < pos) {
|
|
1473
|
-
size_t end = pos;
|
|
1474
|
-
while (end > val_start && (p[end - 1] == ' ' || p[end - 1] == '\t' ||
|
|
1475
|
-
p[end - 1] == '\n' || p[end - 1] == '\r')) {
|
|
1476
|
-
end--;
|
|
1477
|
-
}
|
|
1478
|
-
size_t vs = val_start;
|
|
1479
|
-
while (vs < end && (p[vs] == ' ' || p[vs] == '\t' || p[vs] == '\n' || p[vs] == '\r')) {
|
|
1480
|
-
vs++;
|
|
1481
|
-
}
|
|
1482
|
-
if (vs < end) {
|
|
1483
|
-
char h = p[vs];
|
|
1484
|
-
if (top_expect != JW_VALUE && top_expect != JW_VALUE_OR_CLOSE) {
|
|
1485
|
-
goto reject; /* bytes where no value may start: {x} [1 2] */
|
|
1486
|
-
}
|
|
1487
|
-
if (h == 't' || h == 'f' || h == 'n') {
|
|
1488
|
-
size_t wl = h == 'f' ? 5 : 4;
|
|
1489
|
-
if (end - vs != wl || memcmp(p + vs,
|
|
1490
|
-
h == 't' ? "true"
|
|
1491
|
-
: h == 'n' ? "null"
|
|
1492
|
-
: "false",
|
|
1493
|
-
wl) != 0) {
|
|
1494
|
-
goto reject;
|
|
1495
|
-
}
|
|
1496
|
-
recs[count] =
|
|
1497
|
-
((uint64_t)((uint32_t)vs) << 32) | ((uint64_t)((uint32_t)wl) << 8) |
|
|
1498
|
-
(uint64_t)(h == 'n' ? YEP_T_NULL : (h == 't' ? YEP_T_TRUE : YEP_T_FALSE));
|
|
1499
|
-
count++;
|
|
1500
|
-
} else {
|
|
1501
|
-
if (!((unsigned)(h - '0') <= 9u || h == '-')) {
|
|
1502
|
-
goto reject;
|
|
1503
|
-
}
|
|
1504
|
-
for (size_t k = vs; k < end; k++) {
|
|
1505
|
-
char d = p[k];
|
|
1506
|
-
if ((d < '0' || d > '9') && d != '-' && d != '+' && d != '.' && d != 'e' &&
|
|
1507
|
-
d != 'E') {
|
|
1508
|
-
goto reject;
|
|
1509
|
-
}
|
|
1510
|
-
}
|
|
1511
|
-
recs[count] = ((uint64_t)((uint32_t)vs) << 32) |
|
|
1512
|
-
((uint64_t)((uint32_t)(end - vs)) << 8) | (uint64_t)(YEP_T_NUM);
|
|
1513
|
-
count++;
|
|
1514
|
-
}
|
|
1515
|
-
top_expect = JW_COMMA_OR_CLOSE;
|
|
1516
|
-
key_slot = 0;
|
|
1517
|
-
} else if ((top_expect == JW_VALUE || top_expect == JW_KEY) &&
|
|
1518
|
-
(p[pos] != '"' && p[pos] != '{' && p[pos] != '[')) {
|
|
1519
|
-
goto reject; /* a value/key was required: [1,] {"a":} */
|
|
1520
|
-
}
|
|
1521
|
-
val_start = pos;
|
|
1522
|
-
} else if ((top_expect == JW_VALUE || top_expect == JW_KEY) &&
|
|
1523
|
-
(p[pos] != '"' && p[pos] != '{' && p[pos] != '[')) {
|
|
1524
|
-
goto reject; /* a value/key was required and none started */
|
|
1525
|
-
}
|
|
1526
|
-
|
|
1527
|
-
{
|
|
1528
|
-
char c = p[pos];
|
|
1529
|
-
if (c == '"') {
|
|
1530
|
-
size_t close = 0;
|
|
1531
|
-
if (top_expect == JW_COMMA_OR_CLOSE || top_expect == JW_COLON) {
|
|
1532
|
-
goto reject; /* ["a" "b"] — no punct between values */
|
|
1533
|
-
}
|
|
1534
|
-
size_t end = (tokens != 0) ? off + (size_t)yep_ctz64(tokens) : 0;
|
|
1535
|
-
if (end == 0) {
|
|
1536
|
-
size_t b2 = bi;
|
|
1537
|
-
while (b2 < nblocks && blocks[b2].q == 0 && blocks[b2].op == 0) {
|
|
1538
|
-
b2++;
|
|
1539
|
-
}
|
|
1540
|
-
end = (b2 < nblocks) ? b2 * 64 : len;
|
|
1541
|
-
uint64_t m = blocks[b2].q | blocks[b2].op;
|
|
1542
|
-
if (b2 < nblocks && m != 0) {
|
|
1543
|
-
end = b2 * 64 + (size_t)yep_ctz64(m);
|
|
1544
|
-
}
|
|
1545
|
-
}
|
|
1546
|
-
/* end may be the close quote itself (the raw q mask
|
|
1547
|
-
* feeds the forward position), so the scan includes it */
|
|
1548
|
-
for (size_t k = end + 1; k-- > pos + 1;) {
|
|
1549
|
-
if (p[k] == '"') {
|
|
1550
|
-
close = k;
|
|
1551
|
-
break;
|
|
1552
|
-
}
|
|
1553
|
-
}
|
|
1554
|
-
if (close == 0) {
|
|
1555
|
-
goto reject;
|
|
1556
|
-
}
|
|
1557
|
-
recs[count] = ((uint64_t)((uint32_t)(pos + 1)) << 32) |
|
|
1558
|
-
((uint64_t)((uint32_t)(close - pos - 1)) << 8) |
|
|
1559
|
-
(uint64_t)(YEP_T_STR);
|
|
1560
|
-
count++;
|
|
1561
|
-
val_start = close + 1;
|
|
1562
|
-
if (key_slot) {
|
|
1563
|
-
top_expect = JW_COLON;
|
|
1564
|
-
} else {
|
|
1565
|
-
top_expect = JW_COMMA_OR_CLOSE;
|
|
1566
|
-
}
|
|
1567
|
-
continue;
|
|
1568
|
-
}
|
|
1569
|
-
if (c == ':') {
|
|
1570
|
-
if (top_expect != JW_COLON) {
|
|
1571
|
-
goto reject;
|
|
1572
|
-
}
|
|
1573
|
-
top_expect = JW_VALUE;
|
|
1574
|
-
key_slot = 0;
|
|
1575
|
-
val_start = pos + 1;
|
|
1576
|
-
continue;
|
|
1577
|
-
}
|
|
1578
|
-
if (c == ',') {
|
|
1579
|
-
if (top_expect != JW_COMMA_OR_CLOSE) {
|
|
1580
|
-
goto reject;
|
|
1581
|
-
}
|
|
1582
|
-
top_expect = top_kind ? JW_KEY : JW_VALUE;
|
|
1583
|
-
key_slot = top_kind ? 1 : 0;
|
|
1584
|
-
val_start = pos + 1;
|
|
1585
|
-
continue;
|
|
1586
|
-
}
|
|
1587
|
-
if (c == ']' || c == '}') {
|
|
1588
|
-
int want = c == ']' ? 0 : 1;
|
|
1589
|
-
if (top_kind != want ||
|
|
1590
|
-
(top_expect != JW_VALUE_OR_CLOSE && top_expect != JW_KEY_OR_CLOSE &&
|
|
1591
|
-
top_expect != JW_COMMA_OR_CLOSE)) {
|
|
1592
|
-
goto reject;
|
|
1593
|
-
}
|
|
1594
|
-
recs[count] = ((uint64_t)top_open << 32) | ((uint64_t)0 << 8) | YEP_T_CLOSE;
|
|
1595
|
-
recs[top_open] = (recs[top_open] & ~(uint64_t)0xFFFFFFFF00000000u) |
|
|
1596
|
-
((uint64_t)(uint32_t)count << 32);
|
|
1597
|
-
count++;
|
|
1598
|
-
depth--;
|
|
1599
|
-
if (depth == 0) {
|
|
1600
|
-
break;
|
|
1601
|
-
}
|
|
1602
|
-
top_kind = kind[depth - 1];
|
|
1603
|
-
top_expect = JW_COMMA_OR_CLOSE;
|
|
1604
|
-
top_open = open_at[depth - 1];
|
|
1605
|
-
key_slot = 0;
|
|
1606
|
-
val_start = pos + 1;
|
|
1607
|
-
continue;
|
|
1608
|
-
}
|
|
1609
|
-
if (c == '{' || c == '[') {
|
|
1610
|
-
if (depth >= YEP_JSON_WALK_DEPTH || key_slot || top_expect == JW_COMMA_OR_CLOSE ||
|
|
1611
|
-
top_expect == JW_COLON) {
|
|
1612
|
-
goto reject;
|
|
1613
|
-
}
|
|
1614
|
-
kind[depth - 1] = top_kind;
|
|
1615
|
-
open_at[depth - 1] = top_open;
|
|
1616
|
-
top_kind = c == '[' ? 0 : 1;
|
|
1617
|
-
recs[count] = ((uint64_t)0 << 32) | ((uint64_t)0 << 8) |
|
|
1618
|
-
(uint64_t)(c == '[' ? YEP_T_SEQ_OPEN : YEP_T_MAP_OPEN);
|
|
1619
|
-
top_open = (uint32_t)count;
|
|
1620
|
-
count++;
|
|
1621
|
-
top_expect = top_kind ? JW_KEY_OR_CLOSE : JW_VALUE_OR_CLOSE;
|
|
1622
|
-
key_slot = top_kind ? 1 : 0;
|
|
1623
|
-
kind[depth] = top_kind;
|
|
1624
|
-
open_at[depth] = top_open;
|
|
1625
|
-
depth++;
|
|
1626
|
-
val_start = pos + 1;
|
|
1627
|
-
continue;
|
|
1628
|
-
}
|
|
1629
|
-
}
|
|
1630
|
-
goto reject;
|
|
1631
|
-
}
|
|
1632
|
-
/* trailing residue: after the root close, only ws may follow */
|
|
1633
|
-
size_t last = pos + 1;
|
|
1634
|
-
while (last < len &&
|
|
1635
|
-
(p[last] == ' ' || p[last] == '\t' || p[last] == '\n' || p[last] == '\r')) {
|
|
1636
|
-
last++;
|
|
1637
|
-
}
|
|
1638
|
-
if (last != len) {
|
|
1639
|
-
goto reject;
|
|
1640
|
-
}
|
|
1641
|
-
t->count = count;
|
|
1642
|
-
t->_src = p;
|
|
1643
|
-
t->_srclen = len;
|
|
1644
|
-
return YEPTRIS_OK;
|
|
1645
|
-
|
|
1646
|
-
reject:
|
|
1647
|
-
yeptris_tape_free(t);
|
|
1648
|
-
return YEPTRIS_ERROR_PARSE;
|
|
1649
|
-
}
|
|
1650
|
-
|
|
1651
1980
|
YEPTRIS_API YeptrisStatus yeptris_parse_json_tape_lenient(const char* source, size_t len,
|
|
1652
1981
|
yeptris_json_tape* tape) {
|
|
1653
1982
|
if ((source == NULL && len != 0) || tape == NULL) {
|
|
@@ -1679,25 +2008,12 @@ YEPTRIS_API YeptrisStatus yeptris_parse_json_tape_lenient(const char* source, si
|
|
|
1679
2008
|
}
|
|
1680
2009
|
|
|
1681
2010
|
if (source[at] == '[' || source[at] == '{') {
|
|
1682
|
-
/* the
|
|
1683
|
-
*
|
|
1684
|
-
*
|
|
1685
|
-
*
|
|
1686
|
-
*
|
|
1687
|
-
|
|
1688
|
-
if (blocks == NULL) {
|
|
1689
|
-
return YEPTRIS_ERROR_MEMORY;
|
|
1690
|
-
}
|
|
1691
|
-
size_t nblocks = 0;
|
|
1692
|
-
unsigned flags = 0;
|
|
1693
|
-
if (yep_text_active()->json_stage1_masks(source, len, blocks, &nblocks, &flags) &&
|
|
1694
|
-
(flags & (YEP_S1_C0_IN_STRING | YEP_S1_HAS_ESCAPE)) == 0) {
|
|
1695
|
-
YeptrisStatus st = tape_walk_lnt_span(source, len, at, blocks, nblocks, tape);
|
|
1696
|
-
free(blocks);
|
|
1697
|
-
return st;
|
|
1698
|
-
}
|
|
1699
|
-
free(blocks);
|
|
1700
|
-
return yep_tape_walk_lenient_fused(source, len, at, tape, 0, 0);
|
|
2011
|
+
/* the fused walk IS the lenient route: one pass beats the
|
|
2012
|
+
* stage-1 + span two-pass on every bench corpus (json-doc
|
|
2013
|
+
* 1.65x, json-users 2.2x — the ledger's #85 scoping), and
|
|
2014
|
+
* this exact call already carried the route's verdicts as the
|
|
2015
|
+
* escape/C0 fallback, so acceptance is unchanged. */
|
|
2016
|
+
return yep_tape_walk_lenient_fused(source, len, at, tape, 0, 0, 0);
|
|
1701
2017
|
}
|
|
1702
2018
|
|
|
1703
2019
|
/* scalar root: one record, same deferred split for numbers */
|
|
@@ -1812,6 +2128,19 @@ YEPTRIS_API YeptrisStatus yeptris_parse_json_tape(const char* source, size_t len
|
|
|
1812
2128
|
free(idx);
|
|
1813
2129
|
}
|
|
1814
2130
|
#endif
|
|
2131
|
+
/* the record-primary fused walk first — the DOM route's
|
|
2132
|
+
* exact call and flags (strict numbers at record time,
|
|
2133
|
+
* clean-only gates; a reject frees the tape internally, so
|
|
2134
|
+
* the column attempt below carves fresh). This route's
|
|
2135
|
+
* contract is COLUMNS-EAGER (the suite reads kinds/offs/
|
|
2136
|
+
* lens directly), so the records materialize here — the
|
|
2137
|
+
* fused scan plus one sequential decode pass, still ahead
|
|
2138
|
+
* of the column walk's inline three-stream writes. */
|
|
2139
|
+
/* the columns-primary fused walk: one pass, columns eager
|
|
2140
|
+
* by construction, strict numbers classified at walk time */
|
|
2141
|
+
if (yep_tape_walk_columns_fused(source, len, off, tape, 1, 1) == YEPTRIS_OK) {
|
|
2142
|
+
return YEPTRIS_OK;
|
|
2143
|
+
}
|
|
1815
2144
|
YeptrisStatus st = tape_walk(source, len, off, tape, 1);
|
|
1816
2145
|
if (st != YEPTRIS_ERROR_PARSE) {
|
|
1817
2146
|
return st; /* OK or MEMORY; a reject falls through */
|