yeptris 0.6.18.2-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 +7 -0
- data/README.adoc +141 -0
- data/ext/build_windows_native.rb +41 -0
- data/ext/libyeptris/extconf.rb +57 -0
- data/ext/yeptris_native/cbor_ruby.c +193 -0
- data/ext/yeptris_native/extconf.rb +47 -0
- data/ext/yeptris_native/json_ruby.c +354 -0
- data/ext/yeptris_native/yeptris_native.c +497 -0
- data/lib/yeptris/cbor.rb +130 -0
- data/lib/yeptris/document.rb +255 -0
- data/lib/yeptris/ffi.rb +426 -0
- data/lib/yeptris/json/descriptor.rb +266 -0
- data/lib/yeptris/json.rb +394 -0
- data/lib/yeptris/materializer.rb +354 -0
- data/lib/yeptris/native-3.4.so +0 -0
- data/lib/yeptris/node.rb +453 -0
- data/lib/yeptris/psych/class_loader.rb +24 -0
- data/lib/yeptris/psych/coder_shim.rb +55 -0
- data/lib/yeptris/psych/drop_in.rb +63 -0
- data/lib/yeptris/psych/encodable.rb +14 -0
- data/lib/yeptris/psych/handler.rb +90 -0
- data/lib/yeptris/psych/parser.rb +105 -0
- data/lib/yeptris/psych/scalar_scanner.rb +149 -0
- data/lib/yeptris/psych/visitors.rb +545 -0
- data/lib/yeptris/psych.rb +622 -0
- data/lib/yeptris/schema.rb +253 -0
- data/lib/yeptris/valueml.rb +455 -0
- data/lib/yeptris/yaml/descriptor.rb +56 -0
- data/lib/yeptris/yaml.rb +422 -0
- data/lib/yeptris.rb +113 -0
- data/libyeptris.so +0 -0
- data/vendor/libyeptris/CMakeLists.txt +254 -0
- data/vendor/libyeptris/cmake/yeptris-config.cmake.in +5 -0
- data/vendor/libyeptris/cmake/yeptris.pc.in +11 -0
- data/vendor/libyeptris/src/CMakeLists.txt +167 -0
- data/vendor/libyeptris/src/include/yeptris/api.h +32 -0
- data/vendor/libyeptris/src/include/yeptris/cbor.h +101 -0
- data/vendor/libyeptris/src/include/yeptris/dom.h +190 -0
- data/vendor/libyeptris/src/include/yeptris/emit.h +81 -0
- data/vendor/libyeptris/src/include/yeptris/error.h +41 -0
- data/vendor/libyeptris/src/include/yeptris/events.h +157 -0
- data/vendor/libyeptris/src/include/yeptris/json.h +45 -0
- data/vendor/libyeptris/src/include/yeptris/json.hpp +258 -0
- data/vendor/libyeptris/src/include/yeptris/jsonc_compat.h +115 -0
- data/vendor/libyeptris/src/include/yeptris/marshal.h +52 -0
- data/vendor/libyeptris/src/include/yeptris/parse.h +48 -0
- data/vendor/libyeptris/src/include/yeptris/plan.h +100 -0
- data/vendor/libyeptris/src/include/yeptris/resolve.h +71 -0
- data/vendor/libyeptris/src/include/yeptris/schema.h +121 -0
- data/vendor/libyeptris/src/include/yeptris/tape.h +123 -0
- data/vendor/libyeptris/src/include/yeptris/types.h +38 -0
- data/vendor/libyeptris/src/include/yeptris/values.h +102 -0
- data/vendor/libyeptris/src/include/yeptris/version.h.in +29 -0
- data/vendor/libyeptris/src/include/yeptris/visit.h +77 -0
- data/vendor/libyeptris/src/include/yeptris/yajl_compat.h +135 -0
- data/vendor/libyeptris/src/include/yeptris.h +23 -0
- data/vendor/libyeptris/src/yeptris/build.c +376 -0
- data/vendor/libyeptris/src/yeptris/cbor/cbor.h +25 -0
- data/vendor/libyeptris/src/yeptris/cbor/decode.c +981 -0
- data/vendor/libyeptris/src/yeptris/cbor/encode.c +835 -0
- data/vendor/libyeptris/src/yeptris/cbor/sink.h +58 -0
- data/vendor/libyeptris/src/yeptris/common/chartype.c +41 -0
- data/vendor/libyeptris/src/yeptris/common/chartype.h +77 -0
- data/vendor/libyeptris/src/yeptris/common/cpu.c +81 -0
- data/vendor/libyeptris/src/yeptris/common/cpu.h +40 -0
- data/vendor/libyeptris/src/yeptris/common/error.c +65 -0
- data/vendor/libyeptris/src/yeptris/common/error.h +79 -0
- data/vendor/libyeptris/src/yeptris/common/mutex.h +45 -0
- data/vendor/libyeptris/src/yeptris/common/nametab.c +275 -0
- data/vendor/libyeptris/src/yeptris/common/nametab.h +68 -0
- data/vendor/libyeptris/src/yeptris/common/port.h +74 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text.c +49 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text.h +295 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text_avx2.c +534 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text_neon.c +662 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text_scalar.c +298 -0
- data/vendor/libyeptris/src/yeptris/common/string_view.c +34 -0
- data/vendor/libyeptris/src/yeptris/common/string_view.h +93 -0
- data/vendor/libyeptris/src/yeptris/doc.h +56 -0
- data/vendor/libyeptris/src/yeptris/dom/dom.c +1192 -0
- data/vendor/libyeptris/src/yeptris/dom/dom.h +312 -0
- data/vendor/libyeptris/src/yeptris/dom/hpool.c +107 -0
- data/vendor/libyeptris/src/yeptris/dom/mapindex.c +173 -0
- data/vendor/libyeptris/src/yeptris/dom/mapindex.h +61 -0
- data/vendor/libyeptris/src/yeptris/dom/mutate.c +431 -0
- data/vendor/libyeptris/src/yeptris/emit/emit.c +434 -0
- data/vendor/libyeptris/src/yeptris/emit/float/api.h +38 -0
- data/vendor/libyeptris/src/yeptris/emit/float/dragon.c +405 -0
- data/vendor/libyeptris/src/yeptris/emit/float/floatint.h +231 -0
- data/vendor/libyeptris/src/yeptris/emit/float/print.c +396 -0
- data/vendor/libyeptris/src/yeptris/emit/style.c +81 -0
- data/vendor/libyeptris/src/yeptris/emit/style.h +24 -0
- data/vendor/libyeptris/src/yeptris/emit/writer.c +816 -0
- data/vendor/libyeptris/src/yeptris/emit/writer.h +76 -0
- data/vendor/libyeptris/src/yeptris/encoding/bom.c +31 -0
- data/vendor/libyeptris/src/yeptris/encoding/encoding.h +63 -0
- data/vendor/libyeptris/src/yeptris/encoding/transcode.c +148 -0
- data/vendor/libyeptris/src/yeptris/encoding/utf8_validate.c +178 -0
- data/vendor/libyeptris/src/yeptris/events/capture.c +150 -0
- data/vendor/libyeptris/src/yeptris/events/capture.h +39 -0
- data/vendor/libyeptris/src/yeptris/events/iterparse.c +208 -0
- data/vendor/libyeptris/src/yeptris/events/pull.c +97 -0
- data/vendor/libyeptris/src/yeptris/events/push.c +104 -0
- data/vendor/libyeptris/src/yeptris/events/recorder.c +107 -0
- data/vendor/libyeptris/src/yeptris/events/values.c +527 -0
- data/vendor/libyeptris/src/yeptris/events/values_priv.h +51 -0
- data/vendor/libyeptris/src/yeptris/events/yaml_compat.c +86 -0
- data/vendor/libyeptris/src/yeptris/events/yaml_compat.h +90 -0
- data/vendor/libyeptris/src/yeptris/jsonapi/jsonc_compat.c +687 -0
- data/vendor/libyeptris/src/yeptris/jsonapi/yajl_compat.c +728 -0
- data/vendor/libyeptris/src/yeptris/marshal.c +782 -0
- data/vendor/libyeptris/src/yeptris/memory/allocator.c +20 -0
- data/vendor/libyeptris/src/yeptris/memory/allocator.h +43 -0
- data/vendor/libyeptris/src/yeptris/memory/arena.c +134 -0
- data/vendor/libyeptris/src/yeptris/memory/arena.h +52 -0
- data/vendor/libyeptris/src/yeptris/memory/pool.c +122 -0
- data/vendor/libyeptris/src/yeptris/memory/pool.h +36 -0
- data/vendor/libyeptris/src/yeptris/parse/engine.c +3698 -0
- data/vendor/libyeptris/src/yeptris/parse/engine.h +65 -0
- data/vendor/libyeptris/src/yeptris/parse/events.h +124 -0
- data/vendor/libyeptris/src/yeptris/parse/numbers.c +349 -0
- data/vendor/libyeptris/src/yeptris/parse/numbers.h +33 -0
- data/vendor/libyeptris/src/yeptris/parse/scalars.c +416 -0
- data/vendor/libyeptris/src/yeptris/parse/scalars.h +75 -0
- data/vendor/libyeptris/src/yeptris/parse.c +737 -0
- data/vendor/libyeptris/src/yeptris/plan.c +824 -0
- data/vendor/libyeptris/src/yeptris/resolve/compat11.c +334 -0
- data/vendor/libyeptris/src/yeptris/resolve/core12.c +143 -0
- data/vendor/libyeptris/src/yeptris/resolve/resolver.h +56 -0
- data/vendor/libyeptris/src/yeptris/resolve/tags.c +58 -0
- data/vendor/libyeptris/src/yeptris/scan/json.c +792 -0
- data/vendor/libyeptris/src/yeptris/scan/json.h +109 -0
- data/vendor/libyeptris/src/yeptris/scan/scan.c +463 -0
- data/vendor/libyeptris/src/yeptris/scan/scan.h +150 -0
- data/vendor/libyeptris/src/yeptris/schema.c +308 -0
- data/vendor/libyeptris/src/yeptris/tape.c +1308 -0
- data/vendor/libyeptris/src/yeptris/tape_in.h +19 -0
- data/vendor/libyeptris/src/yeptris/version.c +7 -0
- data/vendor/libyeptris/src/yeptris/visit/dom_visit.c +115 -0
- data/vendor/libyeptris/src/yeptris/visit/json_visit.c +293 -0
- data/vendor/libyeptris/src/yeptris/visit/yaml_visit.c +127 -0
- metadata +199 -0
|
@@ -0,0 +1,1308 @@
|
|
|
1
|
+
/* tape.c — the compact JSON tape (TODO.restructure/85, v2 records).
|
|
2
|
+
*
|
|
3
|
+
* The strict fused walk drives: one THREE-column record per token
|
|
4
|
+
* (kind byte, off, len) — bools encode in the kind, container links
|
|
5
|
+
* ride the off column, numbers record spans only (the lean shape scan
|
|
6
|
+
* validates; yeptris_tape_convert materializes). Strings stay
|
|
7
|
+
* zero-copy spans. The record budget derives from the input length —
|
|
8
|
+
* every token consumes at least one input byte — so len+2 slots
|
|
9
|
+
* suffice with no pre-pass.
|
|
10
|
+
*
|
|
11
|
+
* Route shape mirrors yeptris_parse_json: a gate-clean container root
|
|
12
|
+
* fuses validation into the walk; everything else validates through
|
|
13
|
+
* yep_json_document first (the error precedence json-suite-strict
|
|
14
|
+
* pins), then builds. The walk's DONE delivers the root close as a
|
|
15
|
+
* token; the root OPEN is synthesized here (walk_init consumes the
|
|
16
|
+
* opener without emitting it). */
|
|
17
|
+
|
|
18
|
+
#include <stdlib.h>
|
|
19
|
+
#include <string.h>
|
|
20
|
+
|
|
21
|
+
#include <yeptris/tape.h>
|
|
22
|
+
|
|
23
|
+
#if defined(__GNUC__)
|
|
24
|
+
#define YEP_UNUSED_FN __attribute__((unused))
|
|
25
|
+
#else
|
|
26
|
+
#define YEP_UNUSED_FN
|
|
27
|
+
#endif
|
|
28
|
+
|
|
29
|
+
#ifndef YEP_TOKEN_CONTRACT_ROUTE
|
|
30
|
+
#define YEP_TOKEN_CONTRACT_ROUTE 0
|
|
31
|
+
#endif
|
|
32
|
+
|
|
33
|
+
#include "common/error.h"
|
|
34
|
+
#include "common/simd_text.h"
|
|
35
|
+
#include "encoding/encoding.h"
|
|
36
|
+
#include "memory/allocator.h"
|
|
37
|
+
#include "scan/json.h"
|
|
38
|
+
|
|
39
|
+
typedef struct {
|
|
40
|
+
yeptris_json_tape* t;
|
|
41
|
+
size_t cap;
|
|
42
|
+
uint32_t open[YEP_JSON_WALK_DEPTH]; /* record indices */
|
|
43
|
+
int depth;
|
|
44
|
+
int oom;
|
|
45
|
+
} tape_ctx;
|
|
46
|
+
|
|
47
|
+
static int rec_put(tape_ctx* c, uint8_t kind, uint32_t off, uint32_t len) {
|
|
48
|
+
if (c->t->count >= c->cap) {
|
|
49
|
+
c->oom = 1;
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
size_t i = c->t->count++;
|
|
53
|
+
c->t->kinds[i] = kind;
|
|
54
|
+
c->t->offs[i] = off;
|
|
55
|
+
c->t->lens[i] = len;
|
|
56
|
+
return 1;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
static YeptrisStatus tape_carve(yeptris_json_tape* t, size_t len) {
|
|
60
|
+
size_t cap = len + 2;
|
|
61
|
+
size_t off_o = (cap + 15) & ~(size_t)15;
|
|
62
|
+
char* block = yep_alloc(yep_system_allocator(),
|
|
63
|
+
off_o + 2 * cap * sizeof(uint32_t) + cap * sizeof(yeptris_tape_rec));
|
|
64
|
+
if (block == NULL) {
|
|
65
|
+
return YEPTRIS_ERROR_MEMORY;
|
|
66
|
+
}
|
|
67
|
+
t->_block = block;
|
|
68
|
+
t->kinds = (uint8_t*)block;
|
|
69
|
+
t->offs = (uint32_t*)(void*)(block + off_o);
|
|
70
|
+
t->lens = t->offs + cap;
|
|
71
|
+
t->recs = (yeptris_tape_rec*)(void*)(t->lens + cap);
|
|
72
|
+
t->count = 0;
|
|
73
|
+
t->int_min = 0;
|
|
74
|
+
t->_rec_primary = 0;
|
|
75
|
+
t->_cols_ready = 0;
|
|
76
|
+
return YEPTRIS_OK;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* The lazy column materialization (TODO.max-perf/07): records are the
|
|
80
|
+
* primary storage on the lenient route; the column ABI materializes
|
|
81
|
+
* from them on first touch. */
|
|
82
|
+
YEPTRIS_API int yeptris_tape_columns(yeptris_json_tape* t) {
|
|
83
|
+
if (t == NULL || !t->_rec_primary || t->recs == NULL || t->_cols_ready) {
|
|
84
|
+
return 0; /* column-primary (the strict route) or ready */
|
|
85
|
+
}
|
|
86
|
+
for (size_t i = 0; i < t->count; i++) {
|
|
87
|
+
yeptris_tape_rec r = t->recs[i];
|
|
88
|
+
t->lens[i] = (uint32_t)((r >> 8) & 0xFFFFFFu);
|
|
89
|
+
t->offs[i] = (uint32_t)(r >> 32);
|
|
90
|
+
t->kinds[i] = (uint8_t)(r & 0xFFu);
|
|
91
|
+
}
|
|
92
|
+
t->_cols_ready = 1;
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* Scalar roots: the walk needs an opener, so a bare root value
|
|
97
|
+
* converts through the same kernels. */
|
|
98
|
+
static int tape_put_root_scalar(tape_ctx* c, const char* p, size_t len, size_t at) {
|
|
99
|
+
char ch = p[at];
|
|
100
|
+
if (ch == '"') {
|
|
101
|
+
size_t i = at;
|
|
102
|
+
size_t close = 0;
|
|
103
|
+
int esc = 0;
|
|
104
|
+
if (!yep_json_string(p, len, &i, &close, &esc)) {
|
|
105
|
+
return 0;
|
|
106
|
+
}
|
|
107
|
+
return rec_put(c, YEP_T_STR, (uint32_t)(at + 1), (uint32_t)(close - at - 1));
|
|
108
|
+
}
|
|
109
|
+
if (ch == 't' || ch == 'f' || ch == 'n') {
|
|
110
|
+
const char* word = ch == 't' ? "true" : (ch == 'f' ? "false" : "null");
|
|
111
|
+
size_t i = at;
|
|
112
|
+
if (!yep_json_literal(p, len, &i, word)) {
|
|
113
|
+
return 0;
|
|
114
|
+
}
|
|
115
|
+
uint8_t kind = ch == 'n' ? YEP_T_NULL : (ch == 't' ? YEP_T_TRUE : YEP_T_FALSE);
|
|
116
|
+
return rec_put(c, kind, (uint32_t)at, (uint32_t)(i - at));
|
|
117
|
+
}
|
|
118
|
+
size_t i = 0;
|
|
119
|
+
int flt = 0;
|
|
120
|
+
if (yep_json_number_shape(p + at, len - at, &i, &flt) == 0) {
|
|
121
|
+
return 0;
|
|
122
|
+
}
|
|
123
|
+
return rec_put(c, flt ? YEP_T_FLOAT : YEP_T_INT, (uint32_t)at, (uint32_t)i);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* One strict walk over p[open] -> records. Returns OK, MEMORY
|
|
127
|
+
* (tape zeroed), or PARSE (walk rejected; tape zeroed).
|
|
128
|
+
* check_tail: the fast route has no document validation, so it
|
|
129
|
+
* rejects trailing garbage here.
|
|
130
|
+
*
|
|
131
|
+
* FUSED specialization of yep_json_walk_next: same states, same
|
|
132
|
+
* rejects, byte for byte — but the token never crosses a call
|
|
133
|
+
* boundary or a tok struct. Cursor, record count, and the
|
|
134
|
+
* top-of-stack (kind/expect/open_at) ride in locals; the depth
|
|
135
|
+
* arrays are only touched on push/pop. Columns write directly
|
|
136
|
+
* (capacity is structurally sound: every record consumes at least
|
|
137
|
+
* one input byte, and the carve holds len+2). yep_json_walk stays
|
|
138
|
+
* the reference machine for DOM/push/pull; tape-diff (corpus + the
|
|
139
|
+
* 2M fuzz parity) pins the equivalence. */
|
|
140
|
+
/* The punctuation inline (the simdjson tape-builder lesson): after a
|
|
141
|
+
* value or a key, the next token is a comma/colon or the close —
|
|
142
|
+
* consume it inline instead of paying a full loop iteration for a
|
|
143
|
+
* one-byte state flip. Anything else (close, garbage, a tab) falls
|
|
144
|
+
* through with the cursor parked for the main loop to judge. */
|
|
145
|
+
static inline uint8_t tape_inline_punct(const char* p, size_t len, size_t* i, uint8_t want) {
|
|
146
|
+
size_t j = *i;
|
|
147
|
+
while (j < len && (p[j] == ' ' || p[j] == '\n' || p[j] == '\r')) {
|
|
148
|
+
j++;
|
|
149
|
+
}
|
|
150
|
+
if (j < len && (uint8_t)p[j] == want) {
|
|
151
|
+
*i = j + 1;
|
|
152
|
+
return 1;
|
|
153
|
+
}
|
|
154
|
+
*i = j;
|
|
155
|
+
return 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
static YeptrisStatus tape_walk(const char* p, size_t len, size_t open, yeptris_json_tape* t,
|
|
159
|
+
int check_tail) {
|
|
160
|
+
if (tape_carve(t, len) != YEPTRIS_OK) {
|
|
161
|
+
return YEPTRIS_ERROR_MEMORY;
|
|
162
|
+
}
|
|
163
|
+
uint8_t* kinds = t->kinds;
|
|
164
|
+
uint32_t* offs = t->offs;
|
|
165
|
+
uint32_t* lens = t->lens;
|
|
166
|
+
size_t cap = len + 2;
|
|
167
|
+
uint32_t open_at[YEP_JSON_WALK_DEPTH];
|
|
168
|
+
uint8_t kind[YEP_JSON_WALK_DEPTH];
|
|
169
|
+
|
|
170
|
+
size_t count = 0;
|
|
171
|
+
kinds[0] = YEP_T_DOC;
|
|
172
|
+
offs[0] = 0;
|
|
173
|
+
lens[0] = 0;
|
|
174
|
+
count = 1;
|
|
175
|
+
|
|
176
|
+
uint8_t top_kind = p[open] == '[' ? 0 : 1;
|
|
177
|
+
kinds[1] = top_kind ? YEP_T_MAP_OPEN : YEP_T_SEQ_OPEN;
|
|
178
|
+
offs[1] = 0; /* the CLOSE arm writes the link */
|
|
179
|
+
lens[1] = 0;
|
|
180
|
+
uint32_t top_open = 1;
|
|
181
|
+
count = 2;
|
|
182
|
+
uint8_t top_expect = top_kind ? JW_KEY_OR_CLOSE : JW_VALUE_OR_CLOSE;
|
|
183
|
+
int depth = 1;
|
|
184
|
+
open_at[0] = top_open;
|
|
185
|
+
kind[0] = top_kind;
|
|
186
|
+
|
|
187
|
+
size_t i = open + 1;
|
|
188
|
+
for (;;) {
|
|
189
|
+
while (i < len && (p[i] == ' ' || p[i] == '\n' || p[i] == '\r')) {
|
|
190
|
+
i++;
|
|
191
|
+
}
|
|
192
|
+
if (i >= len || p[i] == '\t') {
|
|
193
|
+
goto reject;
|
|
194
|
+
}
|
|
195
|
+
size_t at = i;
|
|
196
|
+
char c = p[i];
|
|
197
|
+
|
|
198
|
+
/* walker order: punctuation states first so a value arm cannot
|
|
199
|
+
* fire in JW_COMMA_OR_CLOSE / JW_COLON ("[1 2]" is a reject).
|
|
200
|
+
* Close is legal in COMMA_OR_CLOSE, so it falls through. */
|
|
201
|
+
if (top_expect == JW_COLON) {
|
|
202
|
+
if (c != ':') {
|
|
203
|
+
goto reject;
|
|
204
|
+
}
|
|
205
|
+
top_expect = JW_VALUE;
|
|
206
|
+
i = at + 1;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (top_expect == JW_COMMA_OR_CLOSE) {
|
|
210
|
+
if (c == ',') {
|
|
211
|
+
top_expect = top_kind ? JW_KEY : JW_VALUE;
|
|
212
|
+
i = at + 1;
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
if (c != ']' && c != '}') {
|
|
216
|
+
goto reject;
|
|
217
|
+
}
|
|
218
|
+
/* close falls through */
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
int key_slot = top_kind == 1 && (top_expect == JW_KEY_OR_CLOSE || top_expect == JW_KEY);
|
|
222
|
+
|
|
223
|
+
if ((unsigned)(c - '0') <= 9u || c == '-') {
|
|
224
|
+
if (key_slot) {
|
|
225
|
+
goto reject;
|
|
226
|
+
}
|
|
227
|
+
int flt = 0;
|
|
228
|
+
if (!yep_json_number_shape(p, len, &i, &flt)) {
|
|
229
|
+
goto reject;
|
|
230
|
+
}
|
|
231
|
+
kinds[count] = flt ? YEP_T_FLOAT : YEP_T_INT;
|
|
232
|
+
offs[count] = (uint32_t)at;
|
|
233
|
+
lens[count] = (uint32_t)(i - at);
|
|
234
|
+
count++;
|
|
235
|
+
if (tape_inline_punct(p, len, &i, ',')) {
|
|
236
|
+
top_expect = top_kind ? JW_KEY : JW_VALUE;
|
|
237
|
+
key_slot = top_kind ? 1 : 0;
|
|
238
|
+
} else {
|
|
239
|
+
top_expect = JW_COMMA_OR_CLOSE;
|
|
240
|
+
}
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (c == '"') {
|
|
244
|
+
size_t close = 0;
|
|
245
|
+
int esc = 0;
|
|
246
|
+
if (!yep_json_string(p, len, &i, &close, &esc)) {
|
|
247
|
+
goto reject;
|
|
248
|
+
}
|
|
249
|
+
kinds[count] = YEP_T_STR;
|
|
250
|
+
offs[count] = (uint32_t)(at + 1);
|
|
251
|
+
lens[count] = (uint32_t)(close - at - 1);
|
|
252
|
+
count++;
|
|
253
|
+
if (key_slot) { /* the key's colon, inline */
|
|
254
|
+
if (tape_inline_punct(p, len, &i, ':')) {
|
|
255
|
+
top_expect = JW_VALUE;
|
|
256
|
+
key_slot = 0;
|
|
257
|
+
} else {
|
|
258
|
+
top_expect = JW_COLON;
|
|
259
|
+
}
|
|
260
|
+
} else if (tape_inline_punct(p, len, &i, ',')) {
|
|
261
|
+
top_expect = top_kind ? JW_KEY : JW_VALUE;
|
|
262
|
+
key_slot = top_kind ? 1 : 0;
|
|
263
|
+
} else {
|
|
264
|
+
top_expect = JW_COMMA_OR_CLOSE;
|
|
265
|
+
}
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
if (c == ']' || c == '}') {
|
|
269
|
+
int want = c == ']' ? 0 : 1;
|
|
270
|
+
if (top_kind != want ||
|
|
271
|
+
(top_expect != JW_VALUE_OR_CLOSE && top_expect != JW_KEY_OR_CLOSE &&
|
|
272
|
+
top_expect != JW_COMMA_OR_CLOSE)) {
|
|
273
|
+
goto reject;
|
|
274
|
+
}
|
|
275
|
+
kinds[count] = YEP_T_CLOSE;
|
|
276
|
+
offs[count] = top_open; /* link to the OPEN */
|
|
277
|
+
lens[count] = 0;
|
|
278
|
+
offs[top_open] = (uint32_t)count; /* the OPEN's link back */
|
|
279
|
+
count++;
|
|
280
|
+
depth--;
|
|
281
|
+
i = at + 1;
|
|
282
|
+
if (depth == 0) {
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
top_kind = kind[depth - 1];
|
|
286
|
+
top_expect = JW_COMMA_OR_CLOSE;
|
|
287
|
+
top_open = open_at[depth - 1];
|
|
288
|
+
key_slot = 0; /* never read before the comma resets it —
|
|
289
|
+
set anyway so the flag has one owner */
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
if (c == '{' || c == '[') {
|
|
293
|
+
if (depth >= YEP_JSON_WALK_DEPTH) {
|
|
294
|
+
goto reject;
|
|
295
|
+
}
|
|
296
|
+
if (key_slot) {
|
|
297
|
+
goto reject;
|
|
298
|
+
}
|
|
299
|
+
/* spill current top, then push */
|
|
300
|
+
kind[depth - 1] = top_kind;
|
|
301
|
+
open_at[depth - 1] = top_open;
|
|
302
|
+
top_kind = c == '[' ? 0 : 1;
|
|
303
|
+
kinds[count] = c == '[' ? YEP_T_SEQ_OPEN : YEP_T_MAP_OPEN;
|
|
304
|
+
offs[count] = 0; /* the matching CLOSE writes the link */
|
|
305
|
+
lens[count] = 0;
|
|
306
|
+
top_open = (uint32_t)count;
|
|
307
|
+
count++;
|
|
308
|
+
top_expect = top_kind ? JW_KEY_OR_CLOSE : JW_VALUE_OR_CLOSE;
|
|
309
|
+
kind[depth] = top_kind;
|
|
310
|
+
open_at[depth] = top_open;
|
|
311
|
+
depth++;
|
|
312
|
+
i = at + 1;
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
if (c == 't' || c == 'f' || c == 'n') {
|
|
316
|
+
/* packed literal compare: bounds-checked span first, then
|
|
317
|
+
* one u32 load (false adds its 5th byte) */
|
|
318
|
+
size_t wl = c == 'f' ? 5 : 4;
|
|
319
|
+
if (at + wl > len) {
|
|
320
|
+
goto reject;
|
|
321
|
+
}
|
|
322
|
+
uint32_t got4;
|
|
323
|
+
memcpy(&got4, p + at, 4);
|
|
324
|
+
if (got4 != (c == 't' ? 0x65757274u /* "true" */
|
|
325
|
+
: c == 'n' ? 0x6C6C756Eu /* "null" */
|
|
326
|
+
: 0x736C6166u /* "fals" */) ||
|
|
327
|
+
(c == 'f' && p[at + 4] != 'e')) {
|
|
328
|
+
goto reject;
|
|
329
|
+
}
|
|
330
|
+
if (at + wl < len) {
|
|
331
|
+
char z = p[at + wl];
|
|
332
|
+
if (z != ' ' && z != '\n' && z != '\r' && z != ',' && z != ']' && z != '}' &&
|
|
333
|
+
z != ':') {
|
|
334
|
+
goto reject;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
kinds[count] = c == 'n' ? YEP_T_NULL : (c == 't' ? YEP_T_TRUE : YEP_T_FALSE);
|
|
338
|
+
offs[count] = (uint32_t)at;
|
|
339
|
+
lens[count] = (uint32_t)wl;
|
|
340
|
+
count++;
|
|
341
|
+
i = at + wl;
|
|
342
|
+
if (tape_inline_punct(p, len, &i, ',')) {
|
|
343
|
+
top_expect = top_kind ? JW_KEY : JW_VALUE;
|
|
344
|
+
key_slot = top_kind ? 1 : 0;
|
|
345
|
+
} else {
|
|
346
|
+
top_expect = JW_COMMA_OR_CLOSE;
|
|
347
|
+
}
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
goto reject;
|
|
351
|
+
}
|
|
352
|
+
if (check_tail) {
|
|
353
|
+
size_t tail = i;
|
|
354
|
+
while (tail < len &&
|
|
355
|
+
(p[tail] == ' ' || p[tail] == '\t' || p[tail] == '\n' || p[tail] == '\r')) {
|
|
356
|
+
tail++;
|
|
357
|
+
}
|
|
358
|
+
if (tail != len) {
|
|
359
|
+
goto reject;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (count > cap) {
|
|
363
|
+
goto mem;
|
|
364
|
+
}
|
|
365
|
+
t->count = count;
|
|
366
|
+
t->_src = p;
|
|
367
|
+
t->_srclen = len;
|
|
368
|
+
return YEPTRIS_OK;
|
|
369
|
+
|
|
370
|
+
mem:
|
|
371
|
+
yeptris_tape_free(t);
|
|
372
|
+
return YEPTRIS_ERROR_MEMORY;
|
|
373
|
+
reject:
|
|
374
|
+
yeptris_tape_free(t);
|
|
375
|
+
return YEPTRIS_ERROR_PARSE;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/* The token-contract walk: consumes stage 1's positions — whitespace
|
|
379
|
+
* is never scanned (a one-byte-typical gap check proves the residue
|
|
380
|
+
* since the last token is whitespace), string interiors never appear
|
|
381
|
+
* (yep_json_string stays the authority on closes, escapes, and raw
|
|
382
|
+
* C0), numbers are span records via the shape scan. Same states and
|
|
383
|
+
* rejects as the fused walk; tape-diff pins the equivalence. */
|
|
384
|
+
static YEP_UNUSED_FN YeptrisStatus tape_walk_idx(const char* p, size_t len, size_t open,
|
|
385
|
+
const uint32_t* idx, size_t nidx,
|
|
386
|
+
yeptris_json_tape* t) {
|
|
387
|
+
if (tape_carve(t, len) != YEPTRIS_OK) {
|
|
388
|
+
return YEPTRIS_ERROR_MEMORY;
|
|
389
|
+
}
|
|
390
|
+
uint8_t* kinds = t->kinds;
|
|
391
|
+
uint32_t* offs = t->offs;
|
|
392
|
+
uint32_t* lens = t->lens;
|
|
393
|
+
uint32_t open_at[YEP_JSON_WALK_DEPTH];
|
|
394
|
+
uint8_t kind[YEP_JSON_WALK_DEPTH];
|
|
395
|
+
|
|
396
|
+
size_t count = 0;
|
|
397
|
+
kinds[0] = YEP_T_DOC;
|
|
398
|
+
offs[0] = 0;
|
|
399
|
+
lens[0] = 0;
|
|
400
|
+
count = 1;
|
|
401
|
+
|
|
402
|
+
uint8_t top_kind = p[open] == '[' ? 0 : 1;
|
|
403
|
+
kinds[1] = top_kind ? YEP_T_MAP_OPEN : YEP_T_SEQ_OPEN;
|
|
404
|
+
offs[1] = 0;
|
|
405
|
+
lens[1] = 0;
|
|
406
|
+
uint32_t top_open = 1;
|
|
407
|
+
count = 2;
|
|
408
|
+
uint8_t top_expect = top_kind ? JW_KEY_OR_CLOSE : JW_VALUE_OR_CLOSE;
|
|
409
|
+
/* key_slot as a maintained flag: transitions update it, the loop
|
|
410
|
+
* never recomputes (two compares per token saved) */
|
|
411
|
+
int key_slot = top_kind ? 1 : 0;
|
|
412
|
+
int depth = 1;
|
|
413
|
+
open_at[0] = top_open;
|
|
414
|
+
kind[0] = top_kind;
|
|
415
|
+
|
|
416
|
+
size_t si = 0;
|
|
417
|
+
while (si < nidx && idx[si] <= open) {
|
|
418
|
+
si++; /* the root opener (and anything before it) is consumed */
|
|
419
|
+
}
|
|
420
|
+
size_t prev_end = open + 1;
|
|
421
|
+
for (;;) {
|
|
422
|
+
if (si >= nidx) {
|
|
423
|
+
goto reject; /* EOF mid-structure */
|
|
424
|
+
}
|
|
425
|
+
size_t at = idx[si++];
|
|
426
|
+
if (at >= len) {
|
|
427
|
+
goto reject;
|
|
428
|
+
}
|
|
429
|
+
char c = p[at];
|
|
430
|
+
/* no gap check: every byte class that could hide between
|
|
431
|
+
* tokens is itself a token (dropped scalars are scalar-run
|
|
432
|
+
* starts, raw C0 is a scalar — the state machine rejects
|
|
433
|
+
* them); legal ws is simply invisible. Tabs are ws-class and
|
|
434
|
+
* fall to the document path, exactly like the fused walk. */
|
|
435
|
+
prev_end = at + 1;
|
|
436
|
+
|
|
437
|
+
if (top_expect == JW_COLON) {
|
|
438
|
+
if (c != ':') {
|
|
439
|
+
goto reject;
|
|
440
|
+
}
|
|
441
|
+
top_expect = JW_VALUE;
|
|
442
|
+
key_slot = 0; /* a value follows the colon */
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
if (top_expect == JW_COMMA_OR_CLOSE) {
|
|
446
|
+
if (c == ',') {
|
|
447
|
+
top_expect = top_kind ? JW_KEY : JW_VALUE;
|
|
448
|
+
key_slot = top_kind ? 1 : 0;
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
if (c != ']' && c != '}') {
|
|
452
|
+
goto reject;
|
|
453
|
+
}
|
|
454
|
+
} else if (key_slot) {
|
|
455
|
+
/* KEY position: a string or the container's close — the
|
|
456
|
+
* value arms are unreachable, the chain short-circuits */
|
|
457
|
+
if (c != '"' && c != ']' && c != '}') {
|
|
458
|
+
goto reject;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if ((unsigned)(c - '0') <= 9u || c == '-') {
|
|
463
|
+
size_t i = at;
|
|
464
|
+
int flt = 0;
|
|
465
|
+
if (!yep_json_number_shape(p, len, &i, &flt)) {
|
|
466
|
+
goto reject;
|
|
467
|
+
}
|
|
468
|
+
kinds[count] = flt ? YEP_T_FLOAT : YEP_T_INT;
|
|
469
|
+
offs[count] = (uint32_t)at;
|
|
470
|
+
lens[count] = (uint32_t)(i - at);
|
|
471
|
+
count++;
|
|
472
|
+
prev_end = i;
|
|
473
|
+
top_expect = JW_COMMA_OR_CLOSE;
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
if (c == '"') {
|
|
477
|
+
size_t i = at;
|
|
478
|
+
size_t close = 0;
|
|
479
|
+
int esc = 0;
|
|
480
|
+
if (!yep_json_string(p, len, &i, &close, &esc)) {
|
|
481
|
+
goto reject;
|
|
482
|
+
}
|
|
483
|
+
kinds[count] = YEP_T_STR;
|
|
484
|
+
offs[count] = (uint32_t)(at + 1);
|
|
485
|
+
lens[count] = (uint32_t)(close - at - 1);
|
|
486
|
+
count++;
|
|
487
|
+
prev_end = i;
|
|
488
|
+
top_expect = key_slot ? JW_COLON : JW_COMMA_OR_CLOSE;
|
|
489
|
+
/* key_slot stays 1 through COLON — the value arm clears it */
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
if (c == ']' || c == '}') {
|
|
493
|
+
int want = c == ']' ? 0 : 1;
|
|
494
|
+
if (top_kind != want ||
|
|
495
|
+
(top_expect != JW_VALUE_OR_CLOSE && top_expect != JW_KEY_OR_CLOSE &&
|
|
496
|
+
top_expect != JW_COMMA_OR_CLOSE)) {
|
|
497
|
+
goto reject;
|
|
498
|
+
}
|
|
499
|
+
kinds[count] = YEP_T_CLOSE;
|
|
500
|
+
offs[count] = top_open;
|
|
501
|
+
lens[count] = 0;
|
|
502
|
+
offs[top_open] = (uint32_t)count;
|
|
503
|
+
count++;
|
|
504
|
+
depth--;
|
|
505
|
+
if (depth == 0) {
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
top_kind = kind[depth - 1];
|
|
509
|
+
top_expect = JW_COMMA_OR_CLOSE;
|
|
510
|
+
top_open = open_at[depth - 1];
|
|
511
|
+
key_slot = 0; /* never read before the comma resets it —
|
|
512
|
+
set anyway so the flag has one owner */
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
if (c == '{' || c == '[') {
|
|
516
|
+
if (depth >= YEP_JSON_WALK_DEPTH) {
|
|
517
|
+
goto reject;
|
|
518
|
+
}
|
|
519
|
+
kind[depth - 1] = top_kind;
|
|
520
|
+
open_at[depth - 1] = top_open;
|
|
521
|
+
top_kind = c == '[' ? 0 : 1;
|
|
522
|
+
kinds[count] = c == '[' ? YEP_T_SEQ_OPEN : YEP_T_MAP_OPEN;
|
|
523
|
+
offs[count] = 0;
|
|
524
|
+
lens[count] = 0;
|
|
525
|
+
top_open = (uint32_t)count;
|
|
526
|
+
count++;
|
|
527
|
+
top_expect = top_kind ? JW_KEY_OR_CLOSE : JW_VALUE_OR_CLOSE;
|
|
528
|
+
key_slot = top_kind ? 1 : 0;
|
|
529
|
+
kind[depth] = top_kind;
|
|
530
|
+
open_at[depth] = top_open;
|
|
531
|
+
depth++;
|
|
532
|
+
continue;
|
|
533
|
+
}
|
|
534
|
+
if (c == 't' || c == 'f' || c == 'n') {
|
|
535
|
+
size_t wl = c == 'f' ? 5 : 4;
|
|
536
|
+
if (at + wl > len) {
|
|
537
|
+
goto reject;
|
|
538
|
+
}
|
|
539
|
+
uint32_t got4;
|
|
540
|
+
memcpy(&got4, p + at, 4);
|
|
541
|
+
if (got4 != (c == 't' ? 0x65757274u /* "true" */
|
|
542
|
+
: c == 'n' ? 0x6C6C756Eu /* "null" */
|
|
543
|
+
: 0x736C6166u /* "fals" */) ||
|
|
544
|
+
(c == 'f' && p[at + 4] != 'e')) {
|
|
545
|
+
goto reject;
|
|
546
|
+
}
|
|
547
|
+
if (at + wl < len) {
|
|
548
|
+
char z = p[at + wl];
|
|
549
|
+
if (z != ' ' && z != '\n' && z != '\r' && z != ',' && z != ']' && z != '}' &&
|
|
550
|
+
z != ':') {
|
|
551
|
+
goto reject;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
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;
|
|
562
|
+
}
|
|
563
|
+
goto reject;
|
|
564
|
+
}
|
|
565
|
+
/* trailing whitespace only */
|
|
566
|
+
while (prev_end < len && (p[prev_end] == ' ' || p[prev_end] == '\t' || p[prev_end] == '\n' ||
|
|
567
|
+
p[prev_end] == '\r')) {
|
|
568
|
+
prev_end++;
|
|
569
|
+
}
|
|
570
|
+
if (prev_end != len) {
|
|
571
|
+
goto reject;
|
|
572
|
+
}
|
|
573
|
+
if (count > len + 2) {
|
|
574
|
+
goto mem;
|
|
575
|
+
}
|
|
576
|
+
t->count = count;
|
|
577
|
+
t->_src = p;
|
|
578
|
+
t->_srclen = len;
|
|
579
|
+
return YEPTRIS_OK;
|
|
580
|
+
|
|
581
|
+
mem:
|
|
582
|
+
yeptris_tape_free(t);
|
|
583
|
+
return YEPTRIS_ERROR_MEMORY;
|
|
584
|
+
reject:
|
|
585
|
+
yeptris_tape_free(t);
|
|
586
|
+
return YEPTRIS_ERROR_PARSE;
|
|
587
|
+
}
|
|
588
|
+
|
|
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
|
+
YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open,
|
|
605
|
+
yeptris_json_tape* t) {
|
|
606
|
+
if (tape_carve(t, len) != YEPTRIS_OK) {
|
|
607
|
+
return YEPTRIS_ERROR_MEMORY;
|
|
608
|
+
}
|
|
609
|
+
/* the interleaved records are the primary storage (item 07); the
|
|
610
|
+
* columns materialize lazily via yeptris_tape_columns */
|
|
611
|
+
t->_rec_primary = 1;
|
|
612
|
+
yeptris_tape_rec* recs = t->recs;
|
|
613
|
+
uint32_t open_at[YEP_JSON_WALK_DEPTH];
|
|
614
|
+
uint8_t kind[YEP_JSON_WALK_DEPTH];
|
|
615
|
+
|
|
616
|
+
recs[0] = ((uint64_t)0 << 32) | ((uint64_t)0 << 8) | YEP_T_DOC;
|
|
617
|
+
|
|
618
|
+
uint8_t top_kind = p[open] == '[' ? 0 : 1;
|
|
619
|
+
recs[1] =
|
|
620
|
+
((uint64_t)0 << 32) | ((uint64_t)0 << 8) | (top_kind ? YEP_T_MAP_OPEN : YEP_T_SEQ_OPEN);
|
|
621
|
+
uint32_t top_open = 1;
|
|
622
|
+
size_t count = 2;
|
|
623
|
+
uint8_t top_expect = top_kind ? JW_KEY_OR_CLOSE : JW_VALUE_OR_CLOSE;
|
|
624
|
+
int key_slot = top_kind ? 1 : 0;
|
|
625
|
+
int depth = 1;
|
|
626
|
+
open_at[0] = top_open;
|
|
627
|
+
kind[0] = top_kind;
|
|
628
|
+
|
|
629
|
+
size_t i = open + 1;
|
|
630
|
+
for (;;) {
|
|
631
|
+
while (i < len && (p[i] == ' ' || p[i] == '\n' || p[i] == '\r' || p[i] == '\t')) {
|
|
632
|
+
i++;
|
|
633
|
+
}
|
|
634
|
+
if (i >= len) {
|
|
635
|
+
goto lreject;
|
|
636
|
+
}
|
|
637
|
+
size_t at = i;
|
|
638
|
+
char c = p[i];
|
|
639
|
+
|
|
640
|
+
if (top_expect == JW_COLON) {
|
|
641
|
+
if (c != ':') {
|
|
642
|
+
goto lreject;
|
|
643
|
+
}
|
|
644
|
+
top_expect = JW_VALUE;
|
|
645
|
+
key_slot = 0;
|
|
646
|
+
i = at + 1;
|
|
647
|
+
continue;
|
|
648
|
+
}
|
|
649
|
+
if (top_expect == JW_COMMA_OR_CLOSE) {
|
|
650
|
+
if (c == ',') {
|
|
651
|
+
top_expect = top_kind ? JW_KEY : JW_VALUE;
|
|
652
|
+
key_slot = top_kind ? 1 : 0;
|
|
653
|
+
i = at + 1;
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
if (c != ']' && c != '}') {
|
|
657
|
+
goto lreject;
|
|
658
|
+
}
|
|
659
|
+
} else if (key_slot && c != '"' && c != ']' && c != '}') {
|
|
660
|
+
goto lreject;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
if (c == '"') {
|
|
664
|
+
size_t j = at + 1;
|
|
665
|
+
size_t close = 0;
|
|
666
|
+
/* SWAR settle first (the lenient walk's own fast path); the
|
|
667
|
+
* kernel stays the authority on escapes/C0/long spans */
|
|
668
|
+
if (j + 8 <= len) {
|
|
669
|
+
uint64_t w;
|
|
670
|
+
memcpy(&w, p + j, 8);
|
|
671
|
+
uint64_t qm = (w ^ 0x2222222222222222ull);
|
|
672
|
+
uint64_t bm = (w ^ 0x5C5C5C5C5C5C5C5Cull);
|
|
673
|
+
qm = (qm - 0x0101010101010101ull) & ~qm & 0x8080808080808080ull;
|
|
674
|
+
bm = (bm - 0x0101010101010101ull) & ~bm & 0x8080808080808080ull;
|
|
675
|
+
uint64_t c0 = (w - 0x2020202020202020ull) & ~w & 0x8080808080808080ull;
|
|
676
|
+
if (qm != 0 && ((bm | c0) & (qm - 1)) == 0) {
|
|
677
|
+
close = j + (size_t)yep_ctz64(qm) / 8;
|
|
678
|
+
recs[count] = ((uint64_t)((uint32_t)j) << 32) |
|
|
679
|
+
((uint64_t)((uint32_t)(close - j)) << 8) | (uint64_t)(YEP_T_STR);
|
|
680
|
+
count++;
|
|
681
|
+
i = close + 1;
|
|
682
|
+
goto lstr_done;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
int esc = 0;
|
|
686
|
+
if (!yep_json_string(p, len, &i, &close, &esc)) {
|
|
687
|
+
goto lreject;
|
|
688
|
+
}
|
|
689
|
+
recs[count] = ((uint64_t)((uint32_t)(at + 1)) << 32) |
|
|
690
|
+
((uint64_t)((uint32_t)(close - at - 1)) << 8) | (uint64_t)(YEP_T_STR);
|
|
691
|
+
count++;
|
|
692
|
+
lstr_done:
|
|
693
|
+
if (key_slot) {
|
|
694
|
+
if (i < len && p[i] == ':') {
|
|
695
|
+
i++;
|
|
696
|
+
top_expect = JW_VALUE;
|
|
697
|
+
key_slot = 0;
|
|
698
|
+
} else {
|
|
699
|
+
top_expect = JW_COLON;
|
|
700
|
+
}
|
|
701
|
+
} else {
|
|
702
|
+
goto lcomma;
|
|
703
|
+
}
|
|
704
|
+
continue;
|
|
705
|
+
}
|
|
706
|
+
if ((unsigned)(c - '0') <= 9u || c == '-') {
|
|
707
|
+
/* deferred: classify-scan to the run's end — no grammar */
|
|
708
|
+
i = at + 1;
|
|
709
|
+
while (i < len) {
|
|
710
|
+
char d = p[i];
|
|
711
|
+
if ((d >= '0' && d <= '9') || d == '-' || d == '+' || d == '.' || d == 'e' ||
|
|
712
|
+
d == 'E') {
|
|
713
|
+
i++;
|
|
714
|
+
continue;
|
|
715
|
+
}
|
|
716
|
+
break;
|
|
717
|
+
}
|
|
718
|
+
recs[count] = ((uint64_t)((uint32_t)at) << 32) | ((uint64_t)((uint32_t)(i - at)) << 8) |
|
|
719
|
+
(uint64_t)(YEP_T_NUM);
|
|
720
|
+
count++;
|
|
721
|
+
lcomma:
|
|
722
|
+
if (i < len && p[i] == ',') {
|
|
723
|
+
i++;
|
|
724
|
+
top_expect = top_kind ? JW_KEY : JW_VALUE;
|
|
725
|
+
key_slot = top_kind ? 1 : 0;
|
|
726
|
+
} else {
|
|
727
|
+
top_expect = JW_COMMA_OR_CLOSE;
|
|
728
|
+
}
|
|
729
|
+
continue;
|
|
730
|
+
}
|
|
731
|
+
if (c == ']' || c == '}') {
|
|
732
|
+
int want = c == ']' ? 0 : 1;
|
|
733
|
+
if (top_kind != want ||
|
|
734
|
+
(top_expect != JW_VALUE_OR_CLOSE && top_expect != JW_KEY_OR_CLOSE &&
|
|
735
|
+
top_expect != JW_COMMA_OR_CLOSE)) {
|
|
736
|
+
goto lreject;
|
|
737
|
+
}
|
|
738
|
+
recs[count] = ((uint64_t)top_open << 32) | ((uint64_t)0 << 8) | YEP_T_CLOSE;
|
|
739
|
+
/* back-patch the opener's count link: keep the original
|
|
740
|
+
* off/len, set the link into the record's off word */
|
|
741
|
+
recs[top_open] = (recs[top_open] & ~(uint64_t)0xFFFFFFFF00000000u) |
|
|
742
|
+
((uint64_t)(uint32_t)count << 32);
|
|
743
|
+
count++;
|
|
744
|
+
i = at + 1;
|
|
745
|
+
depth--;
|
|
746
|
+
if (depth == 0) {
|
|
747
|
+
break;
|
|
748
|
+
}
|
|
749
|
+
top_kind = kind[depth - 1];
|
|
750
|
+
top_expect = JW_COMMA_OR_CLOSE;
|
|
751
|
+
top_open = open_at[depth - 1];
|
|
752
|
+
key_slot = 0;
|
|
753
|
+
continue;
|
|
754
|
+
}
|
|
755
|
+
if (c == '{' || c == '[') {
|
|
756
|
+
if (depth >= YEP_JSON_WALK_DEPTH) {
|
|
757
|
+
goto lreject;
|
|
758
|
+
}
|
|
759
|
+
if (key_slot) {
|
|
760
|
+
goto lreject;
|
|
761
|
+
}
|
|
762
|
+
kind[depth - 1] = top_kind;
|
|
763
|
+
open_at[depth - 1] = top_open;
|
|
764
|
+
top_kind = c == '[' ? 0 : 1;
|
|
765
|
+
recs[count] = ((uint64_t)0 << 32) | ((uint64_t)0 << 8) |
|
|
766
|
+
(uint64_t)(c == '[' ? YEP_T_SEQ_OPEN : YEP_T_MAP_OPEN);
|
|
767
|
+
top_open = (uint32_t)count;
|
|
768
|
+
count++;
|
|
769
|
+
top_expect = top_kind ? JW_KEY_OR_CLOSE : JW_VALUE_OR_CLOSE;
|
|
770
|
+
key_slot = top_kind ? 1 : 0;
|
|
771
|
+
kind[depth] = top_kind;
|
|
772
|
+
open_at[depth] = top_open;
|
|
773
|
+
depth++;
|
|
774
|
+
i = at + 1;
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
777
|
+
if (c == 't' || c == 'f' || c == 'n') {
|
|
778
|
+
size_t wl = c == 'f' ? 5 : 4;
|
|
779
|
+
if (at + wl > len) {
|
|
780
|
+
goto lreject;
|
|
781
|
+
}
|
|
782
|
+
uint32_t got4;
|
|
783
|
+
memcpy(&got4, p + at, 4);
|
|
784
|
+
if (got4 != (c == 't' ? 0x65757274u /* "true" */
|
|
785
|
+
: c == 'n' ? 0x6C6C756Eu /* "null" */
|
|
786
|
+
: 0x736C6166u /* "fals" */) ||
|
|
787
|
+
(c == 'f' && p[at + 4] != 'e')) {
|
|
788
|
+
goto lreject;
|
|
789
|
+
}
|
|
790
|
+
if (at + wl < len) {
|
|
791
|
+
char z = p[at + wl];
|
|
792
|
+
if (z != ' ' && z != '\t' && z != '\n' && z != '\r' && z != ',' && z != ']' &&
|
|
793
|
+
z != '}' && z != ':') {
|
|
794
|
+
goto lreject;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
recs[count] = ((uint64_t)((uint32_t)at) << 32) | ((uint64_t)((uint32_t)wl) << 8) |
|
|
798
|
+
(uint64_t)(c == 'n' ? YEP_T_NULL : (c == 't' ? YEP_T_TRUE : YEP_T_FALSE));
|
|
799
|
+
count++;
|
|
800
|
+
i = at + wl;
|
|
801
|
+
goto lcomma;
|
|
802
|
+
}
|
|
803
|
+
goto lreject;
|
|
804
|
+
}
|
|
805
|
+
{
|
|
806
|
+
size_t tail = i;
|
|
807
|
+
while (tail < len &&
|
|
808
|
+
(p[tail] == ' ' || p[tail] == '\t' || p[tail] == '\n' || p[tail] == '\r')) {
|
|
809
|
+
tail++;
|
|
810
|
+
}
|
|
811
|
+
if (tail != len) {
|
|
812
|
+
goto lreject;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
t->count = count;
|
|
816
|
+
t->_src = p;
|
|
817
|
+
t->_srclen = len;
|
|
818
|
+
return YEPTRIS_OK;
|
|
819
|
+
|
|
820
|
+
lreject:
|
|
821
|
+
yeptris_tape_free(t);
|
|
822
|
+
return YEPTRIS_ERROR_PARSE;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
static YEP_UNUSED_FN YeptrisStatus tape_walk_lnt(const char* p, size_t len, size_t open,
|
|
826
|
+
const uint32_t* idx, size_t nidx,
|
|
827
|
+
yeptris_json_tape* t) {
|
|
828
|
+
if (tape_carve(t, len) != YEPTRIS_OK) {
|
|
829
|
+
return YEPTRIS_ERROR_MEMORY;
|
|
830
|
+
}
|
|
831
|
+
uint8_t* kinds = t->kinds;
|
|
832
|
+
uint32_t* offs = t->offs;
|
|
833
|
+
uint32_t* lens = t->lens;
|
|
834
|
+
uint32_t open_at[YEP_JSON_WALK_DEPTH];
|
|
835
|
+
uint8_t kind[YEP_JSON_WALK_DEPTH];
|
|
836
|
+
|
|
837
|
+
kinds[0] = YEP_T_DOC;
|
|
838
|
+
offs[0] = 0;
|
|
839
|
+
lens[0] = 0;
|
|
840
|
+
|
|
841
|
+
uint8_t top_kind = p[open] == '[' ? 0 : 1;
|
|
842
|
+
kinds[1] = top_kind ? YEP_T_MAP_OPEN : YEP_T_SEQ_OPEN;
|
|
843
|
+
offs[1] = 0;
|
|
844
|
+
lens[1] = 0;
|
|
845
|
+
uint32_t top_open = 1;
|
|
846
|
+
size_t count = 2;
|
|
847
|
+
uint8_t top_expect = top_kind ? JW_KEY_OR_CLOSE : JW_VALUE_OR_CLOSE;
|
|
848
|
+
int key_slot = top_kind ? 1 : 0;
|
|
849
|
+
int depth = 1;
|
|
850
|
+
open_at[0] = top_open;
|
|
851
|
+
kind[0] = top_kind;
|
|
852
|
+
|
|
853
|
+
size_t si = 0;
|
|
854
|
+
while (si < nidx && idx[si] <= open) {
|
|
855
|
+
si++; /* the root opener (and anything before it) is consumed */
|
|
856
|
+
}
|
|
857
|
+
for (;;) {
|
|
858
|
+
if (si >= nidx) {
|
|
859
|
+
goto reject; /* EOF mid-structure */
|
|
860
|
+
}
|
|
861
|
+
size_t at = idx[si++];
|
|
862
|
+
if (at >= len) {
|
|
863
|
+
goto reject;
|
|
864
|
+
}
|
|
865
|
+
char c = p[at];
|
|
866
|
+
|
|
867
|
+
if (top_expect == JW_COLON) {
|
|
868
|
+
if (c != ':') {
|
|
869
|
+
goto reject;
|
|
870
|
+
}
|
|
871
|
+
top_expect = JW_VALUE;
|
|
872
|
+
key_slot = 0;
|
|
873
|
+
continue;
|
|
874
|
+
}
|
|
875
|
+
if (top_expect == JW_COMMA_OR_CLOSE) {
|
|
876
|
+
if (c == ',') {
|
|
877
|
+
top_expect = top_kind ? JW_KEY : JW_VALUE;
|
|
878
|
+
key_slot = top_kind ? 1 : 0;
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
881
|
+
if (c != ']' && c != '}') {
|
|
882
|
+
goto reject;
|
|
883
|
+
}
|
|
884
|
+
} else if (key_slot) {
|
|
885
|
+
if (c != '"' && c != ']' && c != '}') {
|
|
886
|
+
goto reject;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
if (c == '"') {
|
|
891
|
+
size_t j = at + 1;
|
|
892
|
+
size_t close = 0;
|
|
893
|
+
int esc = 0;
|
|
894
|
+
/* SWAR settle: one u64 window closes the corpus's 1-8
|
|
895
|
+
* byte strings without the call; anything else (escape,
|
|
896
|
+
* C0, longer) falls back to the kernel authority */
|
|
897
|
+
if (j + 8 <= len) {
|
|
898
|
+
uint64_t w;
|
|
899
|
+
memcpy(&w, p + j, 8);
|
|
900
|
+
uint64_t qm = (w ^ 0x2222222222222222ull);
|
|
901
|
+
uint64_t bm = (w ^ 0x5C5C5C5C5C5C5C5Cull);
|
|
902
|
+
qm = (qm - 0x0101010101010101ull) & ~qm & 0x8080808080808080ull;
|
|
903
|
+
bm = (bm - 0x0101010101010101ull) & ~bm & 0x8080808080808080ull;
|
|
904
|
+
uint64_t c0 = (w - 0x2020202020202020ull) & ~w & 0x8080808080808080ull;
|
|
905
|
+
if (qm != 0 && ((bm | c0) & (qm - 1)) == 0) {
|
|
906
|
+
close = j + (size_t)yep_ctz64(qm) / 8;
|
|
907
|
+
kinds[count] = YEP_T_STR;
|
|
908
|
+
offs[count] = (uint32_t)j;
|
|
909
|
+
lens[count] = (uint32_t)(close - j);
|
|
910
|
+
count++;
|
|
911
|
+
goto str_done;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
size_t i = at;
|
|
915
|
+
if (!yep_json_string(p, len, &i, &close, &esc)) {
|
|
916
|
+
goto reject;
|
|
917
|
+
}
|
|
918
|
+
kinds[count] = YEP_T_STR;
|
|
919
|
+
offs[count] = (uint32_t)(at + 1);
|
|
920
|
+
lens[count] = (uint32_t)(close - at - 1);
|
|
921
|
+
count++;
|
|
922
|
+
str_done:
|
|
923
|
+
if (key_slot) {
|
|
924
|
+
/* colon peek: consume it without a loop round */
|
|
925
|
+
if (si < nidx && p[idx[si]] == ':') {
|
|
926
|
+
si++;
|
|
927
|
+
top_expect = JW_VALUE;
|
|
928
|
+
key_slot = 0;
|
|
929
|
+
} else {
|
|
930
|
+
top_expect = JW_COLON;
|
|
931
|
+
}
|
|
932
|
+
} else {
|
|
933
|
+
goto comma_peek;
|
|
934
|
+
}
|
|
935
|
+
continue;
|
|
936
|
+
}
|
|
937
|
+
if ((unsigned)(c - '0') <= 9u || c == '-') {
|
|
938
|
+
/* the deferred arm: the span runs to the next token,
|
|
939
|
+
* trailing ws trimmed — no grammar scan, no shape split */
|
|
940
|
+
size_t end = (si < nidx) ? idx[si] : len;
|
|
941
|
+
while (end > at && (p[end - 1] == ' ' || p[end - 1] == '\t' || p[end - 1] == '\n' ||
|
|
942
|
+
p[end - 1] == '\r')) {
|
|
943
|
+
end--;
|
|
944
|
+
}
|
|
945
|
+
kinds[count] = YEP_T_NUM;
|
|
946
|
+
offs[count] = (uint32_t)at;
|
|
947
|
+
lens[count] = (uint32_t)(end - at);
|
|
948
|
+
count++;
|
|
949
|
+
comma_peek:
|
|
950
|
+
/* comma peek: the value-or-key separator consumes without
|
|
951
|
+
* a loop round (the corpus's dominant cycle) */
|
|
952
|
+
if (si < nidx && p[idx[si]] == ',') {
|
|
953
|
+
si++;
|
|
954
|
+
top_expect = top_kind ? JW_KEY : JW_VALUE;
|
|
955
|
+
key_slot = top_kind ? 1 : 0;
|
|
956
|
+
} else {
|
|
957
|
+
top_expect = JW_COMMA_OR_CLOSE;
|
|
958
|
+
}
|
|
959
|
+
continue;
|
|
960
|
+
}
|
|
961
|
+
if (c == ']' || c == '}') {
|
|
962
|
+
int want = c == ']' ? 0 : 1;
|
|
963
|
+
if (top_kind != want ||
|
|
964
|
+
(top_expect != JW_VALUE_OR_CLOSE && top_expect != JW_KEY_OR_CLOSE &&
|
|
965
|
+
top_expect != JW_COMMA_OR_CLOSE)) {
|
|
966
|
+
goto reject;
|
|
967
|
+
}
|
|
968
|
+
kinds[count] = YEP_T_CLOSE;
|
|
969
|
+
offs[count] = top_open;
|
|
970
|
+
lens[count] = 0;
|
|
971
|
+
offs[top_open] = (uint32_t)count;
|
|
972
|
+
count++;
|
|
973
|
+
depth--;
|
|
974
|
+
if (depth == 0) {
|
|
975
|
+
break;
|
|
976
|
+
}
|
|
977
|
+
top_kind = kind[depth - 1];
|
|
978
|
+
top_expect = JW_COMMA_OR_CLOSE;
|
|
979
|
+
top_open = open_at[depth - 1];
|
|
980
|
+
key_slot = 0;
|
|
981
|
+
continue;
|
|
982
|
+
}
|
|
983
|
+
if (c == '{' || c == '[') {
|
|
984
|
+
if (depth >= YEP_JSON_WALK_DEPTH) {
|
|
985
|
+
goto reject;
|
|
986
|
+
}
|
|
987
|
+
kind[depth - 1] = top_kind;
|
|
988
|
+
open_at[depth - 1] = top_open;
|
|
989
|
+
top_kind = c == '[' ? 0 : 1;
|
|
990
|
+
kinds[count] = c == '[' ? YEP_T_SEQ_OPEN : YEP_T_MAP_OPEN;
|
|
991
|
+
offs[count] = 0;
|
|
992
|
+
lens[count] = 0;
|
|
993
|
+
top_open = (uint32_t)count;
|
|
994
|
+
count++;
|
|
995
|
+
top_expect = top_kind ? JW_KEY_OR_CLOSE : JW_VALUE_OR_CLOSE;
|
|
996
|
+
key_slot = top_kind ? 1 : 0;
|
|
997
|
+
kind[depth] = top_kind;
|
|
998
|
+
open_at[depth] = top_open;
|
|
999
|
+
depth++;
|
|
1000
|
+
continue;
|
|
1001
|
+
}
|
|
1002
|
+
if (c == 't' || c == 'f' || c == 'n') {
|
|
1003
|
+
size_t wl = c == 'f' ? 5 : 4;
|
|
1004
|
+
if (at + wl > len) {
|
|
1005
|
+
goto reject;
|
|
1006
|
+
}
|
|
1007
|
+
uint32_t got4;
|
|
1008
|
+
memcpy(&got4, p + at, 4);
|
|
1009
|
+
if (got4 != (c == 't' ? 0x65757274u /* "true" */
|
|
1010
|
+
: c == 'n' ? 0x6C6C756Eu /* "null" */
|
|
1011
|
+
: 0x736C6166u /* "fals" */) ||
|
|
1012
|
+
(c == 'f' && p[at + 4] != 'e')) {
|
|
1013
|
+
goto reject;
|
|
1014
|
+
}
|
|
1015
|
+
if (at + wl < len) {
|
|
1016
|
+
char z = p[at + wl];
|
|
1017
|
+
if (z != ' ' && z != '\t' && z != '\n' && z != '\r' && z != ',' && z != ']' &&
|
|
1018
|
+
z != '}' && z != ':') {
|
|
1019
|
+
goto reject;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
kinds[count] = c == 'n' ? YEP_T_NULL : (c == 't' ? YEP_T_TRUE : YEP_T_FALSE);
|
|
1023
|
+
offs[count] = (uint32_t)at;
|
|
1024
|
+
lens[count] = (uint32_t)wl;
|
|
1025
|
+
count++;
|
|
1026
|
+
top_expect = JW_COMMA_OR_CLOSE;
|
|
1027
|
+
key_slot = 0;
|
|
1028
|
+
continue;
|
|
1029
|
+
}
|
|
1030
|
+
goto reject;
|
|
1031
|
+
}
|
|
1032
|
+
/* trailing residue: after the root close, any remaining token is
|
|
1033
|
+
* non-ws garbage (pure trailing ws emits no tokens) */
|
|
1034
|
+
if (si != nidx) {
|
|
1035
|
+
goto reject;
|
|
1036
|
+
}
|
|
1037
|
+
t->count = count;
|
|
1038
|
+
t->_src = p;
|
|
1039
|
+
t->_srclen = len;
|
|
1040
|
+
return YEPTRIS_OK;
|
|
1041
|
+
|
|
1042
|
+
reject:
|
|
1043
|
+
yeptris_tape_free(t);
|
|
1044
|
+
return YEPTRIS_ERROR_PARSE;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
YEPTRIS_API YeptrisStatus yeptris_parse_json_tape_lenient(const char* source, size_t len,
|
|
1048
|
+
yeptris_json_tape* tape) {
|
|
1049
|
+
if ((source == NULL && len != 0) || tape == NULL) {
|
|
1050
|
+
return YEPTRIS_ERROR_ARG;
|
|
1051
|
+
}
|
|
1052
|
+
memset(tape, 0, sizeof(*tape));
|
|
1053
|
+
if (len > 0xFFFFFFF0u) {
|
|
1054
|
+
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, 0,
|
|
1055
|
+
"tape spans are uint32; document exceeds 4 GiB");
|
|
1056
|
+
return YEPTRIS_ERROR_ARG;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
/* lenient defers grammar only; strings borrow validated spans, so
|
|
1060
|
+
* the encoding gate keeps the strict fallback (non-ASCII rides
|
|
1061
|
+
* yeptris_parse_json_tape unchanged) */
|
|
1062
|
+
if (len > 0 && yep_text_active()->gate_scan(source, len)) {
|
|
1063
|
+
return yeptris_parse_json_tape(source, len, tape);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
size_t at = 0;
|
|
1067
|
+
while (at < len &&
|
|
1068
|
+
(source[at] == ' ' || source[at] == '\t' || source[at] == '\n' || source[at] == '\r')) {
|
|
1069
|
+
at++;
|
|
1070
|
+
}
|
|
1071
|
+
if (at >= len) {
|
|
1072
|
+
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, at,
|
|
1073
|
+
"empty document (lenient tape)");
|
|
1074
|
+
return YEPTRIS_ERROR_PARSE;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
if (source[at] == '[' || source[at] == '{') {
|
|
1078
|
+
#if YEP_TOKEN_CONTRACT_ROUTE
|
|
1079
|
+
/* the indexed twin: stage 1 + the idx walk (reference route —
|
|
1080
|
+
* measured behind the fused lenient walk, same differential) */
|
|
1081
|
+
uint32_t* idx = (uint32_t*)malloc((len + 2) * sizeof(uint32_t));
|
|
1082
|
+
if (idx == NULL) {
|
|
1083
|
+
return YEPTRIS_ERROR_MEMORY;
|
|
1084
|
+
}
|
|
1085
|
+
size_t nidx = 0;
|
|
1086
|
+
if (yep_text_active()->json_stage1(source, len, idx, &nidx)) {
|
|
1087
|
+
YeptrisStatus st = tape_walk_lnt(source, len, at, idx, nidx, tape);
|
|
1088
|
+
free(idx);
|
|
1089
|
+
return st;
|
|
1090
|
+
}
|
|
1091
|
+
free(idx);
|
|
1092
|
+
#endif
|
|
1093
|
+
return yep_tape_walk_lenient_fused(source, len, at, tape);
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
/* scalar root: one record, same deferred split for numbers */
|
|
1097
|
+
if (tape_carve(tape, len) != YEPTRIS_OK) {
|
|
1098
|
+
return YEPTRIS_ERROR_MEMORY;
|
|
1099
|
+
}
|
|
1100
|
+
tape->_src = source;
|
|
1101
|
+
tape->_srclen = len;
|
|
1102
|
+
tape_ctx c = {tape, len + 2, {0}, 0, 0};
|
|
1103
|
+
if (!rec_put(&c, YEP_T_DOC, 0, 0)) {
|
|
1104
|
+
goto lnt_root_mem;
|
|
1105
|
+
}
|
|
1106
|
+
if (source[at] == '"') {
|
|
1107
|
+
size_t i = at;
|
|
1108
|
+
size_t close = 0;
|
|
1109
|
+
int esc = 0;
|
|
1110
|
+
if (!yep_json_string(source, len, &i, &close, &esc) ||
|
|
1111
|
+
!rec_put(&c, YEP_T_STR, (uint32_t)(at + 1), (uint32_t)(close - at - 1))) {
|
|
1112
|
+
goto lnt_root_reject;
|
|
1113
|
+
}
|
|
1114
|
+
while (i < len &&
|
|
1115
|
+
(source[i] == ' ' || source[i] == '\t' || source[i] == '\n' || source[i] == '\r')) {
|
|
1116
|
+
i++;
|
|
1117
|
+
}
|
|
1118
|
+
if (i != len) {
|
|
1119
|
+
goto lnt_root_reject;
|
|
1120
|
+
}
|
|
1121
|
+
return YEPTRIS_OK;
|
|
1122
|
+
}
|
|
1123
|
+
if (source[at] == 't' || source[at] == 'f' || source[at] == 'n') {
|
|
1124
|
+
const char* word = source[at] == 't' ? "true" : (source[at] == 'f' ? "false" : "null");
|
|
1125
|
+
size_t i = at;
|
|
1126
|
+
if (!yep_json_literal(source, len, &i, word)) {
|
|
1127
|
+
goto lnt_root_reject;
|
|
1128
|
+
}
|
|
1129
|
+
while (i < len &&
|
|
1130
|
+
(source[i] == ' ' || source[i] == '\t' || source[i] == '\n' || source[i] == '\r')) {
|
|
1131
|
+
i++;
|
|
1132
|
+
}
|
|
1133
|
+
if (i != len) {
|
|
1134
|
+
goto lnt_root_reject;
|
|
1135
|
+
}
|
|
1136
|
+
uint8_t k = source[at] == 'n' ? YEP_T_NULL : (source[at] == 't' ? YEP_T_TRUE : YEP_T_FALSE);
|
|
1137
|
+
if (!rec_put(&c, k, (uint32_t)at, (uint32_t)(i - at))) {
|
|
1138
|
+
goto lnt_root_mem;
|
|
1139
|
+
}
|
|
1140
|
+
return YEPTRIS_OK;
|
|
1141
|
+
}
|
|
1142
|
+
{
|
|
1143
|
+
size_t end = len;
|
|
1144
|
+
while (end > at && (source[end - 1] == ' ' || source[end - 1] == '\t' ||
|
|
1145
|
+
source[end - 1] == '\n' || source[end - 1] == '\r')) {
|
|
1146
|
+
end--;
|
|
1147
|
+
}
|
|
1148
|
+
if (!rec_put(&c, YEP_T_NUM, (uint32_t)at, (uint32_t)(end - at))) {
|
|
1149
|
+
goto lnt_root_mem;
|
|
1150
|
+
}
|
|
1151
|
+
return YEPTRIS_OK;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
lnt_root_mem:
|
|
1155
|
+
yeptris_tape_free(tape);
|
|
1156
|
+
return YEPTRIS_ERROR_MEMORY;
|
|
1157
|
+
lnt_root_reject:
|
|
1158
|
+
yeptris_tape_free(tape);
|
|
1159
|
+
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, at,
|
|
1160
|
+
"not strict JSON at byte %zu (lenient tape)", at);
|
|
1161
|
+
return YEPTRIS_ERROR_PARSE;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
YEPTRIS_API YeptrisStatus yeptris_parse_json_tape(const char* source, size_t len,
|
|
1165
|
+
yeptris_json_tape* tape) {
|
|
1166
|
+
if ((source == NULL && len != 0) || tape == NULL) {
|
|
1167
|
+
return YEPTRIS_ERROR_ARG;
|
|
1168
|
+
}
|
|
1169
|
+
memset(tape, 0, sizeof(*tape));
|
|
1170
|
+
if (len > 0xFFFFFFF0u) {
|
|
1171
|
+
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, 0,
|
|
1172
|
+
"tape spans are uint32; document exceeds 4 GiB");
|
|
1173
|
+
return YEPTRIS_ERROR_ARG;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
int gated = len > 0 && yep_text_active()->gate_scan(source, len);
|
|
1177
|
+
if (!gated) {
|
|
1178
|
+
size_t off = 0;
|
|
1179
|
+
while (off < len && (source[off] == ' ' || source[off] == '\t' || source[off] == '\n' ||
|
|
1180
|
+
source[off] == '\r')) {
|
|
1181
|
+
off++;
|
|
1182
|
+
}
|
|
1183
|
+
if (off < len && (source[off] == '[' || source[off] == '{')) {
|
|
1184
|
+
/* the token-contract route: stage 1 (vector indexes) + the
|
|
1185
|
+
* lean walk. Measured BEHIND the fused walk on json-doc
|
|
1186
|
+
* (417-426 vs 526-533: stage 1 at 1408 MB/s + a walk whose
|
|
1187
|
+
* arms carry the same grammar cost) — gated OFF until the
|
|
1188
|
+
* sized cuts land (the op-table classifier trick, the
|
|
1189
|
+
* specialized map/seq loops, stage-1 string closes). The
|
|
1190
|
+
* fused walk is the shipped route; the law. */
|
|
1191
|
+
#if YEP_TOKEN_CONTRACT_ROUTE
|
|
1192
|
+
uint32_t* idx = (uint32_t*)malloc((len + 2) * sizeof(uint32_t));
|
|
1193
|
+
if (idx == NULL) {
|
|
1194
|
+
return YEPTRIS_ERROR_MEMORY;
|
|
1195
|
+
}
|
|
1196
|
+
size_t nidx = 0;
|
|
1197
|
+
if (yep_text_active()->json_stage1(source, len, idx, &nidx)) {
|
|
1198
|
+
YeptrisStatus st = tape_walk_idx(source, len, off, idx, nidx, tape);
|
|
1199
|
+
free(idx);
|
|
1200
|
+
if (st != YEPTRIS_ERROR_PARSE) {
|
|
1201
|
+
return st; /* OK or MEMORY; a reject falls through */
|
|
1202
|
+
}
|
|
1203
|
+
} else {
|
|
1204
|
+
free(idx);
|
|
1205
|
+
}
|
|
1206
|
+
#endif
|
|
1207
|
+
YeptrisStatus st = tape_walk(source, len, off, tape, 1);
|
|
1208
|
+
if (st != YEPTRIS_ERROR_PARSE) {
|
|
1209
|
+
return st; /* OK or MEMORY; a reject falls through */
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
/* The validating sequence — parse_json's fallback, byte for byte
|
|
1215
|
+
* in precedence: grammar, then encoding when the gate tripped. */
|
|
1216
|
+
size_t verr = 0;
|
|
1217
|
+
if (!yep_json_document(source, len, &verr)) {
|
|
1218
|
+
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, verr,
|
|
1219
|
+
"not strict JSON at byte %zu", verr);
|
|
1220
|
+
return YEPTRIS_ERROR_PARSE;
|
|
1221
|
+
}
|
|
1222
|
+
if (gated) {
|
|
1223
|
+
size_t uerr = 0;
|
|
1224
|
+
if (!yep_utf8_validate((const unsigned char*)source, len, &uerr)) {
|
|
1225
|
+
yep_error_set(yep_error_tls(), YEP_ERR_ENCODING, 0, 0, uerr,
|
|
1226
|
+
"ill-formed UTF-8 at byte %zu", uerr);
|
|
1227
|
+
return YEPTRIS_ERROR_ENCODING;
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
size_t at = 0;
|
|
1232
|
+
while (at < len &&
|
|
1233
|
+
(source[at] == ' ' || source[at] == '\t' || source[at] == '\n' || source[at] == '\r')) {
|
|
1234
|
+
at++;
|
|
1235
|
+
}
|
|
1236
|
+
if (at < len && (source[at] == '[' || source[at] == '{')) {
|
|
1237
|
+
YeptrisStatus st = tape_walk(source, len, at, tape, 0);
|
|
1238
|
+
if (st == YEPTRIS_OK || st == YEPTRIS_ERROR_MEMORY) {
|
|
1239
|
+
return st;
|
|
1240
|
+
}
|
|
1241
|
+
yep_error_set(yep_error_tls(), YEP_ERR_INTERNAL, 0, 0, at,
|
|
1242
|
+
"tape walk rejected a validated document at byte %zu", at);
|
|
1243
|
+
return YEPTRIS_ERROR_INTERNAL;
|
|
1244
|
+
}
|
|
1245
|
+
if (tape_carve(tape, len) != YEPTRIS_OK) {
|
|
1246
|
+
return YEPTRIS_ERROR_MEMORY;
|
|
1247
|
+
}
|
|
1248
|
+
tape->_src = source;
|
|
1249
|
+
tape->_srclen = len;
|
|
1250
|
+
tape_ctx c = {tape, len + 2, {0}, 0, 0};
|
|
1251
|
+
if (!rec_put(&c, YEP_T_DOC, 0, 0) || !tape_put_root_scalar(&c, source, len, at)) {
|
|
1252
|
+
yep_error_set(yep_error_tls(), YEP_ERR_INTERNAL, 0, 0, at,
|
|
1253
|
+
"tape scalar conversion rejected a validated root at byte %zu", at);
|
|
1254
|
+
yeptris_tape_free(tape);
|
|
1255
|
+
return YEPTRIS_ERROR_INTERNAL;
|
|
1256
|
+
}
|
|
1257
|
+
return YEPTRIS_OK;
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
YEPTRIS_API size_t yeptris_tape_convert(yeptris_json_tape* t, size_t from, size_t to,
|
|
1261
|
+
int64_t* ivals, double* dvals) {
|
|
1262
|
+
yeptris_tape_columns(t);
|
|
1263
|
+
if (t == NULL || t->_src == NULL || from > to || to > t->count) {
|
|
1264
|
+
return SIZE_MAX;
|
|
1265
|
+
}
|
|
1266
|
+
const char* p = (const char*)t->_src;
|
|
1267
|
+
size_t n = 0;
|
|
1268
|
+
for (size_t i = from; i < to; i++) {
|
|
1269
|
+
uint8_t k = t->kinds[i];
|
|
1270
|
+
if (k != YEP_T_INT && k != YEP_T_FLOAT && k != YEP_T_NUM) {
|
|
1271
|
+
continue;
|
|
1272
|
+
}
|
|
1273
|
+
size_t j = 0;
|
|
1274
|
+
int64_t iv = 0;
|
|
1275
|
+
double dv = 0;
|
|
1276
|
+
int shape = 0;
|
|
1277
|
+
if (!yep_json_number_scan(p + t->offs[i], t->lens[i], &j, &shape, &iv, &dv) ||
|
|
1278
|
+
j != t->lens[i]) {
|
|
1279
|
+
/* full-span consumption: strict spans always re-scan whole
|
|
1280
|
+
* (grammar-validated at parse); a lenient NUM run that
|
|
1281
|
+
* stops early carries non-number bytes — the drain-side
|
|
1282
|
+
* reject the deferred contract promises */
|
|
1283
|
+
return SIZE_MAX;
|
|
1284
|
+
}
|
|
1285
|
+
if (shape == 0) {
|
|
1286
|
+
if (ivals != NULL) {
|
|
1287
|
+
ivals[i] = iv;
|
|
1288
|
+
}
|
|
1289
|
+
} else {
|
|
1290
|
+
if (shape == 2) {
|
|
1291
|
+
t->int_min = 1;
|
|
1292
|
+
}
|
|
1293
|
+
if (dvals != NULL) {
|
|
1294
|
+
dvals[i] = dv;
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
n++;
|
|
1298
|
+
}
|
|
1299
|
+
return n;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
YEPTRIS_API void yeptris_tape_free(yeptris_json_tape* tape) {
|
|
1303
|
+
if (tape == NULL) {
|
|
1304
|
+
return;
|
|
1305
|
+
}
|
|
1306
|
+
yep_free(yep_system_allocator(), tape->_block);
|
|
1307
|
+
memset(tape, 0, sizeof(*tape));
|
|
1308
|
+
}
|