yeptris 0.6.58.1-arm-linux-eabihf → 0.6.60.1-arm-linux-eabihf

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/ext/yeptris_native/version.h +2 -2
  3. data/lib/yeptris/3.4/native.so +0 -0
  4. data/lib/yeptris/document.rb +15 -0
  5. data/lib/yeptris/ffi.rb +112 -0
  6. data/lib/yeptris/psych/visitors.rb +16 -6
  7. data/lib/yeptris/psych.rb +11 -5
  8. data/lib/yeptris/validation.rb +320 -0
  9. data/lib/yeptris/yaml.rb +128 -6
  10. data/lib/yeptris.rb +2 -1
  11. data/libyeptris.so +0 -0
  12. data/vendor/libyeptris/CMakeLists.txt +1 -1
  13. data/vendor/libyeptris/src/CMakeLists.txt +8 -0
  14. data/vendor/libyeptris/src/include/yeptris/emit.h +30 -2
  15. data/vendor/libyeptris/src/include/yeptris/parse.h +52 -0
  16. data/vendor/libyeptris/src/include/yeptris/resolve.h +8 -0
  17. data/vendor/libyeptris/src/include/yeptris/validate.h +259 -15
  18. data/vendor/libyeptris/src/include/yeptris/values.h +8 -2
  19. data/vendor/libyeptris/src/yeptris/cbor/cbor.h +10 -0
  20. data/vendor/libyeptris/src/yeptris/cbor/decode.c +5 -7
  21. data/vendor/libyeptris/src/yeptris/cbor/encode.c +9 -9
  22. data/vendor/libyeptris/src/yeptris/cbor/from_marshal.c +1 -1
  23. data/vendor/libyeptris/src/yeptris/common/error.h +2 -0
  24. data/vendor/libyeptris/src/yeptris/doc.h +20 -0
  25. data/vendor/libyeptris/src/yeptris/emit/emit.c +85 -13
  26. data/vendor/libyeptris/src/yeptris/emit/writer.c +158 -642
  27. data/vendor/libyeptris/src/yeptris/emit/writer.h +15 -1
  28. data/vendor/libyeptris/src/yeptris/events/push.c +28 -3
  29. data/vendor/libyeptris/src/yeptris/events/values.c +24 -0
  30. data/vendor/libyeptris/src/yeptris/marshal/to_json.c +650 -0
  31. data/vendor/libyeptris/src/yeptris/parse/engine.c +121 -40
  32. data/vendor/libyeptris/src/yeptris/parse/stream_iter.c +326 -0
  33. data/vendor/libyeptris/src/yeptris/parse.c +181 -46
  34. data/vendor/libyeptris/src/yeptris/resolve/compat11.c +1 -1
  35. data/vendor/libyeptris/src/yeptris/resolve/core12.c +11 -3
  36. data/vendor/libyeptris/src/yeptris/resolve/full12.c +201 -0
  37. data/vendor/libyeptris/src/yeptris/resolve/json12.c +12 -6
  38. data/vendor/libyeptris/src/yeptris/resolve/resolver.h +20 -0
  39. data/vendor/libyeptris/src/yeptris/validate/compile.c +306 -0
  40. data/vendor/libyeptris/src/yeptris/validate/internal.h +255 -10
  41. data/vendor/libyeptris/src/yeptris/validate/jsonschema.c +1025 -125
  42. data/vendor/libyeptris/src/yeptris/validate/output.c +246 -0
  43. data/vendor/libyeptris/src/yeptris/validate/regexp.c +791 -163
  44. data/vendor/libyeptris/src/yeptris/validate/registry.c +118 -0
  45. data/vendor/libyeptris/src/yeptris/validate/resources.c +601 -0
  46. data/vendor/libyeptris/src/yeptris/validate/stream.c +1155 -0
  47. data/vendor/libyeptris/src/yeptris/validate/validate.c +330 -226
  48. metadata +10 -1
@@ -7,21 +7,52 @@
7
7
  * consistency (spec 10.3 resolution) and mapping-key uniqueness
8
8
  * (spec 3.2.1.3: keys compare by canonical form — 0o13 and 0xB
9
9
  * are the same key). Under YEPTRIS_SCHEMA_12_JSON the spec 10.2
10
- * family applies: every PLAIN scalar must match a JSON production
11
- * (the table's `*` -> Error row), mapping keys must be strings,
12
- * non-JSON tags are rejected; core checks still run.
10
+ * family applies: implicit resolution uses ONLY the JSON
11
+ * productions (the core extensions — 0o/0x radix, "+12.3",
12
+ * "True"/"~" casings — stay strings, per example 10.8's Invalid
13
+ * list), mapping keys must be strings (a key resolving to a
14
+ * non-string production is KEY_NOT_STRING; a no-production plain
15
+ * key IS a string, per example 10.8), explicit non-JSON tags are
16
+ * rejected; core checks still run. Under YEPTRIS_SCHEMA_12_FULL
17
+ * the spec 10.4 "other schema" family applies — the core schema
18
+ * "extended with additional tag resolution rules": untagged plains
19
+ * also resolve RFC3339-era timestamps (spec example 2.22's
20
+ * canonical/iso8601/spaced/date forms, classified by PyYAML's
21
+ * timestamp regex as the practice oracle) and the merge/value
22
+ * words, while explicit !!timestamp content must re-resolve
23
+ * through the same classifier (TAG_MISMATCH otherwise). !!binary
24
+ * rides as passthrough (base64 shaping is a construction concern);
25
+ * core checks still run. The 1.1 numeric quirks (underscores,
26
+ * sexagesimal, leading-0 octal, y/n booleans) stay with
27
+ * 11_COMPAT — full is spec-refereed, not psych-refereed.
13
28
  *
14
29
  * 2. JSON SCHEMA validation (`yeptris_json_schema_validate`): the
15
30
  * schema arrives as bytes (parsed with the same engine), the
16
31
  * target against it — draft 2020-12 keyword subset (see the entry
17
32
  * comment). Unknown keywords are ignored, per 2020-12.
18
33
  *
34
+ * The COMPILED-schema economy (`yeptris_schema_*`) retains one parsed
35
+ * schema for many instance streams; the TAG-DRIVEN registry
36
+ * (`yeptris_schema_registry_*`, #906 slice 4) binds compiled schemas
37
+ * to user tags over the family walk (`yeptris_validate_ex`). The
38
+ * report converts to the published JSON-Schema output shape
39
+ * (`yeptris_validate_report_write`, #906 slice 5).
40
+ *
19
41
  * Every diagnostic carries a JSON-pointer instance path ("/a/b/0" —
20
42
  * ~0/~1 escaped), a YEPTRIS_DIAG_* code, a bounded expected/got
21
43
  * detail, and the offending node's 1-based line/column (0 = unknown:
22
44
  * scalars whose bytes the DOM owns in its arena have no input
23
45
  * position; the path still identifies them exactly).
24
46
  *
47
+ * STREAMS (#885 item 4): a validated stream is addressed as an array
48
+ * of documents. When the input holds MORE THAN ONE document, every
49
+ * diagnostic path is prefixed with its document's index segment —
50
+ * "/1/a/b" is a/b of document 1 (0-based), so diagnostics name their
51
+ * document even when the miss is unpositioned (an empty document's
52
+ * Error-row scalar has no line/col). Line/col/offset stay
53
+ * input-absolute. Streams with a single document keep the bare
54
+ * instance pointers — existing consumers' paths are unchanged.
55
+ *
25
56
  * Results are WHOLE REPORTS: one call, no per-diagnostic callback —
26
57
  * the caller drains the flat array and frees the report once.
27
58
  */
@@ -76,6 +107,17 @@ typedef enum {
76
107
  YEPTRIS_DIAG_LIMIT = 26, /* report truncated (the sentinel
77
108
  * rides the LAST slot; more
78
109
  * diagnostics were dropped) */
110
+ /* the 2020-12 sweep (#885 item 2) */
111
+ YEPTRIS_DIAG_MULTIPLE_OF = 27,
112
+ YEPTRIS_DIAG_MIN_PROPERTIES = 28,
113
+ YEPTRIS_DIAG_MAX_PROPERTIES = 29,
114
+ YEPTRIS_DIAG_CONTAINS = 30,
115
+ YEPTRIS_DIAG_MIN_CONTAINS = 31,
116
+ YEPTRIS_DIAG_MAX_CONTAINS = 32,
117
+ YEPTRIS_DIAG_DEPENDENT_REQUIRED = 33,
118
+ /* the 2020-12 unevaluated* annotation model (the sota sweep) */
119
+ YEPTRIS_DIAG_UNEVALUATED_PROPERTY = 34, /* no sibling/applicator evaluated it */
120
+ YEPTRIS_DIAG_UNEVALUATED_ITEM = 35,
79
121
  } YeptrisDiagCode;
80
122
 
81
123
  /* Bounded diagnostic text; always NUL-terminated (over-long paths and
@@ -110,7 +152,14 @@ YEPTRIS_API void yeptris_validate_report_free(yeptris_validate_report* report);
110
152
 
111
153
  /* Parses `buf` (the same front door as yeptris_parse_ex: encodings,
112
154
  * BOM, NEL normalization) and validates every document of the stream
113
- * against `schema`. Paths are root-relative per document.
155
+ * against `schema` — the strict lanes: explicit-tag consistency,
156
+ * canonical-form key uniqueness, (12_JSON) string keys over the JSON
157
+ * productions, and (12_FULL) timestamp content against the full
158
+ * family's classifier. Paths are root-relative per document; a
159
+ * multi-document stream prefixes them with the document index (see
160
+ * STREAMS above), so diagnostics name their document. The parse's own
161
+ * guards compose: a document past the engine's depth cap fails the
162
+ * parse (YEPTRIS_ERROR_DEPTH) before any validation runs.
114
163
  *
115
164
  * Status: YEPTRIS_OK (valid; *out is a report — possibly with zero
116
165
  * diagnostics for an empty stream); YEPTRIS_ERROR_SCHEMA (invalid:
@@ -127,18 +176,67 @@ YEPTRIS_API YeptrisStatus yeptris_validate(const char* buf, size_t len, YeptrisS
127
176
  YEPTRIS_API YeptrisStatus yeptris_validate_document(YeptrisDocument doc, YeptrisSchema schema,
128
177
  yeptris_validate_report** out);
129
178
 
130
- /* JSON Schema draft 2020-12 subset (#882 slice 2). `schema` is parsed
131
- * with the same engine (JSON is YAML flow); document 0 of the stream
132
- * is the schema. Keyword subset: type, enum, const, pattern, minimum/
133
- * maximum/exclusiveMinimum/exclusiveMaximum (numeric, 2020-12 form),
179
+ /* The EVENT-ROUTE twin of yeptris_validate (#902): the same parse
180
+ * (front-end, depth/encoding guards, statuses — the DOM route's
181
+ * sink-entry seam) feeding a streaming validator state machine. The
182
+ * family lanes ride the event walk itself; NO node tree is ever
183
+ * built. Everything observable is the DOM route's, by construction
184
+ * and by the differential gate:
185
+ *
186
+ * - diagnostics: the same code rail (0-35 after the sweep), the same report shape and
187
+ * cap, the same JSON-pointer paths and the stream face's
188
+ * per-document attribution — emitted in the DOM walk's order (a
189
+ * mapping's own tag check, its duplicate-key misses, then its
190
+ * pairs' content);
191
+ * - positions: the DOM route's region law — a diagnostic sits at the
192
+ * node's input-borrowed value bytes (0/0 when the engine pooled
193
+ * them), so line/col/offset match bit for bit;
194
+ * - statuses: OK / SCHEMA / PARSE / DEPTH / ENCODING / MEMORY / ARG,
195
+ * byte-identical argument gates (NULL with length, 11_COMPAT).
196
+ * All three families (12_CORE / 12_JSON / 12_FULL) ride both
197
+ * routes with identical verdicts.
198
+ *
199
+ * The compiled JSON Schema lane (yeptris_schema_validate) keeps the
200
+ * DOM route: its evaluator needs random access (uniqueItems, contains,
201
+ * required); a streaming twin waits for #901's annotation-model seam.
202
+ *
203
+ * Memory: the caller owns *out; free it with
204
+ * yeptris_validate_report_free. */
205
+ YEPTRIS_API YeptrisStatus yeptris_validate_stream(const char* buf, size_t len, YeptrisSchema schema,
206
+ yeptris_validate_report** out);
207
+
208
+ /* JSON Schema draft 2020-12 subset (#882 slice 2; #885 item 2; the
209
+ * 2020-12 sota sweep). `schema` is parsed with the same engine (JSON
210
+ * is YAML flow); document 0 of the stream is the schema. Keyword
211
+ * subset: type, enum, const, pattern, minimum, maximum,
212
+ * exclusiveMinimum, exclusiveMaximum (numeric, 2020-12 form),
213
+ * multipleOf (libm-free quotient test),
134
214
  * minLength/maxLength (code points), minItems/maxItems, uniqueItems,
135
- * items (+ prefixItems; the draft-07 array form rides as prefixItems),
136
- * properties, required, additionalProperties (bool or schema),
137
- * allOf/anyOf/oneOf/not, $ref (LOCAL "#/..." pointers only — $defs and
138
- * definitions both resolve). Boolean schemas (`true`/`false`) apply.
139
- * Unknown keywords and known keywords with unreadable values are
140
- * ignored (2020-12). Instance types ride the core-schema resolution
141
- * (the YAML->JSON data model): "y" is boolean, 1.0 is integer.
215
+ * contains (+ the minContains/maxContains qualifiers), items
216
+ * (+ prefixItems; the draft-07 array form rides as prefixItems),
217
+ * properties, required, patternProperties, propertyNames,
218
+ * minProperties/maxProperties, additionalProperties (bool or schema;
219
+ * excludes patternProperties matches), dependentRequired,
220
+ * dependentSchemas, if/then/else, allOf/anyOf/oneOf/not,
221
+ * unevaluatedProperties/unevaluatedItems (the 2020-12 annotation
222
+ * model: evaluations collect upward through the in-place applicators,
223
+ * a failed branch annotates nothing, and nothing crosses an
224
+ * instance-location boundary), $ref, $dynamicRef, boolean schemas.
225
+ * REFERENCES: $id base-URI composition (RFC 3986 path merge),
226
+ * $anchor/$dynamicAnchor plain-name fragments scoped to their nearest
227
+ * $id resource, JSON Pointer fragments with the percent layer
228
+ * (%25 -> '%', then ~0/~1), and $dynamicRef's runtime dynamic scope
229
+ * (the OUTERMOST schema resource in scope defining the anchor). No
230
+ * network: a reference resolves only against the schema's own
231
+ * identifier space — an external target (the metaschema, an HTTP
232
+ * fixture) is a DIAG_REF, never a fetch. Boolean schemas
233
+ * (`true`/`false`) apply. Unknown keywords and known keywords with
234
+ * unreadable values are ignored (2020-12). Instance types ride the
235
+ * core-schema resolution (the YAML->JSON data model): "y" is boolean,
236
+ * 1.0 is integer. The IETF WG's next-edition draft
237
+ * (draft-ietf-jsonschema-json-schema-00) carries these same keyword
238
+ * semantics — no evaluator delta; the diff record is
239
+ * docs/schema/ietf-wg-draft-delta.md.
142
240
  *
143
241
  * Status: as yeptris_validate, plus YEPTRIS_ERROR_ARG when the schema
144
242
  * bytes hold no document, and YEPTRIS_ERROR_PARSE when they do not
@@ -150,6 +248,152 @@ YEPTRIS_API YeptrisStatus yeptris_json_schema_validate(const char* schema, size_
150
248
  const char* buf, size_t len,
151
249
  yeptris_validate_report** out);
152
250
 
251
+ /* The COMPILED SCHEMA — the leptris-XSD economy (#885 item 3): parse
252
+ * the schema ONCE, validate MANY instance streams against the retained
253
+ * model. The handle owns everything it reads: the schema bytes (copied
254
+ * — the retained DOM's views borrow them), the parsed document, and
255
+ * the pattern kernel's compiled programs (the XSD content-model
256
+ * analog: `(a+)+$` compiles once here, not once per validated string
257
+ * the way the one-shot face pays). yeptris_schema_compile returns NULL
258
+ * on failure; yeptris_last_error() carries the why (bad arguments,
259
+ * bytes that hold no document, a schema that does not parse,
260
+ * allocation failure).
261
+ *
262
+ * yeptris_schema_validate keeps yeptris_json_schema_validate's exact
263
+ * status/report contract; diagnostics enumerate every miss across
264
+ * every document of the instance stream — the stream face's document
265
+ * attribution applies (see STREAMS above): a multi-document stream's
266
+ * paths carry the document index. yeptris_schema_free releases
267
+ * the handle and everything it owns in ONE call (no refcounting) —
268
+ * afterwards the handle is DEAD: passing it anywhere is undefined,
269
+ * exactly like a freed document. NULL is accepted (a no-op).
270
+ *
271
+ * Thread law: one schema handle per thread, like documents — the
272
+ * handle is immutable after compile (the pattern programs are built at
273
+ * compile time), so read-only sharing across threads is safe; reports
274
+ * are per-call and caller-owned. */
275
+ typedef struct yeptris_schema yeptris_schema;
276
+
277
+ YEPTRIS_API yeptris_schema* yeptris_schema_compile(const char* bytes, size_t n);
278
+
279
+ YEPTRIS_API YeptrisStatus yeptris_schema_validate(yeptris_schema* s, const char* buf, size_t len,
280
+ yeptris_validate_report** out);
281
+
282
+ YEPTRIS_API void yeptris_schema_free(yeptris_schema* s);
283
+
284
+ /* ---- the TAG-DRIVEN SCHEMA registry (#906 slice 4) -----------------------
285
+ *
286
+ * The dialect table's reserved slot: a compiled schema binds to a user
287
+ * tag, so a document node carrying `!shape` (its EXPLICIT tag, exactly
288
+ * the resolved bytes the DOM exposes — `!shape`, `!<tag:...>`, or a
289
+ * `%TAG`-resolved URI; `!!x` arrives as `tag:yaml.org,2002:x`) has its
290
+ * SUBTREE validated against the bound schema. Registration is the only
291
+ * extension point (OCP): the family walk reads the registry, it never
292
+ * grows schema branches.
293
+ *
294
+ * Matching is byte-exact on the tag's resolved form and fires only on
295
+ * an explicit tag — implicit (plain) typing never triggers a binding.
296
+ * An unregistered tag passes untouched: no diagnostic, no lane. The
297
+ * hook rides the DOM family walk (yeptris_validate_ex /
298
+ * yeptris_validate_document_ex): roots, sequence items and mapping
299
+ * VALUES (a tagged mapping KEY is not registry-validated — its
300
+ * instance path is undefined in the walk's model). Diagnostics from a
301
+ * bound subtree land at the tag site: the tag node's own path + the
302
+ * schema walk's instance pointers, with the offending node's
303
+ * line/col/offset; the report cap and codes are the shared rail.
304
+ * Bindings COMPOSE: a node inside a bound subtree that carries its own
305
+ * registered tag is validated by both schemas.
306
+ *
307
+ * THE REGISTRY LAW (the document-ownership law, no refcounting): the
308
+ * registry BORROWS the compiled schemas it binds — it owns nothing
309
+ * they own. A bound schema must OUTLIVE the registry: free the
310
+ * registry first (yeptris_schema_registry_free), then the schemas.
311
+ * Freeing a bound schema while its registry lives leaves the registry
312
+ * dead (a later lookup is undefined), exactly like a freed document.
313
+ * NULL is accepted everywhere a handle is (a NULL registry is simply
314
+ * no bindings; yeptris_schema_registry_free(NULL) is a no-op).
315
+ *
316
+ * Thread law: one registry per thread, like documents and schemas —
317
+ * it is mutable under register and read-only during validation;
318
+ * read-only sharing across threads (no register in flight) is safe. */
319
+ typedef struct yeptris_schema_registry yeptris_schema_registry;
320
+
321
+ /* A fresh empty registry; NULL on allocation failure. */
322
+ YEPTRIS_API yeptris_schema_registry* yeptris_schema_registry_new(void);
323
+
324
+ /* Binds `tag` (copied — nothing borrows the caller's bytes beyond the
325
+ * call) to the compiled `schema` (borrowed — see THE REGISTRY LAW).
326
+ * Status: YEPTRIS_OK; YEPTRIS_ERROR_ARG (NULL handle, an empty tag,
327
+ * or a NULL schema); YEPTRIS_ERROR_MEMORY. Re-registering a tag
328
+ * REPLACES the binding (last registration wins). */
329
+ YEPTRIS_API YeptrisStatus yeptris_schema_registry_register(yeptris_schema_registry* reg,
330
+ const char* tag, size_t tag_len,
331
+ const yeptris_schema* schema);
332
+
333
+ /* The schema bound to `tag` (exact bytes), or NULL. Memory: borrowed
334
+ * from the registry — valid until a register replaces the tag or the
335
+ * registry is freed. */
336
+ YEPTRIS_API const yeptris_schema* yeptris_schema_registry_lookup(const yeptris_schema_registry* reg,
337
+ const char* tag, size_t tag_len);
338
+
339
+ YEPTRIS_API void yeptris_schema_registry_free(yeptris_schema_registry* reg);
340
+
341
+ /* Validation options (size-versioned like yeptris_emit_options:
342
+ * initialize with {sizeof(yeptris_validate_options)} so future fields
343
+ * stay optional; NULL selects the defaults). */
344
+ typedef struct yeptris_validate_options {
345
+ uint32_t size; /* sizeof(yeptris_validate_options) */
346
+ /* The tag-driven registry (#906 slice 4): NULL = none. Only read
347
+ * when the caller's struct is large enough (size-versioned). The
348
+ * registry is borrowed for the call; see THE REGISTRY LAW above. */
349
+ const yeptris_schema_registry* registry;
350
+ } yeptris_validate_options;
351
+
352
+ /* yeptris_validate / yeptris_validate_document with options: the
353
+ * family walk plus, when a registry is attached, the tag-driven
354
+ * schema applications described above. Everything else (statuses,
355
+ * report shape, paths, positions) is the flat face's, unchanged. */
356
+ YEPTRIS_API YeptrisStatus yeptris_validate_ex(const char* buf, size_t len, YeptrisSchema schema,
357
+ const yeptris_validate_options* opts,
358
+ yeptris_validate_report** out);
359
+
360
+ YEPTRIS_API YeptrisStatus yeptris_validate_document_ex(YeptrisDocument doc, YeptrisSchema schema,
361
+ const yeptris_validate_options* opts,
362
+ yeptris_validate_report** out);
363
+
364
+ /* ---- the structured OUTPUT face (#906 slice 5) ---------------------------
365
+ *
366
+ * The report as the json-schema.org RECOMMENDED OUTPUT shape (core
367
+ * spec section 12; the meta-schema at
368
+ * https://json-schema.org/draft/2020-12/output/schema): one root
369
+ * output unit — {"valid", "keywordLocation", "instanceLocation"} and,
370
+ * when the report carries diagnostics, "errors" — with one child unit
371
+ * per diagnostic {valid, keywordLocation, instanceLocation, error}.
372
+ * This is the published BASIC form: the report is flat by the
373
+ * enumerated-misses law, so the schema-structured DETAILED/VERBOSE
374
+ * hierarchies (which need per-miss schema-side keyword paths the flat
375
+ * report does not carry) are not derivable from it. keywordLocation
376
+ * is derived from the diagnostic code — the keyword's name segment
377
+ * ("/type", "/required", ...; the family codes and the bookkeeping
378
+ * codes sit at the root pointer ""); it is a JSON Pointer, but NOT
379
+ * necessarily resolvable in the schema (the flat report carries no
380
+ * schema path). absoluteKeywordLocation is never emitted, and $ref
381
+ * sites report the root pointer, so the output always satisfies the
382
+ * published meta-schema. Strings are JSON-escaped (RFC 8259); the
383
+ * bytes are UTF-8; the transform is pure and deterministic — the same
384
+ * report always produces the same bytes.
385
+ *
386
+ * buf == NULL: returns the exact byte count needed, writes nothing.
387
+ * Otherwise writes at most cap bytes (NUL-terminated when cap
388
+ * allows) and returns the count written; when cap is too small
389
+ * nothing is written and the needed size is returned. Returns 0 on a
390
+ * NULL report (use the flat face for those — the transform never
391
+ * invents a verdict).
392
+ *
393
+ * Memory: writes into the caller's buffer; borrows nothing. */
394
+ YEPTRIS_API size_t yeptris_validate_report_write(const yeptris_validate_report* report, char* buf,
395
+ size_t cap);
396
+
153
397
  #ifdef __cplusplus
154
398
  }
155
399
  #endif
@@ -52,7 +52,11 @@ typedef struct {
52
52
  uint8_t tag_id; /* the resolver's verdict for this scalar */
53
53
  uint8_t is_key; /* the entry lands in the inner map's key slot */
54
54
  uint8_t b; /* BOOL payload; implicit-plain flag otherwise */
55
- uint32_t off; /* STR/TIMESTAMP/ALIAS/anchor bytes */
55
+ uint32_t off; /* STR/TIMESTAMP/ALIAS/anchor bytes; SEQ/MAP OPEN:
56
+ * the collection's EXPLICIT tag text ("tag:yaml.
57
+ * org,2002:set") when it carries one — off/len stay
58
+ * 0 for untagged containers, so hosts re-tag
59
+ * containers without a second drain */
56
60
  uint32_t len;
57
61
  uint64_t p; /* INT or FLOAT payload, by kind */
58
62
  } YeptrisValue;
@@ -80,7 +84,9 @@ typedef struct {
80
84
  size_t count;
81
85
  size_t arena_len;
82
86
  int64_t* payloads; /* INT or FLOAT bits, by kind */
83
- uint32_t* offs; /* STR/TIMESTAMP/ALIAS/ANCHOR bytes */
87
+ uint32_t* offs; /* STR/TIMESTAMP/ALIAS/ANCHOR bytes; SEQ/MAP OPEN:
88
+ the explicit tag text when tagged (see
89
+ YeptrisValue.off) */
84
90
  uint32_t* lens;
85
91
  uint8_t* kinds; /* YeptrisValueKind */
86
92
  uint8_t* tags; /* resolver verdict per scalar */
@@ -11,6 +11,16 @@
11
11
  extern "C" {
12
12
  #endif
13
13
 
14
+ /* The semantic-tag chain law: decode renders the chain into a stack
15
+ * buffer; encode splits that text back into tag heads. ONE pair of
16
+ * constants governs both ends — the nightly's 23-nested-tags artifact
17
+ * (23 links decoded fine, encode-side tags[16] refused) was the two
18
+ * ends disagreeing. 64 links is already pathological (RFC 8949's
19
+ * registry is <20); a link renders up to 20 digits + separator, so
20
+ * the buffer holds a full 64-link chain. */
21
+ #define YEP_CBOR_TAGBUF 1408
22
+ #define YEP_CBOR_TAG_MAX_LINKS 64
23
+
14
24
  /* one data item: bytes -> the shared DOM (the plan's item 01) */
15
25
  /* One data item. consumed (may be NULL): when given, returns the
16
26
  * item's byte extent and TRAILING BYTES ARE NOT an error (the
@@ -50,11 +50,6 @@ typedef struct {
50
50
  uint8_t is_map;
51
51
  } yep_cframe;
52
52
 
53
- #define YEP_CBOR_TAGBUF \
54
- 512 /* a semantic-tag chain over ~23 links is \
55
- * pathological; the arena form had no cap, \
56
- * the stack form does (documented) */
57
-
58
53
  typedef struct {
59
54
  yep_dom* d; /* the DOM sink's ctx (NULL for pure sinks) */
60
55
  const unsigned char* p;
@@ -66,6 +61,7 @@ typedef struct {
66
61
  * first — the next item's writer consumes it) */
67
62
  char tagbuf[YEP_CBOR_TAGBUF];
68
63
  uint32_t taglen;
64
+ uint32_t taglinks; /* the chain's link count (the shared cap) */
69
65
  /* indefinite-string accumulation (chunk framing is the grammar's;
70
66
  * the finished span goes to one str/bytes callback) */
71
67
  unsigned char* ibuf;
@@ -190,6 +186,7 @@ static const char* cbor_take_tag(yep_cdec* c, uint32_t* len) {
190
186
  }
191
187
  *len = c->taglen;
192
188
  c->taglen = 0;
189
+ c->taglinks = 0;
193
190
  return c->tagbuf;
194
191
  }
195
192
 
@@ -239,9 +236,9 @@ static int cbor_open(yep_cdec* c, int is_map, uint64_t cap) {
239
236
  }
240
237
 
241
238
  static int cbor_note_tag(yep_cdec* c, uint64_t tag) {
242
- if (c->taglen + 1 + 20 > sizeof c->tagbuf) {
239
+ if (c->taglinks >= YEP_CBOR_TAG_MAX_LINKS || c->taglen + 1 + 20 > sizeof c->tagbuf) {
243
240
  yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, c->i,
244
- "semantic-tag chain exceeds %u bytes at byte %zu", (unsigned)sizeof c->tagbuf,
241
+ "semantic-tag chain exceeds %u links at byte %zu", YEP_CBOR_TAG_MAX_LINKS,
245
242
  c->i);
246
243
  c->status = YEPTRIS_ERROR_PARSE;
247
244
  return 0;
@@ -250,6 +247,7 @@ static int cbor_note_tag(yep_cdec* c, uint64_t tag) {
250
247
  c->tagbuf[c->taglen++] = ' '; /* separator between chain links */
251
248
  }
252
249
  c->taglen += cbor_u64dec(tag, c->tagbuf + c->taglen);
250
+ c->taglinks++;
253
251
  return 1;
254
252
  }
255
253
 
@@ -326,14 +326,14 @@ typedef struct {
326
326
  /* Encodes one KEY item (tags + scalar) into exactly-sized scratch. */
327
327
  static uint8_t* cbor_encode_key(const yep_dom* d, const yep_dnode* key, size_t* out_len) {
328
328
  yep_view v = yep_dom_view(d, key->value);
329
- size_t cap = 16 * 9 + 9 + v.len; /* tags + head + text */
329
+ size_t cap = (size_t)YEP_CBOR_TAG_MAX_LINKS * 9 + 9 + v.len; /* tags + head + text */
330
330
  uint8_t* buf = malloc(cap);
331
331
  if (buf == NULL) {
332
332
  return NULL;
333
333
  }
334
334
  size_t pos = 0;
335
- uint64_t tags[16];
336
- int ntags = cbor_tag_chain(d, key, tags, 16);
335
+ uint64_t tags[YEP_CBOR_TAG_MAX_LINKS];
336
+ int ntags = cbor_tag_chain(d, key, tags, YEP_CBOR_TAG_MAX_LINKS);
337
337
  if (ntags < 0) {
338
338
  goto bad;
339
339
  }
@@ -491,8 +491,8 @@ static size_t cbor_size_item(cenc* e, uint32_t id);
491
491
  static size_t cbor_size_scalar(cenc* e, const yep_dnode* n) {
492
492
  const yep_dom* d = e->d;
493
493
  size_t sz = 0;
494
- uint64_t tags[16];
495
- int ntags = cbor_tag_chain(d, n, tags, 16);
494
+ uint64_t tags[YEP_CBOR_TAG_MAX_LINKS];
495
+ int ntags = cbor_tag_chain(d, n, tags, YEP_CBOR_TAG_MAX_LINKS);
496
496
  if (ntags < 0) {
497
497
  e->failed = 1;
498
498
  e->status = YEPTRIS_ERROR_UNSUPPORTED;
@@ -534,8 +534,8 @@ static size_t cbor_size_item(cenc* e, uint32_t id) {
534
534
  return cbor_size_scalar(e, n); /* includes the node's own tags */
535
535
  }
536
536
  size_t sz = 0;
537
- uint64_t tags[16];
538
- int ntags = cbor_tag_chain(d, n, tags, 16);
537
+ uint64_t tags[YEP_CBOR_TAG_MAX_LINKS];
538
+ int ntags = cbor_tag_chain(d, n, tags, YEP_CBOR_TAG_MAX_LINKS);
539
539
  if (ntags < 0) {
540
540
  e->failed = 1;
541
541
  e->status = YEPTRIS_ERROR_UNSUPPORTED;
@@ -653,8 +653,8 @@ static void cbor_write_scalar(cenc* e, const yep_dnode* n, uint8_t* out, size_t*
653
653
  static void cbor_write_item(cenc* e, uint32_t id, uint8_t* out, size_t* pos) {
654
654
  const yep_dom* d = e->d;
655
655
  const yep_dnode* n = &d->nodes[id];
656
- uint64_t tags[16];
657
- int ntags = cbor_tag_chain(d, n, tags, 16);
656
+ uint64_t tags[YEP_CBOR_TAG_MAX_LINKS];
657
+ int ntags = cbor_tag_chain(d, n, tags, YEP_CBOR_TAG_MAX_LINKS);
658
658
  for (int t = 0; t < ntags; t++) {
659
659
  yep_cbor_put_head(out, pos, 6, tags[t]);
660
660
  }
@@ -1,7 +1,7 @@
1
1
  /* from_marshal.c — Ruby Marshal.dump bytes to ONE CBOR data item
2
2
  * (yeptris-ruby#322's CBOR half: the binding's dump face).
3
3
  *
4
- * The twin of emit/writer.c's marshal READER (yeptris_json_from_marshal):
4
+ * The twin of marshal/to_json.c's JSON reader (yeptris_json_from_marshal):
5
5
  * the Marshal stream is walked once, in C, and the CBOR item is
6
6
  * appended straight to the output — no per-node Ruby crossings, no
7
7
  * Document, no YAMLTree. The format facts mirror marshal.c's emission
@@ -25,6 +25,7 @@ extern "C" {
25
25
  #define YEP_ERROR_X(X) \
26
26
  X(YEP_ERR_NONE, "no error") \
27
27
  X(YEP_ERR_UNEXPECTED, "unexpected parser state") \
28
+ X(YEP_ERR_DOC_BOUNDARY, "invalid content at a document boundary") \
28
29
  X(YEP_ERR_MEMORY, "out of memory") \
29
30
  X(YEP_ERR_DEPTH, "nesting depth exceeds the limit") \
30
31
  X(YEP_ERR_ENCODING, "ill-formed or unsupported character encoding") \
@@ -33,6 +34,7 @@ extern "C" {
33
34
  X(YEP_ERR_BAD_INDENT, "inconsistent indentation") \
34
35
  X(YEP_ERR_KEY_TOO_LONG, "simple key exceeds 1024 characters") \
35
36
  X(YEP_ERR_UNDEFINED_ALIAS, "alias references an undefined anchor") \
37
+ X(YEP_ERR_ABORTED, "parse aborted by the event callback") \
36
38
  X(YEP_ERR_INVALID_ESCAPE, "invalid escape sequence in double-quoted scalar") \
37
39
  X(YEP_ERR_BAD_DIRECTIVE, "invalid or unsupported directive") \
38
40
  X(YEP_ERR_INTERNAL, "internal invariant violation") \
@@ -11,6 +11,9 @@
11
11
  #include "dom/dom.h"
12
12
  #include "memory/allocator.h"
13
13
 
14
+ #include <yeptris/error.h>
15
+ #include <yeptris/resolve.h> /* YeptrisSchema */
16
+
14
17
  typedef struct yeptris_document {
15
18
  yep_dom* dom;
16
19
  const yep_allocator* sys;
@@ -59,8 +62,25 @@ extern "C" {
59
62
  yep_dom* yep_doc_dom(yeptris_document* doc);
60
63
  yeptris_node* yep_handle_new(yeptris_document* doc, uint32_t id);
61
64
 
65
+ /* parse.c's sink-entry seam (#902): the DOM route's exact front-end and
66
+ * engine run into a caller sink — no DOM, no tape. Statuses are the
67
+ * parse route's (OK, or PARSE / DEPTH / ENCODING / MEMORY; the sink's
68
+ * own failure rides MEMORY like the DOM builder's). on_input (may be
69
+ * NULL) receives the run's input view — the DOM route's input_base law
70
+ * (the transcoded copy, or the caller's bytes) and its post-BOM length
71
+ * — immediately before the engine runs, because the events' borrowed
72
+ * views subtract from it. The bytes live only for the run. */
73
+ typedef void (*yep_input_fn)(void* ctx, const char* base, size_t len);
74
+ YeptrisStatus yep_parse_events(const char* buf, size_t len, YeptrisSchema schema,
75
+ const yep_sink* sink, yep_input_fn on_input, void* on_ctx);
76
+
62
77
  #ifdef __cplusplus
63
78
  }
64
79
  #endif
65
80
 
81
+ /* The typing SSOT's one switch (parse.c owns it; the stream iterator
82
+ * and any future bytes->document route select through it too). */
83
+ struct yep_resolver; /* resolve/resolver.h's fwd — doc.h stays leaf */
84
+ const struct yep_resolver* resolver_for_schema(YeptrisSchema schema);
85
+
66
86
  #endif /* YEP_DOC_H */