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,737 @@
|
|
|
1
|
+
/* parse.c — public API glue: encoding front-end → engine → DOM. */
|
|
2
|
+
|
|
3
|
+
#include <string.h>
|
|
4
|
+
|
|
5
|
+
#include "common/simd_text.h"
|
|
6
|
+
#include "doc.h"
|
|
7
|
+
#include "dom/dom.h"
|
|
8
|
+
#include "encoding/encoding.h"
|
|
9
|
+
#include "memory/allocator.h"
|
|
10
|
+
#include "memory/pool.h"
|
|
11
|
+
#include "parse/engine.h"
|
|
12
|
+
#include "parse/numbers.h"
|
|
13
|
+
#include "resolve/resolver.h"
|
|
14
|
+
#include "scan/json.h"
|
|
15
|
+
#include "tape_in.h"
|
|
16
|
+
|
|
17
|
+
#include "parse/events.h"
|
|
18
|
+
#include <errno.h>
|
|
19
|
+
#include <math.h>
|
|
20
|
+
#include <stdlib.h>
|
|
21
|
+
|
|
22
|
+
#include <yeptris.h>
|
|
23
|
+
|
|
24
|
+
YEPTRIS_API const char* yeptris_last_error(uint32_t* line, uint32_t* col) {
|
|
25
|
+
const yep_error* tls = yep_error_tls();
|
|
26
|
+
if (line != NULL) {
|
|
27
|
+
*line = tls->line;
|
|
28
|
+
}
|
|
29
|
+
if (col != NULL) {
|
|
30
|
+
*col = tls->col;
|
|
31
|
+
}
|
|
32
|
+
return tls->msg;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static YeptrisDocument parse_impl(const char* buf, size_t len, const YeptrisParseOptions* opts,
|
|
36
|
+
int json_mode, YeptrisStatus* status);
|
|
37
|
+
|
|
38
|
+
YEPTRIS_API YeptrisDocument yeptris_parse(const char* buf, size_t len, YeptrisStatus* status) {
|
|
39
|
+
return yeptris_parse_ex(buf, len, NULL, status);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* #342 slice 2: materialize the deferred tree on first access. The
|
|
43
|
+
* gate-clean JSON route carries the parsed TAPE (simdjson's design:
|
|
44
|
+
* its "DOM" is a tape) and pays dom_from_tape only when a consumer
|
|
45
|
+
* touches the tree — parse-only workloads never build nodes. */
|
|
46
|
+
yep_dom* yep_doc_dom(yeptris_document* doc) {
|
|
47
|
+
if (doc == NULL) {
|
|
48
|
+
return NULL;
|
|
49
|
+
}
|
|
50
|
+
if (doc->dom == NULL && doc->lazy_tape != NULL) {
|
|
51
|
+
yeptris_json_tape* t = (yeptris_json_tape*)doc->lazy_tape;
|
|
52
|
+
yep_dom* dom = yep_dom_create(doc->sys);
|
|
53
|
+
if (dom != NULL && dom_from_tape(dom, t) == 0) {
|
|
54
|
+
doc->dom = dom;
|
|
55
|
+
yeptris_tape_free(t);
|
|
56
|
+
yep_free(doc->sys, t);
|
|
57
|
+
doc->lazy_tape = NULL;
|
|
58
|
+
} else {
|
|
59
|
+
yep_dom_destroy(dom);
|
|
60
|
+
dom = NULL; /* the tape stays: a later access retries, or
|
|
61
|
+
free drops it (the materializer only fails on
|
|
62
|
+
malformed NUM spans, which the strict gate
|
|
63
|
+
already rejected at parse) */
|
|
64
|
+
}
|
|
65
|
+
return dom;
|
|
66
|
+
}
|
|
67
|
+
return doc->dom;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* The strict-JSON document wrapper (both routes share it). */
|
|
71
|
+
/* The lazy route's acceptance debt: the fused lenient walk records
|
|
72
|
+
* number runs UNVALIDATED (its simdjson-style deferred contract).
|
|
73
|
+
* parse_json's contract is RFC 8259 at parse time, so the deferred
|
|
74
|
+
* spans settle HERE — full-span shape check per NUM record, decoding
|
|
75
|
+
* the packed records directly (no columns build at parse; the walk
|
|
76
|
+
* guarantees recs are primary on this route). */
|
|
77
|
+
static int lazy_nums_settled(const yeptris_json_tape* t) {
|
|
78
|
+
const char* p = (const char*)t->_src;
|
|
79
|
+
for (uint32_t i = 0; i < t->count; i++) {
|
|
80
|
+
uint64_t r = t->recs[i];
|
|
81
|
+
if ((uint8_t)(r & 0xFFu) != YEP_T_NUM) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
uint32_t len = (uint32_t)((r >> 8) & 0x7FFFFFu);
|
|
85
|
+
uint32_t off = (uint32_t)(r >> 32);
|
|
86
|
+
size_t adv = 0;
|
|
87
|
+
int flt = 0;
|
|
88
|
+
if (yep_json_number_shape(p + off, len, &adv, &flt) == 0 || adv != (size_t)len) {
|
|
89
|
+
return -1;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* The strict-JSON document wrapper (both routes share it). */
|
|
96
|
+
static YeptrisDocument yep_json_doc_wrap(yep_dom* dom, const char* buf, size_t len,
|
|
97
|
+
const yep_allocator* sys, YeptrisStatus* status) {
|
|
98
|
+
(void)len;
|
|
99
|
+
yeptris_document* doc = yep_alloc(sys, sizeof(yeptris_document));
|
|
100
|
+
if (doc == NULL) {
|
|
101
|
+
yep_dom_destroy(dom);
|
|
102
|
+
if (status != NULL) {
|
|
103
|
+
*status = YEPTRIS_ERROR_MEMORY;
|
|
104
|
+
}
|
|
105
|
+
return NULL;
|
|
106
|
+
}
|
|
107
|
+
doc->dom = dom;
|
|
108
|
+
doc->sys = sys;
|
|
109
|
+
doc->lazy_tape = NULL;
|
|
110
|
+
doc->schema = YEPTRIS_SCHEMA_12_CORE; /* strict JSON is core by construction */
|
|
111
|
+
doc->transcoded = NULL;
|
|
112
|
+
doc->transcoded_len = 0;
|
|
113
|
+
doc->input = buf;
|
|
114
|
+
doc->finish_pool = NULL;
|
|
115
|
+
if (status != NULL) {
|
|
116
|
+
*status = YEPTRIS_OK;
|
|
117
|
+
}
|
|
118
|
+
return (YeptrisDocument)doc;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
YEPTRIS_API YeptrisDocument yeptris_parse_json(const char* buf, size_t len, YeptrisStatus* status) {
|
|
122
|
+
YeptrisStatus st = YEPTRIS_OK;
|
|
123
|
+
if (buf == NULL && len != 0) {
|
|
124
|
+
st = YEPTRIS_ERROR_ARG;
|
|
125
|
+
goto jfail;
|
|
126
|
+
}
|
|
127
|
+
/* Clean-gate fast route (TODO.restructure/81 stage 2): a gate-clean
|
|
128
|
+
* buffer is printable ASCII, and the FUSED builder's walk runs
|
|
129
|
+
* STRICT here (dom->flow_strict) — one pass validates RFC 8259 and
|
|
130
|
+
* builds. Rejects, non-opener roots, and surprises fall to the
|
|
131
|
+
* original sequence below, whose error precedence is byte-for-byte
|
|
132
|
+
* the pinned behavior (json-suite-strict gates this). */
|
|
133
|
+
int gated = len > 0 && yep_text_active()->gate_scan(buf, len);
|
|
134
|
+
if (!gated) {
|
|
135
|
+
size_t off = 0;
|
|
136
|
+
while (off < len &&
|
|
137
|
+
(buf[off] == ' ' || buf[off] == '\t' || buf[off] == '\n' || buf[off] == '\r')) {
|
|
138
|
+
off++;
|
|
139
|
+
}
|
|
140
|
+
/* tabs: the lenient walk's own pinned acceptance (its route
|
|
141
|
+
* takes them); the strict routes reject them (ErrorParity's
|
|
142
|
+
* pinned agreement). A tab-carrying buffer must NOT take the
|
|
143
|
+
* lazy walk — the validating sequence below reports exactly
|
|
144
|
+
* the pinned reject. */
|
|
145
|
+
if (off < len && (buf[off] == '[' || buf[off] == '{') && memchr(buf, '\t', len) == NULL) {
|
|
146
|
+
/* #342 slice 2: the fused LENIENT walk (one pass, records
|
|
147
|
+
* only — no node building) settles the deferred number
|
|
148
|
+
* grammar inline, then the tape rides the document and
|
|
149
|
+
* dom_from_tape builds nodes on the first tree access.
|
|
150
|
+
* A reject or malformed span falls to the original
|
|
151
|
+
* sequence below, whose error precedence is byte-for-byte
|
|
152
|
+
* the pinned behavior. */
|
|
153
|
+
const yep_allocator* sys = yep_system_allocator();
|
|
154
|
+
yeptris_json_tape* t = yep_alloc(sys, sizeof(*t));
|
|
155
|
+
if (t == NULL) {
|
|
156
|
+
st = YEPTRIS_ERROR_MEMORY;
|
|
157
|
+
goto jfail;
|
|
158
|
+
}
|
|
159
|
+
if (yep_tape_walk_lenient_fused(buf, len, off, t) == YEPTRIS_OK &&
|
|
160
|
+
lazy_nums_settled(t) == 0) {
|
|
161
|
+
YeptrisDocument h = yep_json_doc_wrap(NULL, buf, len, sys, status);
|
|
162
|
+
if (h != NULL) {
|
|
163
|
+
((yeptris_document*)h)->lazy_tape = t;
|
|
164
|
+
return h;
|
|
165
|
+
}
|
|
166
|
+
yeptris_tape_free(t); /* wrap failed (memory): below */
|
|
167
|
+
} else {
|
|
168
|
+
yeptris_tape_free(t); /* reject/malformed: below */
|
|
169
|
+
}
|
|
170
|
+
yep_free(sys, t);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
size_t verr = 0;
|
|
174
|
+
if (!yep_json_document(buf, len, &verr)) {
|
|
175
|
+
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, verr,
|
|
176
|
+
"not strict JSON at byte %zu", verr);
|
|
177
|
+
st = YEPTRIS_ERROR_PARSE;
|
|
178
|
+
goto jfail;
|
|
179
|
+
}
|
|
180
|
+
size_t uerr = 0;
|
|
181
|
+
if (gated && !yep_utf8_validate((const unsigned char*)buf, len, &uerr)) {
|
|
182
|
+
yep_error_set(yep_error_tls(), YEP_ERR_ENCODING, 0, 0, uerr, "ill-formed UTF-8 at byte %zu",
|
|
183
|
+
uerr);
|
|
184
|
+
st = YEPTRIS_ERROR_ENCODING;
|
|
185
|
+
goto jfail;
|
|
186
|
+
}
|
|
187
|
+
/* Direct DOM construction (TODO.impl/27): the validated buffer
|
|
188
|
+
* needs no engine — one walk builds the tree, skipping the event
|
|
189
|
+
* pipeline. A builder/validator disagreement defers to the engine
|
|
190
|
+
* (never happens in-tree; belt and braces). */
|
|
191
|
+
{
|
|
192
|
+
const yep_allocator* sys = yep_system_allocator();
|
|
193
|
+
yep_dom* dom = yep_dom_create(sys);
|
|
194
|
+
if (dom == NULL) {
|
|
195
|
+
st = YEPTRIS_ERROR_MEMORY;
|
|
196
|
+
goto jfail;
|
|
197
|
+
}
|
|
198
|
+
dom->input_base = buf; /* strict JSON is UTF-8 by definition */
|
|
199
|
+
dom->input_len = len;
|
|
200
|
+
yep_dom_prepare_len(dom, len);
|
|
201
|
+
int brc = yep_dom_build_json(dom, buf, len);
|
|
202
|
+
if (brc == -1) {
|
|
203
|
+
yep_dom_destroy(dom);
|
|
204
|
+
st = YEPTRIS_ERROR_MEMORY;
|
|
205
|
+
goto jfail;
|
|
206
|
+
}
|
|
207
|
+
if (brc == -2) {
|
|
208
|
+
yep_dom_destroy(dom);
|
|
209
|
+
return parse_impl(buf, len, NULL, 1, status);
|
|
210
|
+
}
|
|
211
|
+
return yep_json_doc_wrap(dom, buf, len, sys, status);
|
|
212
|
+
}
|
|
213
|
+
jfail:
|
|
214
|
+
if (status != NULL) {
|
|
215
|
+
*status = st;
|
|
216
|
+
}
|
|
217
|
+
return NULL;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
static YeptrisDocument parse_impl(const char* buf, size_t len, const YeptrisParseOptions* opts,
|
|
221
|
+
int json_mode, YeptrisStatus* status) {
|
|
222
|
+
YeptrisStatus st = YEPTRIS_OK;
|
|
223
|
+
if (buf == NULL && len != 0) {
|
|
224
|
+
st = YEPTRIS_ERROR_ARG;
|
|
225
|
+
goto fail;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const yep_allocator* sys = yep_system_allocator();
|
|
229
|
+
|
|
230
|
+
/* Encoding front-end: BOM sniff; borrow UTF-8, transcode the rest. */
|
|
231
|
+
const char* data = buf;
|
|
232
|
+
size_t data_len = len;
|
|
233
|
+
unsigned char* transcoded = NULL;
|
|
234
|
+
size_t transcoded_len = 0;
|
|
235
|
+
yep_encoding enc = YEP_ENC_UNKNOWN;
|
|
236
|
+
|
|
237
|
+
if (json_mode) {
|
|
238
|
+
/* JSON mode validated grammar and UTF-8 well-formedness at the
|
|
239
|
+
* entry: no BOM, no transcoding, and never the printable set —
|
|
240
|
+
* RFC 8259 allows DEL and noncharacters that YAML c-printable
|
|
241
|
+
* excludes. The engine takes the bytes directly. */
|
|
242
|
+
goto engine_enter;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
size_t bom = yep_bom_sniff((const unsigned char*)buf, len, &enc);
|
|
246
|
+
data = buf + bom;
|
|
247
|
+
data_len = len - bom;
|
|
248
|
+
|
|
249
|
+
if (enc == YEP_ENC_UTF16LE || enc == YEP_ENC_UTF16BE || enc == YEP_ENC_UTF32LE ||
|
|
250
|
+
enc == YEP_ENC_UTF32BE) {
|
|
251
|
+
size_t terr = 0;
|
|
252
|
+
int rc = yep_transcode_to_utf8(sys, enc, (const unsigned char*)data, data_len, &transcoded,
|
|
253
|
+
&transcoded_len, &terr);
|
|
254
|
+
if (rc != 0) {
|
|
255
|
+
yep_error_set(yep_error_tls(), YEP_ERR_ENCODING, 0, 0, terr,
|
|
256
|
+
"ill-formed input encoding");
|
|
257
|
+
yep_free(sys, transcoded);
|
|
258
|
+
st = YEPTRIS_ERROR_ENCODING;
|
|
259
|
+
goto fail;
|
|
260
|
+
}
|
|
261
|
+
data = (const char*)transcoded;
|
|
262
|
+
data_len = transcoded_len;
|
|
263
|
+
size_t pverr = 0;
|
|
264
|
+
if (!yep_printable_validate((const unsigned char*)data, data_len, &pverr)) {
|
|
265
|
+
yep_error_set(yep_error_tls(), YEP_ERR_ENCODING, 0, 0, pverr,
|
|
266
|
+
"non-printable character at byte %zu", pverr);
|
|
267
|
+
yep_free(sys, transcoded);
|
|
268
|
+
st = YEPTRIS_ERROR_ENCODING;
|
|
269
|
+
goto fail;
|
|
270
|
+
}
|
|
271
|
+
} else {
|
|
272
|
+
/* The encoding gate rides the cheap gate_scan kernel; sizing
|
|
273
|
+
* rides length heuristics (TODO.restructure/66: the fused
|
|
274
|
+
* multi-class stats sweep cost ~12% on the ubuntu asymmetry
|
|
275
|
+
* shapes — ryml pays no pre-pass). Pure gate-safe input skips
|
|
276
|
+
* the SWAR validator entirely; anything else falls to it for
|
|
277
|
+
* the authoritative answer + error position. */
|
|
278
|
+
if (yep_text_active()->gate_scan(data, data_len)) {
|
|
279
|
+
size_t verr = 0;
|
|
280
|
+
if (!yep_printable_validate((const unsigned char*)data, data_len, &verr)) {
|
|
281
|
+
yep_error_set(yep_error_tls(), YEP_ERR_ENCODING, 0, 0, verr,
|
|
282
|
+
"ill-formed or non-printable UTF-8 at byte %zu", verr);
|
|
283
|
+
st = YEPTRIS_ERROR_ENCODING;
|
|
284
|
+
goto fail;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/* Engine → DOM. */
|
|
290
|
+
yep_engine* eng = NULL;
|
|
291
|
+
engine_enter:
|
|
292
|
+
eng = yep_engine_create(sys);
|
|
293
|
+
if (opts != NULL) {
|
|
294
|
+
yep_engine_set_resolver(eng, opts->schema == YEPTRIS_SCHEMA_11_COMPAT
|
|
295
|
+
? yep_resolver_compat11()
|
|
296
|
+
: yep_resolver_core12());
|
|
297
|
+
if (opts->max_depth > 0) {
|
|
298
|
+
yep_engine_set_max_depth(eng, opts->max_depth);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (eng == NULL) {
|
|
302
|
+
yep_free(sys, transcoded);
|
|
303
|
+
st = YEPTRIS_ERROR_MEMORY;
|
|
304
|
+
goto fail;
|
|
305
|
+
}
|
|
306
|
+
yep_dom* dom = yep_dom_create(sys);
|
|
307
|
+
if (dom == NULL) {
|
|
308
|
+
yep_engine_destroy(eng);
|
|
309
|
+
yep_free(sys, transcoded);
|
|
310
|
+
st = YEPTRIS_ERROR_MEMORY;
|
|
311
|
+
goto fail;
|
|
312
|
+
}
|
|
313
|
+
/* the direct builders resolve with the engine's schema (the typing
|
|
314
|
+
* SSOT — one resolver decision per scalar, whichever path builds) */
|
|
315
|
+
dom->resolver = (opts != NULL && opts->schema == YEPTRIS_SCHEMA_11_COMPAT)
|
|
316
|
+
? yep_resolver_compat11()
|
|
317
|
+
: yep_resolver_core12();
|
|
318
|
+
/* BEFORE the run: input-slice strings borrow as views (zero copy)
|
|
319
|
+
* — the document keeps `transcoded` alive for exactly this. Set
|
|
320
|
+
* after, every scalar was arena-copied (found 2026-09-10). */
|
|
321
|
+
dom->input_len = data_len;
|
|
322
|
+
dom->input_base = transcoded ? (const char*)transcoded : buf;
|
|
323
|
+
yep_dom_prepare_len(dom, data_len);
|
|
324
|
+
{
|
|
325
|
+
/* the nametab reserve survives: a memchr chain for '&' is
|
|
326
|
+
* far cheaper than the class sweep it replaced */
|
|
327
|
+
yep_text_stats amp_only = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
328
|
+
const char* q = data;
|
|
329
|
+
const char* end = data + data_len;
|
|
330
|
+
if (q != NULL) {
|
|
331
|
+
while ((q = memchr(q, '&', (size_t)(end - q))) != NULL) {
|
|
332
|
+
amp_only.amp++;
|
|
333
|
+
q++;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
yep_engine_prepare(eng, &_only);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
yep_sink sink = {.on_event = yep_dom_on_event,
|
|
340
|
+
.ctx = dom,
|
|
341
|
+
.on_flow_build = dom_on_flow_build,
|
|
342
|
+
.on_flow_commit = dom_on_flow_commit,
|
|
343
|
+
.on_flow_rollback = dom_on_flow_rollback,
|
|
344
|
+
.on_block_pair = dom_on_block_pair,
|
|
345
|
+
.on_scalar = dom_on_scalar,
|
|
346
|
+
.on_block_open = dom_on_block_open,
|
|
347
|
+
.on_block_item = dom_on_block_item};
|
|
348
|
+
int rc = yep_engine_run(eng, data, data_len, &sink);
|
|
349
|
+
if (rc != 0) {
|
|
350
|
+
const yep_error* ee = yep_engine_error(eng);
|
|
351
|
+
yep_err_code code = ee ? ee->code : YEP_ERR_UNEXPECTED;
|
|
352
|
+
if (ee) {
|
|
353
|
+
yep_error* tls = yep_error_tls();
|
|
354
|
+
*tls = *ee;
|
|
355
|
+
}
|
|
356
|
+
yep_dom_destroy(dom);
|
|
357
|
+
yep_engine_destroy(eng);
|
|
358
|
+
yep_free(sys, transcoded);
|
|
359
|
+
st = (code == YEP_ERR_MEMORY) ? YEPTRIS_ERROR_MEMORY
|
|
360
|
+
: (code == YEP_ERR_DEPTH) ? YEPTRIS_ERROR_DEPTH
|
|
361
|
+
: YEPTRIS_ERROR_PARSE;
|
|
362
|
+
goto fail;
|
|
363
|
+
}
|
|
364
|
+
/* Resolved tags, folded and escaped scalars live in the engine's
|
|
365
|
+
* finish pool; the document must own it or every such string would
|
|
366
|
+
* dangle at engine teardown (found by ASAN). */
|
|
367
|
+
yep_pool* finish = yep_engine_detach_pool(eng);
|
|
368
|
+
yep_engine_destroy(eng);
|
|
369
|
+
/* DOM strings are input-offsets or arena copies; nothing in the
|
|
370
|
+
* tree references the finish pool anymore — release it now */
|
|
371
|
+
|
|
372
|
+
/* Empty stream (no documents): NULL document with YEPTRIS_OK. */
|
|
373
|
+
if (dom->dcount == 0) {
|
|
374
|
+
yep_dom_destroy(dom);
|
|
375
|
+
yep_pool_destroy(finish);
|
|
376
|
+
yep_free(sys, transcoded);
|
|
377
|
+
if (status != NULL) {
|
|
378
|
+
*status = YEPTRIS_OK;
|
|
379
|
+
}
|
|
380
|
+
return NULL;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
yeptris_document* doc = yep_alloc(sys, sizeof(yeptris_document));
|
|
384
|
+
if (doc == NULL) {
|
|
385
|
+
yep_dom_destroy(dom);
|
|
386
|
+
yep_pool_destroy(finish);
|
|
387
|
+
yep_free(sys, transcoded);
|
|
388
|
+
st = YEPTRIS_ERROR_MEMORY;
|
|
389
|
+
goto fail;
|
|
390
|
+
}
|
|
391
|
+
doc->dom = dom;
|
|
392
|
+
doc->sys = sys;
|
|
393
|
+
doc->schema = (opts != NULL && opts->schema == YEPTRIS_SCHEMA_11_COMPAT)
|
|
394
|
+
? YEPTRIS_SCHEMA_11_COMPAT
|
|
395
|
+
: YEPTRIS_SCHEMA_12_CORE;
|
|
396
|
+
doc->transcoded = transcoded;
|
|
397
|
+
doc->transcoded_len = transcoded_len;
|
|
398
|
+
doc->input = buf;
|
|
399
|
+
/* the finish pool dies here: every DOM string is an input offset
|
|
400
|
+
* or an arena copy (dom_ev_str) — nothing references it */
|
|
401
|
+
yep_pool_destroy(finish);
|
|
402
|
+
doc->finish_pool = NULL;
|
|
403
|
+
doc->lazy_tape = NULL; /* field-by-field ctor: leave no garbage
|
|
404
|
+
* (document_free frees a non-NULL tape) */
|
|
405
|
+
return (YeptrisDocument)doc;
|
|
406
|
+
|
|
407
|
+
fail:
|
|
408
|
+
if (status != NULL) {
|
|
409
|
+
*status = st;
|
|
410
|
+
}
|
|
411
|
+
return NULL;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
YEPTRIS_API YeptrisDocument yeptris_parse_ex(const char* buf, size_t len,
|
|
415
|
+
const YeptrisParseOptions* opts,
|
|
416
|
+
YeptrisStatus* status) {
|
|
417
|
+
return parse_impl(buf, len, opts, 0, status);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
YEPTRIS_API void yeptris_document_free(YeptrisDocument handle) {
|
|
421
|
+
yeptris_document* doc = (yeptris_document*)handle;
|
|
422
|
+
if (doc == NULL) {
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
if (doc->lazy_tape != NULL) { /* never materialized: free stays free */
|
|
426
|
+
yeptris_tape_free((yeptris_json_tape*)doc->lazy_tape);
|
|
427
|
+
yep_free(doc->sys, doc->lazy_tape);
|
|
428
|
+
}
|
|
429
|
+
yep_dom_destroy(doc->dom);
|
|
430
|
+
yep_pool_destroy((yep_pool*)doc->finish_pool);
|
|
431
|
+
yep_free(doc->sys, doc->transcoded);
|
|
432
|
+
yep_free(doc->sys, doc);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
YEPTRIS_API size_t yeptris_document_count(YeptrisDocument handle) {
|
|
436
|
+
yeptris_document* doc = (yeptris_document*)handle;
|
|
437
|
+
return doc ? yep_doc_dom(doc)->dcount : 0;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
yeptris_node* yep_handle_new(yeptris_document* doc, uint32_t id) {
|
|
441
|
+
yeptris_node* n = yep_hpool_alloc(yep_dom_handles(doc->dom), sizeof(yeptris_node), 16);
|
|
442
|
+
if (n == NULL) {
|
|
443
|
+
return NULL;
|
|
444
|
+
}
|
|
445
|
+
n->doc = doc;
|
|
446
|
+
n->id = id;
|
|
447
|
+
return n;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
static YeptrisNode node_new_handle(yeptris_document* doc, uint32_t id) {
|
|
451
|
+
return (YeptrisNode)yep_handle_new(doc, id);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
YEPTRIS_API YeptrisNode yeptris_document_root(YeptrisDocument handle, size_t index) {
|
|
455
|
+
yeptris_document* doc = (yeptris_document*)handle;
|
|
456
|
+
if (doc == NULL) {
|
|
457
|
+
return NULL;
|
|
458
|
+
}
|
|
459
|
+
yep_dom* dom = yep_doc_dom(doc);
|
|
460
|
+
if (dom == NULL || index >= dom->dcount) {
|
|
461
|
+
return NULL;
|
|
462
|
+
}
|
|
463
|
+
return node_new_handle(doc, dom->docs[index]);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
static const yep_dnode* node_of(YeptrisNode handle) {
|
|
467
|
+
yeptris_node* n = (yeptris_node*)handle;
|
|
468
|
+
if (n == NULL || n->doc == NULL) {
|
|
469
|
+
return NULL;
|
|
470
|
+
}
|
|
471
|
+
return yep_dom_node(n->doc->dom, n->id);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
YEPTRIS_API uint32_t yeptris_node_id(YeptrisNode handle) {
|
|
475
|
+
yeptris_node* n = (yeptris_node*)handle;
|
|
476
|
+
return n == NULL ? UINT32_MAX : n->id;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
YEPTRIS_API YeptrisNodeKind yeptris_node_kind(YeptrisNode handle) {
|
|
480
|
+
const yep_dnode* n = node_of(handle);
|
|
481
|
+
if (n == NULL) {
|
|
482
|
+
return YEPTRIS_NODE_SCALAR;
|
|
483
|
+
}
|
|
484
|
+
switch (n->kind) {
|
|
485
|
+
case YEP_DOM_SEQUENCE:
|
|
486
|
+
return YEPTRIS_NODE_SEQUENCE;
|
|
487
|
+
case YEP_DOM_MAPPING:
|
|
488
|
+
return YEPTRIS_NODE_MAPPING;
|
|
489
|
+
case YEP_DOM_ALIAS:
|
|
490
|
+
return YEPTRIS_NODE_ALIAS;
|
|
491
|
+
default:
|
|
492
|
+
return YEPTRIS_NODE_SCALAR;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/* Decodes a node's compact string through its document's regions. */
|
|
497
|
+
static yep_view node_view(const yeptris_node* h, yep_sview sv) {
|
|
498
|
+
return yep_dom_view(h->doc->dom, sv);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
static const char* view_out(yep_view v, size_t* len) {
|
|
502
|
+
if (len != NULL) {
|
|
503
|
+
*len = v.len;
|
|
504
|
+
}
|
|
505
|
+
return v.len ? v.p : (v.p ? v.p : "");
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
YEPTRIS_API const char* yeptris_node_value(YeptrisNode handle, size_t* len) {
|
|
509
|
+
const yep_dnode* n = node_of(handle);
|
|
510
|
+
if (n == NULL || (n->kind != YEP_DOM_SCALAR && n->kind != YEP_DOM_ALIAS)) {
|
|
511
|
+
if (len != NULL) {
|
|
512
|
+
*len = 0;
|
|
513
|
+
}
|
|
514
|
+
return NULL;
|
|
515
|
+
}
|
|
516
|
+
return view_out(node_view((yeptris_node*)handle, n->value), len);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
YEPTRIS_API YeptrisScalarStyle yeptris_node_style(YeptrisNode handle) {
|
|
520
|
+
const yep_dnode* n = node_of(handle);
|
|
521
|
+
return n ? (YeptrisScalarStyle)n->style : YEPTRIS_STYLE_ANY;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
YEPTRIS_API const char* yeptris_tag_uri(YeptrisTagId id) {
|
|
525
|
+
return yep_tag_uri((yep_tag_id)id);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
YEPTRIS_API YeptrisTagId yeptris_node_tag_id(YeptrisNode handle) {
|
|
529
|
+
const yep_dnode* n = node_of(handle);
|
|
530
|
+
if (n == NULL) {
|
|
531
|
+
return YEPTRIS_TAG_CUSTOM;
|
|
532
|
+
}
|
|
533
|
+
if (n->kind == YEPTRIS_NODE_SEQUENCE) {
|
|
534
|
+
return YEPTRIS_TAG_SEQ;
|
|
535
|
+
}
|
|
536
|
+
if (n->kind == YEPTRIS_NODE_MAPPING) {
|
|
537
|
+
return YEPTRIS_TAG_MAP;
|
|
538
|
+
}
|
|
539
|
+
return (YeptrisTagId)n->tag_id;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/* strips '_' and ',' into dst (nul-terminated); returns length.
|
|
543
|
+
* The COMMON case (no separators) returns the borrowed view — no
|
|
544
|
+
* copy, no nul-termination needed by the in-place parsers. */
|
|
545
|
+
YEPTRIS_API YeptrisStatus yeptris_node_int(YeptrisNode handle, int64_t* out) {
|
|
546
|
+
/* conversion is the number kernel's alone (MECE: one fold, one
|
|
547
|
+
* fast path, one Psych-sexagesimal weight table) */
|
|
548
|
+
const yep_dnode* n = node_of(handle);
|
|
549
|
+
if (n == NULL || out == NULL) {
|
|
550
|
+
return YEPTRIS_ERROR_ARG;
|
|
551
|
+
}
|
|
552
|
+
if (n->tag_id != YEPTRIS_TAG_INT) {
|
|
553
|
+
return YEPTRIS_ERROR_PARSE;
|
|
554
|
+
}
|
|
555
|
+
yep_view v = node_view((yeptris_node*)handle, n->value);
|
|
556
|
+
return yep_num_i64((const char*)v.p, v.len, out) == 0 ? YEPTRIS_OK : YEPTRIS_ERROR_PARSE;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
YEPTRIS_API YeptrisStatus yeptris_node_float(YeptrisNode handle, double* out) {
|
|
560
|
+
const yep_dnode* n = node_of(handle);
|
|
561
|
+
if (n == NULL || out == NULL) {
|
|
562
|
+
return YEPTRIS_ERROR_ARG;
|
|
563
|
+
}
|
|
564
|
+
if (n->tag_id != YEPTRIS_TAG_FLOAT) {
|
|
565
|
+
return YEPTRIS_ERROR_PARSE;
|
|
566
|
+
}
|
|
567
|
+
yep_view v = node_view((yeptris_node*)handle, n->value);
|
|
568
|
+
return yep_num_f64((const char*)v.p, v.len, out) == 0 ? YEPTRIS_OK : YEPTRIS_ERROR_PARSE;
|
|
569
|
+
}
|
|
570
|
+
YEPTRIS_API YeptrisStatus yeptris_node_bool(YeptrisNode handle, int* out) {
|
|
571
|
+
const yep_dnode* n = node_of(handle);
|
|
572
|
+
if (n == NULL || out == NULL) {
|
|
573
|
+
return YEPTRIS_ERROR_ARG;
|
|
574
|
+
}
|
|
575
|
+
if (n->tag_id != YEPTRIS_TAG_BOOL) {
|
|
576
|
+
return YEPTRIS_ERROR_PARSE;
|
|
577
|
+
}
|
|
578
|
+
/* the resolver accepted it; true-set membership decides the value */
|
|
579
|
+
static const char* k_true[] = {"true", "True", "TRUE", "y", "Y", "yes",
|
|
580
|
+
"Yes", "YES", "on", "On", "ON"};
|
|
581
|
+
for (size_t i = 0; i < sizeof(k_true) / sizeof(k_true[0]); i++) {
|
|
582
|
+
size_t m = strlen(k_true[i]);
|
|
583
|
+
yep_view v = node_view((yeptris_node*)handle, n->value);
|
|
584
|
+
if (v.len == m && memcmp(v.p, k_true[i], m) == 0) {
|
|
585
|
+
*out = 1;
|
|
586
|
+
return YEPTRIS_OK;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
*out = 0;
|
|
590
|
+
return YEPTRIS_OK;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
YEPTRIS_API const char* yeptris_node_tag(YeptrisNode handle, size_t* len) {
|
|
594
|
+
const yep_dnode* n = node_of(handle);
|
|
595
|
+
if (n == NULL || n->tag.len == 0) {
|
|
596
|
+
if (len != NULL) {
|
|
597
|
+
*len = 0;
|
|
598
|
+
}
|
|
599
|
+
return n ? NULL : NULL;
|
|
600
|
+
}
|
|
601
|
+
return view_out(node_view((yeptris_node*)handle, n->tag), len);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
YEPTRIS_API const char* yeptris_node_anchor(YeptrisNode handle, size_t* len) {
|
|
605
|
+
const yep_dnode* n = node_of(handle);
|
|
606
|
+
if (n == NULL || n->anchor.len == 0) {
|
|
607
|
+
if (len != NULL) {
|
|
608
|
+
*len = 0;
|
|
609
|
+
}
|
|
610
|
+
return NULL;
|
|
611
|
+
}
|
|
612
|
+
return view_out(node_view((yeptris_node*)handle, n->anchor), len);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
static YeptrisNode wrap(yeptris_node* base, uint32_t id) {
|
|
616
|
+
if (base == NULL || base->doc == NULL) {
|
|
617
|
+
return NULL;
|
|
618
|
+
}
|
|
619
|
+
/* Handles live in the document's thread-safe arena: one
|
|
620
|
+
* document_free reclaims every handle ever handed out (zero-leak
|
|
621
|
+
* contract) while read-only sharing stays safe (TODO.impl/19) */
|
|
622
|
+
yeptris_node* n = yep_hpool_alloc(yep_dom_handles(base->doc->dom), sizeof(yeptris_node), 16);
|
|
623
|
+
if (n == NULL) {
|
|
624
|
+
return NULL;
|
|
625
|
+
}
|
|
626
|
+
n->doc = base->doc;
|
|
627
|
+
n->id = id;
|
|
628
|
+
return (YeptrisNode)n;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
YEPTRIS_API YeptrisNode yeptris_node_alias_target(YeptrisNode handle) {
|
|
632
|
+
const yep_dnode* n = node_of(handle);
|
|
633
|
+
if (n == NULL || n->kind != YEP_DOM_ALIAS || n->target == UINT32_MAX) {
|
|
634
|
+
return NULL;
|
|
635
|
+
}
|
|
636
|
+
return wrap((yeptris_node*)handle, n->target);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
YEPTRIS_API size_t yeptris_node_seq_count(YeptrisNode handle) {
|
|
640
|
+
const yep_dnode* n = node_of(handle);
|
|
641
|
+
return (n && n->kind == YEP_DOM_SEQUENCE) ? n->count : 0;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
YEPTRIS_API YeptrisNode yeptris_node_seq_at(YeptrisNode handle, size_t index) {
|
|
645
|
+
const yep_dnode* n = node_of(handle);
|
|
646
|
+
if (n == NULL || n->kind != YEP_DOM_SEQUENCE || index >= n->count) {
|
|
647
|
+
return NULL;
|
|
648
|
+
}
|
|
649
|
+
yep_dom* dom = ((yeptris_node*)handle)->doc->dom;
|
|
650
|
+
uint32_t count = 0;
|
|
651
|
+
/* the node id IS its dnode index */
|
|
652
|
+
uint32_t id = dom_indexed_child(dom, ((yeptris_node*)handle)->id, index, &count); /* #377 */
|
|
653
|
+
if (id == UINT32_MAX) {
|
|
654
|
+
return NULL;
|
|
655
|
+
}
|
|
656
|
+
return wrap((yeptris_node*)handle, id);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
YEPTRIS_API size_t yeptris_node_children(YeptrisNode handle, YeptrisNode* out, size_t cap) {
|
|
660
|
+
const yep_dnode* n = node_of(handle);
|
|
661
|
+
if (n == NULL || (n->kind != YEP_DOM_SEQUENCE && n->kind != YEP_DOM_MAPPING)) {
|
|
662
|
+
return 0;
|
|
663
|
+
}
|
|
664
|
+
size_t count = 0;
|
|
665
|
+
uint32_t id = n->first_child;
|
|
666
|
+
while (id != UINT32_MAX) {
|
|
667
|
+
if (out != NULL && count < cap) {
|
|
668
|
+
out[count] = wrap((yeptris_node*)handle, id);
|
|
669
|
+
}
|
|
670
|
+
count++;
|
|
671
|
+
const yep_dnode* cur = yep_dom_node(((yeptris_node*)handle)->doc->dom, id);
|
|
672
|
+
id = cur ? cur->next_sibling : UINT32_MAX;
|
|
673
|
+
}
|
|
674
|
+
return count;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
YEPTRIS_API size_t yeptris_node_map_count(YeptrisNode handle) {
|
|
678
|
+
const yep_dnode* n = node_of(handle);
|
|
679
|
+
return (n && n->kind == YEP_DOM_MAPPING) ? n->count / 2 : 0;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
YEPTRIS_API int yeptris_node_map_at(YeptrisNode handle, size_t index, YeptrisNode* key,
|
|
683
|
+
YeptrisNode* value) {
|
|
684
|
+
const yep_dnode* n = node_of(handle);
|
|
685
|
+
if (n == NULL || n->kind != YEPTRIS_NODE_MAPPING || index >= n->count / 2) {
|
|
686
|
+
return -1;
|
|
687
|
+
}
|
|
688
|
+
yeptris_node* h = (yeptris_node*)handle;
|
|
689
|
+
yep_dom* d = h->doc->dom;
|
|
690
|
+
uint32_t count = 0;
|
|
691
|
+
uint32_t child = dom_indexed_child(d, h->id, (size_t)index * 2, &count); /* #377 */
|
|
692
|
+
if (child == UINT32_MAX) {
|
|
693
|
+
return -1;
|
|
694
|
+
}
|
|
695
|
+
if (key != NULL) {
|
|
696
|
+
*key = wrap(h, child);
|
|
697
|
+
}
|
|
698
|
+
if (value != NULL) {
|
|
699
|
+
*value = wrap(h, d->nodes[child].next_sibling);
|
|
700
|
+
}
|
|
701
|
+
return 0;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
YEPTRIS_API YeptrisNode yeptris_node_map_get(YeptrisNode handle, const char* key, size_t key_len) {
|
|
705
|
+
const yep_dnode* n = node_of(handle);
|
|
706
|
+
if (n == NULL || n->kind != YEP_DOM_MAPPING || key == NULL) {
|
|
707
|
+
return NULL;
|
|
708
|
+
}
|
|
709
|
+
yep_dom* dom = ((yeptris_node*)handle)->doc->dom;
|
|
710
|
+
/* O(1) through the lazy index (first use builds it); the scan
|
|
711
|
+
* below is the build-failure fallback */
|
|
712
|
+
uint32_t hit =
|
|
713
|
+
yep_midx_lookup(dom, ((yeptris_node*)handle)->id, (yep_view){key, (uint32_t)key_len});
|
|
714
|
+
if (hit != UINT32_MAX) {
|
|
715
|
+
const yep_dnode* kn = yep_dom_node(dom, hit);
|
|
716
|
+
if (kn != NULL) {
|
|
717
|
+
return wrap((yeptris_node*)handle, kn->next_sibling);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
uint32_t id = n->first_child;
|
|
721
|
+
int want_key = 1;
|
|
722
|
+
while (id != UINT32_MAX) {
|
|
723
|
+
const yep_dnode* cur = yep_dom_node(dom, id);
|
|
724
|
+
if (cur == NULL) {
|
|
725
|
+
break;
|
|
726
|
+
}
|
|
727
|
+
if (want_key && cur->kind == YEP_DOM_SCALAR) {
|
|
728
|
+
yep_view kv = {key, (uint32_t)key_len};
|
|
729
|
+
if (yep_view_eq(yep_dom_view(dom, cur->value), kv)) {
|
|
730
|
+
return wrap((yeptris_node*)handle, cur->next_sibling);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
want_key = !want_key;
|
|
734
|
+
id = cur->next_sibling;
|
|
735
|
+
}
|
|
736
|
+
return NULL;
|
|
737
|
+
}
|