yeptris 0.6.57.1-aarch64-linux → 0.6.58.1-aarch64-linux

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d071b1a081dbf8992a7883e883fdd983b87a412146a4cf7d28350b0618aae1e
4
- data.tar.gz: 90ebeda42b248b5329a04394528790cd6c006f6643eb404dd912a37bede95745
3
+ metadata.gz: 5818ae725e39fa04b9800c2ceb9eb855bf9171984829ebd921b5e79b4f89b4e5
4
+ data.tar.gz: 82e7aa925d97603d8b127c9a86457717c180d97a49fd310db382b116a8e8bb89
5
5
  SHA512:
6
- metadata.gz: a6470d03e70743c5c4f798f0cbecf130a152159b2199254747c24d055e8bb766d335f74113aeec0fca593343a21b8d0716307451b7a9071fab4647873f23e781
7
- data.tar.gz: 29b9b8b6a78daa44723175aeea9fe4c03bcf38e8bff8e8518314d24d64afc246d151ab2923429d3e6d86ea0035a2d4b7720f4fa9eed744c02107a2046ce6028b
6
+ metadata.gz: 2a6dd6cf0a944461dcc4e6c6e0785b40c76ea96328a3f72688314d83f915f5c6afa96a5e08e478af1d0fe35356f2e16cb0fdd3dd104073fbbbb0311b2b5f89e2
7
+ data.tar.gz: 7652f2e05e068913782f77192e405957bc570aafc7b0157c289ca7f793280e366d1d27da43dca6ef26a3efbfaae1da2f447c193611beb410fce2c81117730ce3
@@ -11,8 +11,8 @@
11
11
 
12
12
  #define YEPTRIS_VERSION_MAJOR 0
13
13
  #define YEPTRIS_VERSION_MINOR 6
14
- #define YEPTRIS_VERSION_PATCH 57
15
- #define YEPTRIS_VERSION_STRING "0.6.57"
14
+ #define YEPTRIS_VERSION_PATCH 58
15
+ #define YEPTRIS_VERSION_STRING "0.6.58"
16
16
 
17
17
  #ifdef __cplusplus
18
18
  extern "C" {
Binary file
Binary file
Binary file
data/lib/yeptris.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module Yeptris
4
4
  # The gem's version lives in the parent namespace's file — the last
5
5
  # internal require (yeptris/version) retired with it.
6
- VERSION = "0.6.57.1".freeze
6
+ VERSION = "0.6.58.1".freeze
7
7
 
8
8
  # Informational notices are OPT-IN (yeptris-ruby#217): consumers
9
9
  # embed yeptris inside CLIs that assert clean stderr, and a
data/libyeptris.so CHANGED
Binary file
@@ -3,7 +3,7 @@
3
3
  cmake_minimum_required(VERSION 3.20)
4
4
 
5
5
  project(yeptris
6
- VERSION 0.6.57
6
+ VERSION 0.6.58
7
7
  DESCRIPTION "Ultra-fast YAML 1.2 parser, emitter and streamer in C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -39,9 +39,13 @@ set(YEPTRIS_SOURCES
39
39
  yeptris/resolve/tags.c
40
40
  yeptris/resolve/core12.c
41
41
  yeptris/resolve/compat11.c
42
+ yeptris/resolve/json12.c
42
43
  yeptris/parse/numbers.c
43
44
  yeptris/events/values.c
44
45
  yeptris/schema.c
46
+ yeptris/validate/regexp.c
47
+ yeptris/validate/validate.c
48
+ yeptris/validate/jsonschema.c
45
49
  yeptris/tape.c
46
50
  yeptris/plan.c
47
51
 
@@ -95,6 +99,7 @@ set(YEPTRIS_PUBLIC_HEADERS
95
99
  ${CMAKE_CURRENT_SOURCE_DIR}/include/yeptris/parse.h
96
100
  ${CMAKE_CURRENT_SOURCE_DIR}/include/yeptris/values.h
97
101
  ${CMAKE_CURRENT_SOURCE_DIR}/include/yeptris/schema.h
102
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/yeptris/validate.h
98
103
  ${CMAKE_CURRENT_SOURCE_DIR}/include/yeptris/tape.h
99
104
  ${CMAKE_CURRENT_SOURCE_DIR}/include/yeptris/plan.h
100
105
  ${CMAKE_CURRENT_SOURCE_DIR}/include/yeptris/marshal.h
@@ -25,7 +25,8 @@ typedef enum {
25
25
  YEPTRIS_ERROR_ARG = 6, /* invalid argument (NULL handle, bad option) */
26
26
  YEPTRIS_ERROR_UNSUPPORTED = 7, /* requested feature not built in */
27
27
  YEPTRIS_ERROR_INTERNAL = 8, /* invariant violation — a bug, please report */
28
- YEPTRIS_ERROR_SCHEMA = 9, /* descriptor materialization: a REQUIRED node missing (issue #238) */
28
+ YEPTRIS_ERROR_SCHEMA = 9, /* validation: the report carries diagnostics (#882);
29
+ * descriptor materialization: REQUIRED missing (#238) */
29
30
  } YeptrisStatus;
30
31
 
31
32
  /* Message of the most recent failure on the calling thread, with its
@@ -40,10 +40,12 @@ typedef enum {
40
40
  YEPTRIS_TAG_CUSTOM = 11,
41
41
  } YeptrisTagId;
42
42
 
43
- /* Schemas. */
43
+ /* Schemas. Appending only — bindings hard-code the values (test_abi). */
44
44
  typedef enum {
45
45
  YEPTRIS_SCHEMA_12_CORE = 0, /* default: the yaml-test-suite target */
46
46
  YEPTRIS_SCHEMA_11_COMPAT, /* libyaml/Psych implicit typing */
47
+ YEPTRIS_SCHEMA_12_JSON, /* spec 10.2: JSON productions; plain
48
+ * scalars matching none are errors (#882) */
47
49
  } YeptrisSchema;
48
50
 
49
51
  /* Canonical tag URI for a core id ("tag:yaml.org,2002:str"); NULL for
@@ -0,0 +1,157 @@
1
+ /* validate.h — the validation face (issue #882).
2
+ *
3
+ * Two checks over one engine pass:
4
+ *
5
+ * 1. SCHEMA-FAMILY validation (`yeptris_validate`): parse + validate
6
+ * fused. Under YEPTRIS_SCHEMA_12_CORE the walk checks explicit-tag
7
+ * consistency (spec 10.3 resolution) and mapping-key uniqueness
8
+ * (spec 3.2.1.3: keys compare by canonical form — 0o13 and 0xB
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.
13
+ *
14
+ * 2. JSON SCHEMA validation (`yeptris_json_schema_validate`): the
15
+ * schema arrives as bytes (parsed with the same engine), the
16
+ * target against it — draft 2020-12 keyword subset (see the entry
17
+ * comment). Unknown keywords are ignored, per 2020-12.
18
+ *
19
+ * Every diagnostic carries a JSON-pointer instance path ("/a/b/0" —
20
+ * ~0/~1 escaped), a YEPTRIS_DIAG_* code, a bounded expected/got
21
+ * detail, and the offending node's 1-based line/column (0 = unknown:
22
+ * scalars whose bytes the DOM owns in its arena have no input
23
+ * position; the path still identifies them exactly).
24
+ *
25
+ * Results are WHOLE REPORTS: one call, no per-diagnostic callback —
26
+ * the caller drains the flat array and frees the report once.
27
+ */
28
+ #ifndef YEPTRIS_VALIDATE_H
29
+ #define YEPTRIS_VALIDATE_H
30
+
31
+ #include <stddef.h>
32
+ #include <stdint.h>
33
+
34
+ #include <yeptris/api.h>
35
+ #include <yeptris/error.h>
36
+ #include <yeptris/parse.h> /* YeptrisDocument, YeptrisSchema */
37
+ #include <yeptris/types.h>
38
+
39
+ #ifdef __cplusplus
40
+ extern "C" {
41
+ #endif
42
+
43
+ /* Diagnostic codes. Appending only — bindings hard-code the values
44
+ * (test_abi pins the head). */
45
+ typedef enum {
46
+ YEPTRIS_DIAG_NONE = 0,
47
+ /* the schema-family walk */
48
+ YEPTRIS_DIAG_TAG_MISMATCH = 1, /* explicit tag contradicts content */
49
+ YEPTRIS_DIAG_KEY_NOT_STRING = 2, /* json12: mapping key is not a string */
50
+ YEPTRIS_DIAG_NON_JSON_TYPE = 3, /* json12: plain scalar matches no
51
+ * JSON production / carries a
52
+ * non-JSON tag (spec 10.2.2 Error) */
53
+ YEPTRIS_DIAG_DUPLICATE_KEY = 4, /* equal keys in one mapping */
54
+ /* the JSON Schema walk */
55
+ YEPTRIS_DIAG_TYPE = 5,
56
+ YEPTRIS_DIAG_REQUIRED = 6,
57
+ YEPTRIS_DIAG_ENUM = 7,
58
+ YEPTRIS_DIAG_CONST = 8,
59
+ YEPTRIS_DIAG_PATTERN = 9,
60
+ YEPTRIS_DIAG_MINIMUM = 10,
61
+ YEPTRIS_DIAG_MAXIMUM = 11,
62
+ YEPTRIS_DIAG_EXCLUSIVE_MINIMUM = 12,
63
+ YEPTRIS_DIAG_EXCLUSIVE_MAXIMUM = 13,
64
+ YEPTRIS_DIAG_MIN_LENGTH = 14,
65
+ YEPTRIS_DIAG_MAX_LENGTH = 15,
66
+ YEPTRIS_DIAG_MIN_ITEMS = 16,
67
+ YEPTRIS_DIAG_MAX_ITEMS = 17,
68
+ YEPTRIS_DIAG_UNIQUE_ITEMS = 18,
69
+ YEPTRIS_DIAG_ADDITIONAL_PROPERTY = 19,
70
+ YEPTRIS_DIAG_ANY_OF = 20,
71
+ YEPTRIS_DIAG_ONE_OF = 21,
72
+ YEPTRIS_DIAG_NOT = 22,
73
+ YEPTRIS_DIAG_REF = 23, /* $ref unresolvable / chain too deep */
74
+ YEPTRIS_DIAG_FALSE_SCHEMA = 24, /* the schema is `false` here */
75
+ YEPTRIS_DIAG_DEPTH = 25, /* recursion guard tripped */
76
+ YEPTRIS_DIAG_LIMIT = 26, /* report truncated (the sentinel
77
+ * rides the LAST slot; more
78
+ * diagnostics were dropped) */
79
+ } YeptrisDiagCode;
80
+
81
+ /* Bounded diagnostic text; always NUL-terminated (over-long paths and
82
+ * details truncate — the same discipline as the error channel). */
83
+ #define YEPTRIS_DIAG_PATH_MAX 256
84
+ #define YEPTRIS_DIAG_DETAIL_MAX 128
85
+
86
+ typedef struct yeptris_diagnostic {
87
+ uint32_t code; /* YeptrisDiagCode */
88
+ uint32_t line; /* 1-based; 0 = unknown */
89
+ uint32_t col; /* 1-based; 0 = unknown */
90
+ uint32_t offset;
91
+ char path[YEPTRIS_DIAG_PATH_MAX];
92
+ char detail[YEPTRIS_DIAG_DETAIL_MAX];
93
+ } yeptris_diagnostic;
94
+ YEPTRIS_CT_ASSERT(sizeof(yeptris_diagnostic) ==
95
+ 16 + YEPTRIS_DIAG_PATH_MAX + YEPTRIS_DIAG_DETAIL_MAX);
96
+
97
+ /* The diagnostics list. Opaque; free it with
98
+ * yeptris_validate_report_free (one call, everything). */
99
+ typedef struct yeptris_validate_report yeptris_validate_report;
100
+
101
+ /* Diagnostic count (0 = the document is valid). */
102
+ YEPTRIS_API size_t yeptris_validate_report_count(const yeptris_validate_report* report);
103
+
104
+ /* Diagnostic i (0-based); NULL out of range. Memory: borrowed from the
105
+ * report — valid until yeptris_validate_report_free. */
106
+ YEPTRIS_API const yeptris_diagnostic*
107
+ yeptris_validate_report_at(const yeptris_validate_report* report, size_t index);
108
+
109
+ YEPTRIS_API void yeptris_validate_report_free(yeptris_validate_report* report);
110
+
111
+ /* Parses `buf` (the same front door as yeptris_parse_ex: encodings,
112
+ * BOM, NEL normalization) and validates every document of the stream
113
+ * against `schema`. Paths are root-relative per document.
114
+ *
115
+ * Status: YEPTRIS_OK (valid; *out is a report — possibly with zero
116
+ * diagnostics for an empty stream); YEPTRIS_ERROR_SCHEMA (invalid:
117
+ * drain *out); YEPTRIS_ERROR_PARSE / DEPTH / ENCODING / MEMORY (the
118
+ * parse itself failed; *out stays NULL); YEPTRIS_ERROR_ARG.
119
+ *
120
+ * Memory: the caller owns *out; free it with
121
+ * yeptris_validate_report_free. */
122
+ YEPTRIS_API YeptrisStatus yeptris_validate(const char* buf, size_t len, YeptrisSchema schema,
123
+ yeptris_validate_report** out);
124
+
125
+ /* Validates an already-parsed document (or stream). The document is
126
+ * not modified; the report borrows nothing from it. */
127
+ YEPTRIS_API YeptrisStatus yeptris_validate_document(YeptrisDocument doc, YeptrisSchema schema,
128
+ yeptris_validate_report** out);
129
+
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),
134
+ * 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.
142
+ *
143
+ * Status: as yeptris_validate, plus YEPTRIS_ERROR_ARG when the schema
144
+ * bytes hold no document, and YEPTRIS_ERROR_PARSE when they do not
145
+ * parse. A $ref that resolves nowhere is a DIAG_REF diagnostic, not a
146
+ * status. Recursion is depth-guarded (the engine's guard): a
147
+ * self-referential $ref over a deep or cyclic chain reports DIAG_DEPTH
148
+ * / DIAG_REF — never a crash. */
149
+ YEPTRIS_API YeptrisStatus yeptris_json_schema_validate(const char* schema, size_t schema_len,
150
+ const char* buf, size_t len,
151
+ yeptris_validate_report** out);
152
+
153
+ #ifdef __cplusplus
154
+ }
155
+ #endif
156
+
157
+ #endif /* YEPTRIS_VALIDATE_H */
@@ -18,6 +18,7 @@
18
18
  #include <yeptris/parse.h>
19
19
  #include <yeptris/resolve.h>
20
20
  #include <yeptris/types.h>
21
+ #include <yeptris/validate.h>
21
22
  #include <yeptris/version.h>
22
23
 
23
24
  #endif /* YEPTRIS_H */
@@ -325,9 +325,13 @@ static YeptrisDocument parse_impl(const char* buf, size_t len, const YeptrisPars
325
325
  engine_enter:
326
326
  eng = yep_engine_create(sys);
327
327
  if (opts != NULL) {
328
+ /* the typing SSOT: the family's resolver (compat11 when asked,
329
+ * json12 for the 12_JSON validation family, core12 otherwise) */
328
330
  yep_engine_set_resolver(eng, opts->schema == YEPTRIS_SCHEMA_11_COMPAT
329
331
  ? yep_resolver_compat11()
330
- : yep_resolver_core12());
332
+ : (opts->schema == YEPTRIS_SCHEMA_12_JSON
333
+ ? yep_resolver_json12()
334
+ : yep_resolver_core12()));
331
335
  if (opts->schema == YEPTRIS_SCHEMA_11_COMPAT) {
332
336
  /* the compat schema is the psych/libyaml surface: its grammar
333
337
  * must accept what libyaml accepts (the flow floor is suite-
@@ -357,9 +361,13 @@ engine_enter:
357
361
  }
358
362
  /* the direct builders resolve with the engine's schema (the typing
359
363
  * SSOT — one resolver decision per scalar, whichever path builds) */
360
- dom->resolver = (opts != NULL && opts->schema == YEPTRIS_SCHEMA_11_COMPAT)
361
- ? yep_resolver_compat11()
362
- : yep_resolver_core12();
364
+ if (opts != NULL && opts->schema == YEPTRIS_SCHEMA_11_COMPAT) {
365
+ dom->resolver = yep_resolver_compat11();
366
+ } else if (opts != NULL && opts->schema == YEPTRIS_SCHEMA_12_JSON) {
367
+ dom->resolver = yep_resolver_json12();
368
+ } else {
369
+ dom->resolver = yep_resolver_core12();
370
+ }
363
371
  /* BEFORE the run: input-slice strings borrow as views (zero copy)
364
372
  * — the document keeps `transcoded` alive for exactly this. Set
365
373
  * after, every scalar was arena-copied (found 2026-09-10). */
@@ -422,6 +430,8 @@ engine_enter:
422
430
  } else if (have_tape && !norm_kept_raw &&
423
431
  ytap_fused_run(&yt, (opts != NULL && opts->schema == YEPTRIS_SCHEMA_11_COMPAT)
424
432
  ? yep_resolver_compat11()
433
+ : (opts != NULL && opts->schema == YEPTRIS_SCHEMA_12_JSON)
434
+ ? yep_resolver_json12()
425
435
  : yep_resolver_core12()) == 0) {
426
436
  /* the fused block runner owned the whole document — the engine
427
437
  * never runs (TODO.restructure/79). Its only cost was the parse
@@ -496,9 +506,8 @@ engine_enter:
496
506
  }
497
507
  yep_mutex_init(&doc->lazy_mu);
498
508
  doc->sys = sys;
499
- doc->schema = (opts != NULL && opts->schema == YEPTRIS_SCHEMA_11_COMPAT)
500
- ? YEPTRIS_SCHEMA_11_COMPAT
501
- : YEPTRIS_SCHEMA_12_CORE;
509
+ doc->schema = (opts != NULL && opts->schema != YEPTRIS_SCHEMA_12_CORE) ? opts->schema
510
+ : YEPTRIS_SCHEMA_12_CORE;
502
511
  doc->transcoded = transcoded;
503
512
  doc->transcoded_len = transcoded_len;
504
513
  doc->input = buf;
@@ -0,0 +1,103 @@
1
+ /* json12.c — the spec 10.2 JSON schema resolver (#882).
2
+ *
3
+ * The productions are the spec 10.2.2 table (1.2.2 erratum kept: the
4
+ * float regex needs NO digits after the dot — "0." is a float):
5
+ * null: null
6
+ * bool: true | false
7
+ * int: -? ( 0 | [1-9] [0-9]* )
8
+ * float: -? ( 0 | [1-9] [0-9]* ) ( \. [0-9]* )? ( [eE] [-+]? [0-9]+ )?
9
+ * * -> Error (the validator's business; the resolver stays str)
10
+ *
11
+ * Deliberately NOT accepted (the core schema's extensions): "True"/
12
+ * "False"/"NULL" casings, "~"/empty nulls, +signs, 0o/0x radix, .inf/
13
+ * .nan, underscores. The example-10.8 Invalid list pins each one.
14
+ *
15
+ * Shape: yep_json12_plain is the ONE classifier — the resolver wraps
16
+ * it, and the validator re-asks it per plain scalar (no second truth
17
+ * table anywhere). Parse never errors here: a scalar outside the
18
+ * productions resolves str so the DOM stays family-neutral; the
19
+ * validation face turns the spec's Error row into diagnostics.
20
+ */
21
+
22
+ #include <stdint.h>
23
+ #include <string.h>
24
+
25
+ #include "resolver.h"
26
+
27
+ /* JSON int: -?(0|[1-9][0-9]*); optionally continues as the float
28
+ * production (the int regex is a prefix of the float one). Returns 1
29
+ * (int), 2 (float), 0 (no production). */
30
+ int yep_json12_plain(const char* p, uint32_t n) {
31
+ if (n == 0) {
32
+ return 0;
33
+ }
34
+ if (n == 4 && memcmp(p, "null", 4) == 0) {
35
+ return 4; /* null */
36
+ }
37
+ if (n == 4 && memcmp(p, "true", 4) == 0) {
38
+ return 3; /* bool */
39
+ }
40
+ if (n == 5 && memcmp(p, "false", 5) == 0) {
41
+ return 3;
42
+ }
43
+ uint32_t i = (p[0] == '-') ? 1 : 0;
44
+ if (i >= n) {
45
+ return 0; /* lone "-" (or empty after the prefix check) */
46
+ }
47
+ /* int part: 0 | [1-9][0-9]* — no +sign, no leading zeros */
48
+ if (p[i] == '0') {
49
+ i++;
50
+ } else if (p[i] >= '1' && p[i] <= '9') {
51
+ i++;
52
+ while (i < n && p[i] >= '0' && p[i] <= '9') {
53
+ i++;
54
+ }
55
+ } else {
56
+ return 0;
57
+ }
58
+ if (i == n) {
59
+ return 1; /* bare int */
60
+ }
61
+ /* float tail: (\.[0-9]*)? ([eE][-+]?[0-9]+)? — at least one of the
62
+ * two must be present (a bare int already returned) */
63
+ int floaty = 0;
64
+ if (p[i] == '.') {
65
+ floaty = 1;
66
+ i++;
67
+ while (i < n && p[i] >= '0' && p[i] <= '9') {
68
+ i++; /* digits optional after the dot (1.2.2 erratum) */
69
+ }
70
+ }
71
+ if (i < n && (p[i] == 'e' || p[i] == 'E')) {
72
+ i++;
73
+ if (i < n && (p[i] == '+' || p[i] == '-')) {
74
+ i++;
75
+ }
76
+ int ed = 0;
77
+ while (i < n && p[i] >= '0' && p[i] <= '9') {
78
+ i++;
79
+ ed = 1;
80
+ }
81
+ if (!ed) {
82
+ return 0; /* exponent sign(s) with no digits */
83
+ }
84
+ floaty = 1;
85
+ }
86
+ return (floaty && i == n) ? 2 : 0;
87
+ }
88
+
89
+ static yep_tag_id json12(void* ctx, const char* p, uint32_t n) {
90
+ (void)ctx;
91
+ return (yep_tag_id)yep_json12_plain(p, n);
92
+ }
93
+
94
+ static yep_tag_id json12_number(void* ctx, int is_float) {
95
+ (void)ctx;
96
+ return is_float ? 2 : 1;
97
+ }
98
+
99
+ static const yep_resolver k_json12 = {json12, json12_number, NULL};
100
+
101
+ const yep_resolver* yep_resolver_json12(void) {
102
+ return &k_json12;
103
+ }
@@ -40,6 +40,15 @@ static inline yep_tag_id yep_resolve_number(const yep_resolver* r, int is_float)
40
40
  const yep_resolver* yep_resolver_core12(void);
41
41
  const yep_resolver* yep_resolver_compat11(void);
42
42
 
43
+ /* The spec 10.2 JSON schema resolver (#882): null/true/false exact,
44
+ * the JSON int and float productions, everything else str. Parse stays
45
+ * lenient — the VALIDATOR flags plain scalars that matched no
46
+ * production (the spec's `*` -> Error row) through the classifier. */
47
+ const yep_resolver* yep_resolver_json12(void);
48
+ /* 1 when the plain span matches a JSON-schema production. The one
49
+ * truth table for the 12_JSON family (validate/ re-asks it). */
50
+ int yep_json12_plain(const char* p, uint32_t n);
51
+
43
52
  /* core tag id <-> canonical URI (tags.c is the identity SSOT). */
44
53
  const char* yep_tag_uri(yep_tag_id id);
45
54
 
@@ -0,0 +1,102 @@
1
+ /* validate/internal.h — the validation face's shared internals (#882).
2
+ *
3
+ * Private to src/yeptris/validate/: the report shape, the diagnostic
4
+ * emitter (path capture + line/col resolution), and the JSON-pointer
5
+ * scratch path. The two walks (validate.c's schema family and
6
+ * jsonschema.c's keyword subset) share only this — MECE keeps the
7
+ * checks themselves in their own TUs.
8
+ */
9
+ #ifndef YEP_VALIDATE_INTERNAL_H
10
+ #define YEP_VALIDATE_INTERNAL_H
11
+
12
+ #include <stdarg.h>
13
+ #include <stddef.h>
14
+ #include <stdint.h>
15
+
16
+ #include <yeptris/validate.h>
17
+
18
+ #include "../dom/dom.h"
19
+
20
+ #ifdef __cplusplus
21
+ extern "C" {
22
+ #endif
23
+
24
+ /* The report cap: a hostile document can carry O(nodes) violations, so
25
+ * the walk stops here and the LIMIT sentinel replaces the last slot. */
26
+ #define YEP_VALIDATE_MAX_DIAGS 256
27
+
28
+ struct yeptris_validate_report {
29
+ yeptris_diagnostic* diags;
30
+ uint32_t count;
31
+ int truncated;
32
+ };
33
+
34
+ typedef struct yep_vctx {
35
+ const yep_dom* dom;
36
+ yeptris_validate_report* rep;
37
+ /* line/col resolution over the node bytes (lazy: built on the
38
+ * first positioned diagnostic; valid documents never pay) */
39
+ const char* input;
40
+ size_t input_len;
41
+ uint32_t* line_off; /* byte offset of every line start */
42
+ uint32_t line_cnt, line_cap;
43
+ /* JSON-pointer path under construction (DFS scratch) */
44
+ char* path;
45
+ size_t path_len, path_cap;
46
+ int depth; /* the walk's nesting guard (never exceeds the DOM's) */
47
+ int oom; /* an allocation failed: stop diagnosing */
48
+ /* JSON Schema trial suppression (anyOf/oneOf/not probes) */
49
+ int suppress;
50
+ int trial_hit;
51
+ int ref_depth; /* consecutive $ref expansions */
52
+ } yep_vctx;
53
+
54
+ /* Offset of a node's first positioned byte (the value span of the node
55
+ * itself, or of its first scalar leaf for collections; UINT32_MAX when
56
+ * everything reachable lives in the arena — line/col unknown). */
57
+ uint32_t yep_validate_node_off(const yep_dom* d, uint32_t id);
58
+
59
+ /* Emits one diagnostic at the current path. line/col resolve from
60
+ * `off` through the lazy line index; 0/0 when unknown. Detail is
61
+ * printf-composed into the bounded slot. Never fails the caller: the
62
+ * report cap turns the last slot into the LIMIT sentinel. */
63
+ void yep_validate_emit(yep_vctx* c, int code, uint32_t off, const char* detail_fmt, ...);
64
+
65
+ /* JSON-pointer path scratch: push an escaped segment / a decimal
66
+ * index, pop to a mark. 0 ok, -1 OOM (ctx.oom set; the walk unwinds). */
67
+ int yep_validate_path_push(yep_vctx* c, const char* seg, size_t seg_len);
68
+ int yep_validate_path_push_index(yep_vctx* c, uint32_t idx);
69
+ void yep_validate_path_pop(yep_vctx* c, size_t mark);
70
+
71
+ /* The bounded ECMA-regex subset behind `pattern` (jsonschema.c):
72
+ * literals, '.', classes, groups, alternation, the greedy/lazy
73
+ * quantifiers, anchors, \d\w\s\D\W\S\b\B and \xHH. Byte-oriented
74
+ * (ASCII classes; UTF-8 literals match byte-wise). A Thompson NFA —
75
+ * O(len * m), no backtracking blowup; patterns over the program
76
+ * budget are invalid. 1 match, 0 no match, -1 invalid pattern. */
77
+ int yep_re_search(const char* pat, uint32_t pat_len, const char* s, uint32_t s_len);
78
+
79
+ /* Canonical scalar tag of a DOM node (explicit tag, then the parse
80
+ * resolver's plain verdict, then str): the value model both walks
81
+ * compare under. */
82
+ uint8_t yep_validate_scalar_tag(const yep_dnode* n);
83
+
84
+ /* Canonical-form hash and equality over DOM subtrees (spec 3.2.1.3:
85
+ * same tag + canonical form; numbers numerically within a tag). The
86
+ * equality may cross documents — the schema's enum/const live in a
87
+ * different DOM than the instance. Depth-bounded. */
88
+ uint64_t yep_validate_node_hash(const yep_dom* d, uint32_t id, int depth);
89
+ int yep_validate_node_equal(const yep_dom* da, uint32_t a, const yep_dom* db, uint32_t b,
90
+ int depth);
91
+
92
+ /* jsonschema.c's driver: applies the schema tree (its own DOM) to
93
+ * every instance document root, emitting into `rep`. Returns 0, -1
94
+ * on OOM. */
95
+ int yep_jsonschema_run(const yep_dom* schema_dom, uint32_t schema_root, const yep_dom* instance_dom,
96
+ const uint32_t* doc_roots, uint32_t doc_count, yeptris_validate_report* rep);
97
+
98
+ #ifdef __cplusplus
99
+ }
100
+ #endif
101
+
102
+ #endif /* YEP_VALIDATE_INTERNAL_H */