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.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/README.adoc +141 -0
  3. data/ext/build_windows_native.rb +41 -0
  4. data/ext/libyeptris/extconf.rb +57 -0
  5. data/ext/yeptris_native/cbor_ruby.c +193 -0
  6. data/ext/yeptris_native/extconf.rb +47 -0
  7. data/ext/yeptris_native/json_ruby.c +354 -0
  8. data/ext/yeptris_native/yeptris_native.c +497 -0
  9. data/lib/yeptris/cbor.rb +130 -0
  10. data/lib/yeptris/document.rb +255 -0
  11. data/lib/yeptris/ffi.rb +426 -0
  12. data/lib/yeptris/json/descriptor.rb +266 -0
  13. data/lib/yeptris/json.rb +394 -0
  14. data/lib/yeptris/materializer.rb +354 -0
  15. data/lib/yeptris/native-3.4.so +0 -0
  16. data/lib/yeptris/node.rb +453 -0
  17. data/lib/yeptris/psych/class_loader.rb +24 -0
  18. data/lib/yeptris/psych/coder_shim.rb +55 -0
  19. data/lib/yeptris/psych/drop_in.rb +63 -0
  20. data/lib/yeptris/psych/encodable.rb +14 -0
  21. data/lib/yeptris/psych/handler.rb +90 -0
  22. data/lib/yeptris/psych/parser.rb +105 -0
  23. data/lib/yeptris/psych/scalar_scanner.rb +149 -0
  24. data/lib/yeptris/psych/visitors.rb +545 -0
  25. data/lib/yeptris/psych.rb +622 -0
  26. data/lib/yeptris/schema.rb +253 -0
  27. data/lib/yeptris/valueml.rb +455 -0
  28. data/lib/yeptris/yaml/descriptor.rb +56 -0
  29. data/lib/yeptris/yaml.rb +422 -0
  30. data/lib/yeptris.rb +113 -0
  31. data/libyeptris.so +0 -0
  32. data/vendor/libyeptris/CMakeLists.txt +254 -0
  33. data/vendor/libyeptris/cmake/yeptris-config.cmake.in +5 -0
  34. data/vendor/libyeptris/cmake/yeptris.pc.in +11 -0
  35. data/vendor/libyeptris/src/CMakeLists.txt +167 -0
  36. data/vendor/libyeptris/src/include/yeptris/api.h +32 -0
  37. data/vendor/libyeptris/src/include/yeptris/cbor.h +101 -0
  38. data/vendor/libyeptris/src/include/yeptris/dom.h +190 -0
  39. data/vendor/libyeptris/src/include/yeptris/emit.h +81 -0
  40. data/vendor/libyeptris/src/include/yeptris/error.h +41 -0
  41. data/vendor/libyeptris/src/include/yeptris/events.h +157 -0
  42. data/vendor/libyeptris/src/include/yeptris/json.h +45 -0
  43. data/vendor/libyeptris/src/include/yeptris/json.hpp +258 -0
  44. data/vendor/libyeptris/src/include/yeptris/jsonc_compat.h +115 -0
  45. data/vendor/libyeptris/src/include/yeptris/marshal.h +52 -0
  46. data/vendor/libyeptris/src/include/yeptris/parse.h +48 -0
  47. data/vendor/libyeptris/src/include/yeptris/plan.h +100 -0
  48. data/vendor/libyeptris/src/include/yeptris/resolve.h +71 -0
  49. data/vendor/libyeptris/src/include/yeptris/schema.h +121 -0
  50. data/vendor/libyeptris/src/include/yeptris/tape.h +123 -0
  51. data/vendor/libyeptris/src/include/yeptris/types.h +38 -0
  52. data/vendor/libyeptris/src/include/yeptris/values.h +102 -0
  53. data/vendor/libyeptris/src/include/yeptris/version.h.in +29 -0
  54. data/vendor/libyeptris/src/include/yeptris/visit.h +77 -0
  55. data/vendor/libyeptris/src/include/yeptris/yajl_compat.h +135 -0
  56. data/vendor/libyeptris/src/include/yeptris.h +23 -0
  57. data/vendor/libyeptris/src/yeptris/build.c +376 -0
  58. data/vendor/libyeptris/src/yeptris/cbor/cbor.h +25 -0
  59. data/vendor/libyeptris/src/yeptris/cbor/decode.c +981 -0
  60. data/vendor/libyeptris/src/yeptris/cbor/encode.c +835 -0
  61. data/vendor/libyeptris/src/yeptris/cbor/sink.h +58 -0
  62. data/vendor/libyeptris/src/yeptris/common/chartype.c +41 -0
  63. data/vendor/libyeptris/src/yeptris/common/chartype.h +77 -0
  64. data/vendor/libyeptris/src/yeptris/common/cpu.c +81 -0
  65. data/vendor/libyeptris/src/yeptris/common/cpu.h +40 -0
  66. data/vendor/libyeptris/src/yeptris/common/error.c +65 -0
  67. data/vendor/libyeptris/src/yeptris/common/error.h +79 -0
  68. data/vendor/libyeptris/src/yeptris/common/mutex.h +45 -0
  69. data/vendor/libyeptris/src/yeptris/common/nametab.c +275 -0
  70. data/vendor/libyeptris/src/yeptris/common/nametab.h +68 -0
  71. data/vendor/libyeptris/src/yeptris/common/port.h +74 -0
  72. data/vendor/libyeptris/src/yeptris/common/simd_text.c +49 -0
  73. data/vendor/libyeptris/src/yeptris/common/simd_text.h +295 -0
  74. data/vendor/libyeptris/src/yeptris/common/simd_text_avx2.c +534 -0
  75. data/vendor/libyeptris/src/yeptris/common/simd_text_neon.c +662 -0
  76. data/vendor/libyeptris/src/yeptris/common/simd_text_scalar.c +298 -0
  77. data/vendor/libyeptris/src/yeptris/common/string_view.c +34 -0
  78. data/vendor/libyeptris/src/yeptris/common/string_view.h +93 -0
  79. data/vendor/libyeptris/src/yeptris/doc.h +56 -0
  80. data/vendor/libyeptris/src/yeptris/dom/dom.c +1192 -0
  81. data/vendor/libyeptris/src/yeptris/dom/dom.h +312 -0
  82. data/vendor/libyeptris/src/yeptris/dom/hpool.c +107 -0
  83. data/vendor/libyeptris/src/yeptris/dom/mapindex.c +173 -0
  84. data/vendor/libyeptris/src/yeptris/dom/mapindex.h +61 -0
  85. data/vendor/libyeptris/src/yeptris/dom/mutate.c +431 -0
  86. data/vendor/libyeptris/src/yeptris/emit/emit.c +434 -0
  87. data/vendor/libyeptris/src/yeptris/emit/float/api.h +38 -0
  88. data/vendor/libyeptris/src/yeptris/emit/float/dragon.c +405 -0
  89. data/vendor/libyeptris/src/yeptris/emit/float/floatint.h +231 -0
  90. data/vendor/libyeptris/src/yeptris/emit/float/print.c +396 -0
  91. data/vendor/libyeptris/src/yeptris/emit/style.c +81 -0
  92. data/vendor/libyeptris/src/yeptris/emit/style.h +24 -0
  93. data/vendor/libyeptris/src/yeptris/emit/writer.c +816 -0
  94. data/vendor/libyeptris/src/yeptris/emit/writer.h +76 -0
  95. data/vendor/libyeptris/src/yeptris/encoding/bom.c +31 -0
  96. data/vendor/libyeptris/src/yeptris/encoding/encoding.h +63 -0
  97. data/vendor/libyeptris/src/yeptris/encoding/transcode.c +148 -0
  98. data/vendor/libyeptris/src/yeptris/encoding/utf8_validate.c +178 -0
  99. data/vendor/libyeptris/src/yeptris/events/capture.c +150 -0
  100. data/vendor/libyeptris/src/yeptris/events/capture.h +39 -0
  101. data/vendor/libyeptris/src/yeptris/events/iterparse.c +208 -0
  102. data/vendor/libyeptris/src/yeptris/events/pull.c +97 -0
  103. data/vendor/libyeptris/src/yeptris/events/push.c +104 -0
  104. data/vendor/libyeptris/src/yeptris/events/recorder.c +107 -0
  105. data/vendor/libyeptris/src/yeptris/events/values.c +527 -0
  106. data/vendor/libyeptris/src/yeptris/events/values_priv.h +51 -0
  107. data/vendor/libyeptris/src/yeptris/events/yaml_compat.c +86 -0
  108. data/vendor/libyeptris/src/yeptris/events/yaml_compat.h +90 -0
  109. data/vendor/libyeptris/src/yeptris/jsonapi/jsonc_compat.c +687 -0
  110. data/vendor/libyeptris/src/yeptris/jsonapi/yajl_compat.c +728 -0
  111. data/vendor/libyeptris/src/yeptris/marshal.c +782 -0
  112. data/vendor/libyeptris/src/yeptris/memory/allocator.c +20 -0
  113. data/vendor/libyeptris/src/yeptris/memory/allocator.h +43 -0
  114. data/vendor/libyeptris/src/yeptris/memory/arena.c +134 -0
  115. data/vendor/libyeptris/src/yeptris/memory/arena.h +52 -0
  116. data/vendor/libyeptris/src/yeptris/memory/pool.c +122 -0
  117. data/vendor/libyeptris/src/yeptris/memory/pool.h +36 -0
  118. data/vendor/libyeptris/src/yeptris/parse/engine.c +3698 -0
  119. data/vendor/libyeptris/src/yeptris/parse/engine.h +65 -0
  120. data/vendor/libyeptris/src/yeptris/parse/events.h +124 -0
  121. data/vendor/libyeptris/src/yeptris/parse/numbers.c +349 -0
  122. data/vendor/libyeptris/src/yeptris/parse/numbers.h +33 -0
  123. data/vendor/libyeptris/src/yeptris/parse/scalars.c +416 -0
  124. data/vendor/libyeptris/src/yeptris/parse/scalars.h +75 -0
  125. data/vendor/libyeptris/src/yeptris/parse.c +737 -0
  126. data/vendor/libyeptris/src/yeptris/plan.c +824 -0
  127. data/vendor/libyeptris/src/yeptris/resolve/compat11.c +334 -0
  128. data/vendor/libyeptris/src/yeptris/resolve/core12.c +143 -0
  129. data/vendor/libyeptris/src/yeptris/resolve/resolver.h +56 -0
  130. data/vendor/libyeptris/src/yeptris/resolve/tags.c +58 -0
  131. data/vendor/libyeptris/src/yeptris/scan/json.c +792 -0
  132. data/vendor/libyeptris/src/yeptris/scan/json.h +109 -0
  133. data/vendor/libyeptris/src/yeptris/scan/scan.c +463 -0
  134. data/vendor/libyeptris/src/yeptris/scan/scan.h +150 -0
  135. data/vendor/libyeptris/src/yeptris/schema.c +308 -0
  136. data/vendor/libyeptris/src/yeptris/tape.c +1308 -0
  137. data/vendor/libyeptris/src/yeptris/tape_in.h +19 -0
  138. data/vendor/libyeptris/src/yeptris/version.c +7 -0
  139. data/vendor/libyeptris/src/yeptris/visit/dom_visit.c +115 -0
  140. data/vendor/libyeptris/src/yeptris/visit/json_visit.c +293 -0
  141. data/vendor/libyeptris/src/yeptris/visit/yaml_visit.c +127 -0
  142. metadata +199 -0
@@ -0,0 +1,109 @@
1
+ /* json.h — the strict-JSON grammar interface (TODO.impl/08C/21).
2
+ *
3
+ * Kernels are exported (YEPTRIS_API) so host materializers (the Ruby
4
+ * native extension's fused JSON→VALUE path) can call them without
5
+ * pulling the whole static archive. */
6
+ #ifndef YEP_JSON_H
7
+ #define YEP_JSON_H
8
+
9
+ #include <stddef.h>
10
+ #include <yeptris/api.h>
11
+
12
+ #ifdef __cplusplus
13
+ extern "C" {
14
+ #endif
15
+
16
+ YEPTRIS_API int yep_json_ws(const char* p, size_t len, size_t* i, int* saw_tab);
17
+
18
+ /* Token-stream walker over a JSON-class flow span (TODO.restructure/53):
19
+ * the ONE grammar walk, shared by the engine's validator and the DOM's
20
+ * fused builder — validate and build ride the same state machine. */
21
+ #define YEP_JSON_WALK_DEPTH 256
22
+
23
+ typedef enum {
24
+ YEP_JW_OK = 0, /* token delivered in *t */
25
+ YEP_JW_DONE = 1, /* the span's matching close was consumed */
26
+ YEP_JW_REJECT = 2, /* not JSON-class: the general kernel judges */
27
+ } yep_jw_status;
28
+
29
+ typedef struct yep_json_tok {
30
+ size_t at; /* token start (the quote/opener/digit) */
31
+ size_t end; /* token end (past the closing quote for strings) */
32
+ char cls; /* '"' string, '#' number, 'a' literal, '[', '{', ']', '}' */
33
+ int has_escape; /* strings: a backslash escape is present */
34
+ int is_float; /* numbers (cls '#'): the text has '.' or an exponent */
35
+ /* numbers: the ONE conversion (the walker's number arm runs
36
+ * yep_json_number_scan — validate, advance, convert in a single
37
+ * pass; consumers read the values instead of rescanning). nshape:
38
+ * 0 int (ival exact), 1 float text (dval), 2 integer text beyond
39
+ * int64 (dval approximate — the number-kernel contract). */
40
+ int nshape;
41
+ int64_t ival;
42
+ double dval;
43
+ } yep_json_tok;
44
+
45
+ /* Walker states (the reference machine in scan/json.c and the tape's
46
+ * fused specialization share one set — same grammar, same rejects). */
47
+ enum {
48
+ JW_VALUE_OR_CLOSE = 0,
49
+ JW_VALUE,
50
+ JW_KEY_OR_CLOSE,
51
+ JW_KEY,
52
+ JW_COLON,
53
+ JW_COMMA_OR_CLOSE,
54
+ };
55
+
56
+ typedef struct yep_json_walk {
57
+ const char* p;
58
+ size_t len;
59
+ int max_depth; /* the engine's runtime nesting limit */
60
+ size_t i; /* cursor: one past the opener */
61
+ size_t close; /* valid once DONE */
62
+ int long_key; /* a map key over the 1024-char simple-key limit */
63
+ int saw_tab;
64
+ /* strict JSON (RFC 8259): map keys are STRINGS only, including
65
+ * the first entry — the lenient flow class accepts YAML keys
66
+ * (TODO.restructure/81 stage 2: the strict build's walk IS the
67
+ * validator; reject falls to yep_json_document's error path). */
68
+ int strict;
69
+ uint8_t kind[YEP_JSON_WALK_DEPTH]; /* 0 seq, 1 map */
70
+ uint8_t expect[YEP_JSON_WALK_DEPTH]; /* walker states */
71
+ int depth;
72
+ } yep_json_walk;
73
+
74
+ /* Opens over p[open] ('[' or '{'); call _next until DONE/REJECT. */
75
+ void yep_json_walk_init(yep_json_walk* w, const char* p, size_t len, size_t open, int max_depth);
76
+ yep_jw_status yep_json_walk_next(yep_json_walk* w, yep_json_tok* t);
77
+ YEPTRIS_API int yep_json_number(const char* p, size_t len, size_t* i);
78
+ /* The grammar walk fused with conversion (TODO.restructure/26): one
79
+ * scan validates and converts. *is_float reports the TEXT shape:
80
+ * 0 = integer (*iv exact, INT64_MIN included), 1 = float text
81
+ * (*dv converted via the number-kernel SSOT), 2 = integer text
82
+ * beyond int64 (*dv approximate; exact hosts rebuild from the span
83
+ * start..*i). Out params may be NULL. */
84
+ YEPTRIS_API int yep_json_number_scan(const char* p, size_t len, size_t* i, int* is_float,
85
+ int64_t* iv, double* dv);
86
+ /* Same grammar, same rejects, same advance — NO conversion: reports
87
+ * the text shape only (0 int / 1 float). The lazy tape's arm. */
88
+ YEPTRIS_API int yep_json_number_shape(const char* p, size_t len, size_t* i, int* is_float);
89
+ YEPTRIS_API int yep_json_literal(const char* p, size_t len, size_t* i, const char* word);
90
+ YEPTRIS_API int yep_json_string(const char* p, size_t len, size_t* i, size_t* close_out,
91
+ int* has_esc);
92
+ /* Stage 1 of the token-contract tape front: the structural indexer
93
+ * (scalar reference; the kernels table's json_stage1 slot carries the
94
+ * ISA twins). Writes the token positions stage 2 dispatches on —
95
+ * operators, string OPEN quotes, scalar-run starts — and returns 0
96
+ * only for an unterminated string. idx holds len+2 entries. */
97
+ YEPTRIS_API int yep_json_stage1_scalar(const char* p, size_t len, uint32_t* idx, size_t* nidx);
98
+
99
+ /* The per-chunk byte-class classifier behind the flow kernels: the
100
+ * kernels table's json_chunk slot (common/simd_text.h) — yep_chunk_masks
101
+ * is defined there; the differential suite pins the ISAs to it. */
102
+
103
+ YEPTRIS_API int yep_json_document(const char* p, size_t len, size_t* err);
104
+
105
+ #ifdef __cplusplus
106
+ }
107
+ #endif
108
+
109
+ #endif /* YEP_JSON_H */
@@ -0,0 +1,463 @@
1
+ /* scan.c — line facts and span location (TODO.impl/06).
2
+ *
3
+ * Byte classification truth lives in chartype; SIMD kernels accelerate
4
+ * the span scans; this module owns YAML's line/span semantics only.
5
+ */
6
+
7
+ #include <string.h>
8
+
9
+ #include "common/chartype.h"
10
+ #include "common/simd_text.h"
11
+ #include "scan.h"
12
+
13
+ size_t yep_scan_break_len(const char* p, size_t len, size_t pos) {
14
+ if (pos >= len) {
15
+ return 0;
16
+ }
17
+ if (p[pos] == '\n') {
18
+ return 1;
19
+ }
20
+ if (p[pos] == '\r') {
21
+ return (pos + 1 < len && p[pos + 1] == '\n') ? 2 : 1;
22
+ }
23
+ return 0;
24
+ }
25
+
26
+ void yep_scan_advance_line(const char* p, size_t* from, size_t to, uint32_t* line,
27
+ size_t* line_start) {
28
+ for (size_t i = *from; i < to; i++) {
29
+ if (p[i] == '\n') {
30
+ (*line)++;
31
+ *line_start = i + 1;
32
+ }
33
+ }
34
+ *from = to;
35
+ }
36
+
37
+ /* ONE home for the \n/\r break class (scan owns the concept): the
38
+ * engine's multiline walk shares it — it had rebuilt a duplicate per
39
+ * quoted scalar. Prebuilt nibble-class tables (TODO.restructure/68);
40
+ * the StopsetLiterals spec pins them against yep_stopset_init. */
41
+ const yep_stopset yep_break_stopset = {
42
+ .bitmap = {0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
43
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
45
+ .groups = 1,
46
+ .lo = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02,
47
+ 0x00, 0x00}},
48
+ .hi = {{0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49
+ 0x00, 0x00}},
50
+ };
51
+
52
+ void yep_scan_facts(const char* p, size_t len, size_t pos, yep_line_facts* out) {
53
+ yep_text_active()->line_facts(p, len, pos, out);
54
+ }
55
+
56
+ /* Line facts -> line info (the flags/marker derivation, facts-free).
57
+ * One kernel pass feeds BOTH this and the shape classifier via the
58
+ * engine's combined memo (TODO.restructure/76). */
59
+ void yep_scan_line_f(const char* p, size_t len, size_t pos, const yep_line_facts* f,
60
+ yep_line_info* out) {
61
+ yep_line_info li;
62
+ li.offset = (uint32_t)pos;
63
+ li.indent = 0;
64
+ li.flags = 0;
65
+ li.first = 0;
66
+ li.end = f->end;
67
+ size_t j = f->indent;
68
+ li.indent = (uint16_t)(j - pos);
69
+ if (j < li.end && p[j] == '\t') {
70
+ size_t k = j;
71
+ while (k < li.end && (p[k] == ' ' || p[k] == '\t')) {
72
+ k++;
73
+ }
74
+ if (k >= li.end) {
75
+ li.flags |= YEP_LF_BLANK;
76
+ if (li.indent == 0) {
77
+ li.flags |= YEP_LF_TAB;
78
+ }
79
+ *out = li;
80
+ return;
81
+ }
82
+ li.flags |= YEP_LF_TAB;
83
+ }
84
+
85
+ if (j >= li.end) {
86
+ li.flags |= YEP_LF_BLANK;
87
+ *out = li;
88
+ return;
89
+ }
90
+
91
+ li.first = (unsigned char)p[j];
92
+ if (li.first == '#') {
93
+ li.flags |= YEP_LF_COMMENT;
94
+ *out = li;
95
+ return;
96
+ }
97
+ if (li.first == '%' && li.indent == 0) {
98
+ li.flags |= YEP_LF_DIRECTIVE;
99
+ *out = li;
100
+ return;
101
+ }
102
+
103
+ /* "---" / "..." at column 0, followed by EOL/space/tab/comment —
104
+ * content may follow on the same line ("--- > folded"). */
105
+ if (li.indent == 0 && li.end - j >= 3 && memcmp(p + j, "---", 3) == 0 &&
106
+ (li.end - j == 3 || p[j + 3] == ' ' || p[j + 3] == '\t')) {
107
+ li.flags |= YEP_LF_DOC_START;
108
+ } else if (li.indent == 0 && li.end - j >= 3 && memcmp(p + j, "...", 3) == 0 &&
109
+ (li.end - j == 3 || p[j + 3] == ' ' || p[j + 3] == '\t')) {
110
+ li.flags |= YEP_LF_DOC_END;
111
+ }
112
+ *out = li;
113
+ }
114
+
115
+ yep_line_info yep_scan_line(const char* p, size_t len, size_t pos) {
116
+ yep_line_info li;
117
+ yep_line_facts f;
118
+ yep_scan_facts(p, len, pos, &f);
119
+ yep_scan_line_f(p, len, pos, &f, &li);
120
+ return li;
121
+ }
122
+
123
+ /* Terminator check for ':' — blank, EOL, or (in flow) a flow indicator. */
124
+ static int yep_colon_terminates(const char* p, size_t len, size_t colon, int flow) {
125
+ size_t next = colon + 1;
126
+ if (next >= len) {
127
+ return 1; /* ':' at EOF terminates */
128
+ }
129
+ unsigned char c = (unsigned char)p[next];
130
+ if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
131
+ return 1;
132
+ }
133
+ if (flow && yep_ct_is(c, YEP_CT_FLOW_IND)) {
134
+ return 1;
135
+ }
136
+ return 0;
137
+ }
138
+
139
+ int yep_plain_first_ok(unsigned char c) {
140
+ return !(c == ',' || c == ']' || c == '}' || c == '%' || c == '@' || c == '`');
141
+ }
142
+
143
+ int yep_scan_prop_char(unsigned char c) {
144
+ return !yep_ct_any(c, YEP_CT_BLANK | YEP_CT_LBREAK | YEP_CT_FLOW_IND) && c != ',' && c != '#';
145
+ }
146
+
147
+ size_t yep_scan_prop_end(const char* p, size_t len, size_t pos) {
148
+ while (pos < len && yep_scan_prop_char((unsigned char)p[pos])) {
149
+ pos++;
150
+ }
151
+ return pos;
152
+ }
153
+
154
+ /* ---- line-shape classification (TODO.restructure/49) ---- */
155
+
156
+ /* blank/EOL/EOF directly after p[at] (the dash / explicit-key rule). */
157
+ static int shape_blank_next(const char* p, size_t len, size_t at) {
158
+ return at + 1 >= len || p[at + 1] == ' ' || p[at + 1] == '\t' || p[at + 1] == '\n' ||
159
+ p[at + 1] == '\r';
160
+ }
161
+
162
+ /* Value bytes the fast arms do not own: quoted/tagged/block/flow
163
+ * scalars and the compact-syntax leads whose semantics belong to the
164
+ * general chain. */
165
+ static int shape_val_bail(unsigned char c, const char* p, size_t len, size_t at) {
166
+ switch (c) {
167
+ case '"':
168
+ case '\'':
169
+ case '!':
170
+ case '|':
171
+ case '>':
172
+ case '[':
173
+ case '{':
174
+ case '*': /* an alias after an anchor is an error shape (SR86) */
175
+ return 1;
176
+ case '-':
177
+ case '?':
178
+ return shape_blank_next(p, len, at);
179
+ default:
180
+ return 0;
181
+ }
182
+ }
183
+
184
+ static void shape_value(const char* p, size_t len, const yep_line_info* li, size_t vt,
185
+ yep_line_shape* s) {
186
+ s->val_start = (uint32_t)vt;
187
+ if (vt >= li->end || p[vt] == '#') { /* '#' here follows a blank by construction */
188
+ s->val = YEP_LVAL_EMPTY;
189
+ return;
190
+ }
191
+ unsigned char c = (unsigned char)p[vt];
192
+ if (c == '*') {
193
+ s->val = YEP_LVAL_ALIAS; /* the engine's alias walk owns name semantics */
194
+ return;
195
+ }
196
+ if (c == '[' || c == '{') {
197
+ s->val = YEP_LVAL_FLOW;
198
+ return;
199
+ }
200
+ if (c == '&') {
201
+ size_t a_end = yep_scan_prop_end(p, len, vt + 1);
202
+ size_t t = a_end;
203
+ while (t < len && (p[t] == ' ' || p[t] == '\t')) {
204
+ t++;
205
+ }
206
+ if (t < li->end && p[t] != '#' && !shape_val_bail((unsigned char)p[t], p, len, t) &&
207
+ yep_plain_first_ok((unsigned char)p[t])) {
208
+ yep_span v = yep_scan_plain(p, len, t, 0);
209
+ if (v.term != YEP_TERM_COLON && v.end > v.start) {
210
+ s->val = YEP_LVAL_ANCHOR_PLAIN;
211
+ s->anchor_end = (uint32_t)a_end;
212
+ s->val_span = v;
213
+ return;
214
+ }
215
+ }
216
+ return; /* anchor with a following-lines value / odd content: bail */
217
+ }
218
+ if (shape_val_bail(c, p, len, vt) || !yep_plain_first_ok(c)) {
219
+ return;
220
+ }
221
+ yep_span v = yep_scan_plain(p, len, vt, 0);
222
+ if (v.term == YEP_TERM_COLON) {
223
+ return; /* a second terminating ':' is compact/error territory */
224
+ }
225
+ s->val = YEP_LVAL_PLAIN;
226
+ s->val_span = v;
227
+ }
228
+
229
+ /* The key span straight from the fused facts (TODO.restructure/76):
230
+ * the common line's key scan becomes zero byte-walking. Rare shapes
231
+ * (interior ':', embedded '#') fall back to the walking scan — the
232
+ * two must agree, and the LineShape spec pins them together. */
233
+ static yep_span shape_key_span(const char* p, size_t len, size_t t, const yep_line_facts* f) {
234
+ yep_span k;
235
+ k.start = (uint32_t)t;
236
+ k.term = YEP_TERM_EOF;
237
+ if (f->stop_set && f->stop >= t) {
238
+ unsigned char c = (unsigned char)p[f->stop];
239
+ if (c == ':') {
240
+ if (yep_colon_terminates(p, len, f->stop, 0)) {
241
+ k.term = YEP_TERM_COLON;
242
+ k.end = f->stop;
243
+ while (k.end > k.start && (p[k.end - 1] == ' ' || p[k.end - 1] == '\t')) {
244
+ k.end--;
245
+ }
246
+ return k;
247
+ }
248
+ } else if (c == '#' && (f->stop == t || p[f->stop - 1] == ' ' || p[f->stop - 1] == '\t')) {
249
+ k.term = YEP_TERM_COMMENT;
250
+ k.end = f->stop;
251
+ while (k.end > k.start && (p[k.end - 1] == ' ' || p[k.end - 1] == '\t')) {
252
+ k.end--;
253
+ }
254
+ return k;
255
+ }
256
+ return yep_scan_plain(p, len, t, 0); /* non-terminating stop: the walk owns it */
257
+ }
258
+ /* no stop byte before EOL: the span runs to the line end */
259
+ k.end = f->end;
260
+ while (k.end > k.start && (p[k.end - 1] == ' ' || p[k.end - 1] == '\t')) {
261
+ k.end--;
262
+ }
263
+ k.term = f->end < len ? YEP_TERM_EOL : YEP_TERM_EOF;
264
+ return k;
265
+ }
266
+
267
+ void yep_scan_shape_f(const char* p, size_t len, const yep_line_info* li, const yep_line_facts* f,
268
+ yep_line_shape* s) {
269
+ memset(s, 0, sizeof(*s));
270
+ s->kind = YEP_LSHAPE_NONE;
271
+ s->val = YEP_LVAL_NONE;
272
+ if (li->flags != 0) {
273
+ return; /* blank/comment/doc/directive/tab lines: general paths */
274
+ }
275
+ size_t t = li->offset + li->indent;
276
+ unsigned char c = (unsigned char)p[t];
277
+
278
+ if (c == '-' && shape_blank_next(p, len, t)) {
279
+ size_t vt = t + 1;
280
+ while (vt < len && (p[vt] == ' ' || p[vt] == '\t')) {
281
+ vt++;
282
+ }
283
+ s->kind = YEP_LSHAPE_DASH;
284
+ s->dash = (uint32_t)t;
285
+ shape_value(p, len, li, vt, s);
286
+ return;
287
+ }
288
+
289
+ /* '?' / ':' followed by a blank are the explicit-key and bare-colon
290
+ * lines (the general paths own them); followed by content they are
291
+ * ordinary plain-first bytes. A dash + blank returned as DASH above. */
292
+ if (yep_plain_first_ok(c) && c != '&' && c != '!' && c != '*' && c != '\'' && c != '"' &&
293
+ c != '[' && c != '{' && !((c == '?' || c == ':') && shape_blank_next(p, len, t))) {
294
+ yep_span k = shape_key_span(p, len, t, f);
295
+ if (k.term == YEP_TERM_COLON) {
296
+ /* k.end is the TRIMMED span end: the ':' sits past the
297
+ * trimmed blanks (or past interior stops on the fallback
298
+ * path) — the forward walk is over spaces, a few bytes */
299
+ size_t colon = k.end;
300
+ while (p[colon] != ':') {
301
+ colon++;
302
+ }
303
+ size_t vt = colon + 1;
304
+ while (vt < len && (p[vt] == ' ' || p[vt] == '\t')) {
305
+ vt++;
306
+ }
307
+ s->kind = YEP_LSHAPE_KEY;
308
+ s->key_start = k.start;
309
+ s->key_end = k.end;
310
+ s->colon = (uint32_t)colon;
311
+ shape_value(p, len, li, vt, s);
312
+ }
313
+ }
314
+ }
315
+
316
+ void yep_scan_shape(const char* p, size_t len, const yep_line_info* li, yep_line_shape* s) {
317
+ yep_line_facts f;
318
+ yep_scan_facts(p, len, li->offset, &f);
319
+ yep_scan_shape_f(p, len, li, &f, s);
320
+ }
321
+
322
+ /* The two plain-scalar stop classes are constants — they were rebuilt
323
+ on EVERY scan (~2 per line; clear + 4-9 adds ≈ 3M ops on a 100k-line
324
+ document), then became static bitmaps, now prebuilt nibble-class
325
+ tables (TODO.restructure/68). Generated: set[c>>3] |= 1 << (c&7) for
326
+ the stop chars below; lo/hi pinned by the StopsetLiterals spec. */
327
+ const yep_stopset yep_plain_stop_block = {
328
+ .bitmap = {0x00, 0x24, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
329
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
331
+ /* members: \n \r # : */
332
+ .groups = 1,
333
+ .lo = {{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x02,
334
+ 0x00, 0x00}},
335
+ .hi = {{0x03, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
336
+ 0x00, 0x00}},
337
+ };
338
+
339
+ const yep_stopset yep_plain_stop_flow = {
340
+ .bitmap = {0x00, 0x24, 0x00, 0x00, 0x08, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00,
341
+ 0x28, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
343
+ /* members: \n \r # , : [ ] { } */
344
+ .groups = 2,
345
+ .lo = {{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x08, 0x42,
346
+ 0x00, 0x00},
347
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
348
+ 0x00, 0x00}},
349
+ .hi = {{0x03, 0x00, 0x0C, 0x10, 0x00, 0x60, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350
+ 0x00, 0x00},
351
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
352
+ 0x00, 0x00}},
353
+ };
354
+
355
+ yep_span yep_scan_plain(const char* p, size_t len, size_t pos, int flow) {
356
+ const yep_text_kernels* k = yep_text_active();
357
+ const yep_stopset* stop = flow ? &yep_plain_stop_flow : &yep_plain_stop_block;
358
+ /* Short spans keep the scalar walk: the kernel dispatch costs more
359
+ * than it saves below a vector (block keys run 2-8 bytes — the
360
+ * same gate scan_line uses for its end-find). */
361
+ const int tiny = (len - pos) < 64;
362
+
363
+ yep_span s;
364
+ s.start = (uint32_t)pos;
365
+ s.end = (uint32_t)pos;
366
+ s.term = YEP_TERM_EOF;
367
+
368
+ size_t i = pos;
369
+ while (i < len) {
370
+ ptrdiff_t hit;
371
+ if (tiny) {
372
+ size_t at = i;
373
+ while (at < len && !yep_stopset_test(stop->bitmap, (unsigned char)p[at])) {
374
+ at++;
375
+ }
376
+ hit = (at < len) ? (ptrdiff_t)(at - i) : -1;
377
+ } else {
378
+ hit = k->stopset_find(stop, p + i, len - i);
379
+ }
380
+ size_t at = (hit < 0) ? len : i + (size_t)hit;
381
+ unsigned char c = (at < len) ? (unsigned char)p[at] : 0;
382
+
383
+ if (at == len) {
384
+ i = len;
385
+ s.term = YEP_TERM_EOF;
386
+ break;
387
+ }
388
+ if (c == '\n' || c == '\r') {
389
+ i = at;
390
+ s.term = YEP_TERM_EOL;
391
+ break;
392
+ }
393
+ if (c == ':') {
394
+ if (yep_colon_terminates(p, len, at, flow)) {
395
+ i = at;
396
+ s.term = YEP_TERM_COLON;
397
+ break;
398
+ }
399
+ i = at + 1;
400
+ continue;
401
+ }
402
+ if (c == '#') {
403
+ /* '#' starts a comment after a blank or at span start */
404
+ if (at == s.start || (at > s.start && (p[at - 1] == ' ' || p[at - 1] == '\t'))) {
405
+ i = at;
406
+ s.term = YEP_TERM_COMMENT;
407
+ break;
408
+ }
409
+ i = at + 1;
410
+ continue;
411
+ }
412
+ /* flow indicator (flow context only) */
413
+ i = at;
414
+ s.term = YEP_TERM_FLOW;
415
+ break;
416
+ }
417
+
418
+ /* Trim trailing spaces/tabs from the span. */
419
+ size_t e = i;
420
+ while (e > s.start && (p[e - 1] == ' ' || p[e - 1] == '\t')) {
421
+ e--;
422
+ }
423
+ s.end = (uint32_t)e;
424
+ if (e == s.start && s.term == YEP_TERM_EOF) {
425
+ s.term = YEP_TERM_EOF;
426
+ }
427
+ return s;
428
+ }
429
+
430
+ yep_span yep_scan_quoted(const char* p, size_t len, size_t pos, int* has_escape) {
431
+ const yep_text_kernels* k = yep_text_active();
432
+ unsigned char q = (unsigned char)p[pos];
433
+ int esc = 0;
434
+ ptrdiff_t r = k->quote_scan(p + pos + 1, len - pos - 1, (char)q, &esc);
435
+ if (has_escape != NULL) {
436
+ *has_escape = esc;
437
+ }
438
+ yep_span s;
439
+ s.start = (uint32_t)(pos + 1);
440
+ if (r < 0) {
441
+ s.end = (uint32_t)len;
442
+ s.term = YEP_TERM_EOL; /* unterminated — caller reports the error */
443
+ } else {
444
+ s.end = (uint32_t)(pos + 1 + (size_t)r);
445
+ s.term = YEP_TERM_EOF;
446
+ }
447
+ return s;
448
+ }
449
+
450
+ int yep_scan_is_key_start(unsigned char c) {
451
+ /* Quotes and flow openers always start a potential key; plain-first
452
+ * excludes most indicators. */
453
+ if (c == '\'' || c == '"' || c == '[' || c == '{' || c == '?') {
454
+ return 1;
455
+ }
456
+ if (c == '&' || c == '!' || c == '*') {
457
+ return 1; /* properties or an alias may open a key node */
458
+ }
459
+ if (yep_ct_is(c, YEP_CT_INDICATOR)) {
460
+ return 0; /* the remaining indicators cannot start a plain scalar */
461
+ }
462
+ return yep_ct_is_ns(c);
463
+ }