yeptris 0.6.60.1-arm-linux-eabihf → 0.6.61.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.
- checksums.yaml +4 -4
- data/ext/yeptris_native/version.h +2 -2
- data/lib/yeptris/yaml.rb +10 -0
- data/lib/yeptris.rb +1 -1
- data/libyeptris.so +0 -0
- data/vendor/libyeptris/CMakeLists.txt +1 -1
- data/vendor/libyeptris/src/include/yeptris/parse.h +21 -0
- data/vendor/libyeptris/src/yeptris/dom/dom.c +12 -1
- data/vendor/libyeptris/src/yeptris/dom/ytape.c +56 -7
- data/vendor/libyeptris/src/yeptris/emit/emit.c +8 -0
- data/vendor/libyeptris/src/yeptris/emit/writer.c +85 -10
- data/vendor/libyeptris/src/yeptris/emit/writer.h +10 -7
- data/vendor/libyeptris/src/yeptris/events/values.c +22 -0
- data/vendor/libyeptris/src/yeptris/parse/engine.c +490 -90
- data/vendor/libyeptris/src/yeptris/parse/engine.h +5 -0
- data/vendor/libyeptris/src/yeptris/parse/stream_iter.c +33 -1
- data/vendor/libyeptris/src/yeptris/parse.c +43 -1
- data/vendor/libyeptris/src/yeptris/resolve/compat11.c +2 -5
- data/vendor/libyeptris/src/yeptris/resolve/resolver.h +18 -0
- data/vendor/libyeptris/src/yeptris/resolve/tags.c +192 -0
- data/vendor/libyeptris/src/yeptris/scan/scan.c +22 -7
- data/vendor/libyeptris/src/yeptris/tape.c +24 -5
- metadata +1 -1
|
@@ -53,6 +53,14 @@ typedef struct {
|
|
|
53
53
|
uint8_t kind;
|
|
54
54
|
} yep_frame;
|
|
55
55
|
|
|
56
|
+
/* One repeat-alias memo slot: the name is an input-relative span
|
|
57
|
+
* (alias names are always raw input views), so at+len re-derive it. */
|
|
58
|
+
typedef struct e_alias_slot {
|
|
59
|
+
uint32_t at; /* offset of the name inside e->p */
|
|
60
|
+
uint32_t len; /* 0 = slot empty */
|
|
61
|
+
uint32_t ord; /* the ordinal the nametab answered */
|
|
62
|
+
} e_alias_slot;
|
|
63
|
+
|
|
56
64
|
struct yep_engine {
|
|
57
65
|
const yep_allocator* sys;
|
|
58
66
|
yep_pool* pool; /* finish pool: folded/escaped scalar content */
|
|
@@ -89,10 +97,13 @@ struct yep_engine {
|
|
|
89
97
|
* 38541356075) */
|
|
90
98
|
uint32_t anchor_placed_cap;
|
|
91
99
|
/* repeat-alias memo (TODO.restructure/71): offset/len/ordinal of
|
|
92
|
-
* the last alias resolved — hit
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
100
|
+
* the last alias resolved — a hit answers by an input-span word
|
|
101
|
+
* compare (yep_view_eq; no libc call), not by the table.
|
|
102
|
+
* anchor_define drops the slot when the name being (re)defined is
|
|
103
|
+
* the memo's: the table's last-definition-wins overwrite would
|
|
104
|
+
* otherwise leave the memo serving a STALE ordinal (and skip the
|
|
105
|
+
* new ordinal's unplaced check). */
|
|
106
|
+
e_alias_slot alias_memo;
|
|
96
107
|
/* the line-facts memo (TODO.restructure/76): one kernel pass per
|
|
97
108
|
* line feeds both the line info and the shape */
|
|
98
109
|
yep_line_facts facts_cache;
|
|
@@ -149,6 +160,7 @@ struct yep_engine {
|
|
|
149
160
|
uint32_t ev_buf_n, ev_buf_cap;
|
|
150
161
|
uint32_t ev_scopes; /* active entry-buffer scopes */
|
|
151
162
|
char* norm_buf;
|
|
163
|
+
size_t norm_buf_len; /* norm_buf's byte length (NULL when no copy) */
|
|
152
164
|
unsigned char* enc_buf;
|
|
153
165
|
/* owned UTF-16/32 transcode scratch (run-owned) */ /* owned input copy with exotic breaks
|
|
154
166
|
normalized */
|
|
@@ -425,17 +437,17 @@ static uint32_t anchor_id_of(yep_engine* e, yep_view name) {
|
|
|
425
437
|
* the same alias thousands of times in a row; the memo answers
|
|
426
438
|
* those with one input compare, skipping the hash + a likely
|
|
427
439
|
* cache-missing probe into the (multi-MB, reserved) slots table. */
|
|
428
|
-
if (e->
|
|
429
|
-
|
|
430
|
-
return e->
|
|
440
|
+
if (e->alias_memo.len == name.len && name.len != 0 &&
|
|
441
|
+
yep_view_eq((yep_view){e->p + e->alias_memo.at, name.len}, name)) {
|
|
442
|
+
return e->alias_memo.ord;
|
|
431
443
|
}
|
|
432
444
|
uint32_t id = yep_nametab_get(&e->anchors, name);
|
|
433
445
|
if (id == YEP_NAMETAB_NIL) {
|
|
434
446
|
return 0;
|
|
435
447
|
}
|
|
436
|
-
e->
|
|
437
|
-
e->
|
|
438
|
-
e->
|
|
448
|
+
e->alias_memo.at = (uint32_t)(name.p - e->p);
|
|
449
|
+
e->alias_memo.len = name.len;
|
|
450
|
+
e->alias_memo.ord = id;
|
|
439
451
|
return id;
|
|
440
452
|
}
|
|
441
453
|
|
|
@@ -447,30 +459,48 @@ static void e_anchor_mark(yep_engine* e, uint32_t id) {
|
|
|
447
459
|
}
|
|
448
460
|
}
|
|
449
461
|
|
|
462
|
+
/* Grows the per-ordinal placed flags so flags[id-1] is writable.
|
|
463
|
+
* Returns 0 only on allocation failure (table unchanged). */
|
|
464
|
+
static int anchor_placed_fit(yep_engine* e, uint32_t id) {
|
|
465
|
+
if (id <= e->anchor_placed_cap) {
|
|
466
|
+
return 1;
|
|
467
|
+
}
|
|
468
|
+
uint32_t cap = e->anchor_placed_cap ? e->anchor_placed_cap : 64;
|
|
469
|
+
while (cap < id) {
|
|
470
|
+
cap *= 2;
|
|
471
|
+
}
|
|
472
|
+
uint8_t* nb = yep_alloc(e->sys, cap);
|
|
473
|
+
if (nb == NULL) {
|
|
474
|
+
return 0;
|
|
475
|
+
}
|
|
476
|
+
if (e->anchor_placed != NULL) {
|
|
477
|
+
memcpy(nb, e->anchor_placed, e->anchor_placed_cap);
|
|
478
|
+
yep_free(e->sys, e->anchor_placed);
|
|
479
|
+
}
|
|
480
|
+
memset(nb + e->anchor_placed_cap, 0, cap - e->anchor_placed_cap);
|
|
481
|
+
e->anchor_placed = nb;
|
|
482
|
+
e->anchor_placed_cap = cap;
|
|
483
|
+
return 1;
|
|
484
|
+
}
|
|
485
|
+
|
|
450
486
|
static uint32_t anchor_define(yep_engine* e, yep_view name) {
|
|
451
487
|
/* Last definition wins (libyaml parity); OOM leaves the anchor
|
|
452
488
|
* undefined so its alias errors. The VALUE is the anchor's 1-based
|
|
453
489
|
* ordinal — sinks key on it and skip the name hash entirely. */
|
|
454
490
|
uint32_t id = ++e->anchor_serial;
|
|
455
|
-
if (id
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
cap *= 2;
|
|
459
|
-
}
|
|
460
|
-
uint8_t* nb = yep_alloc(e->sys, cap);
|
|
461
|
-
if (nb == NULL) {
|
|
462
|
-
e->anchor_serial--;
|
|
463
|
-
return 0; /* OOM: the anchor stays undefined, its alias errors */
|
|
464
|
-
}
|
|
465
|
-
if (e->anchor_placed != NULL) {
|
|
466
|
-
memcpy(nb, e->anchor_placed, e->anchor_placed_cap);
|
|
467
|
-
yep_free(e->sys, e->anchor_placed);
|
|
468
|
-
}
|
|
469
|
-
memset(nb + e->anchor_placed_cap, 0, cap - e->anchor_placed_cap);
|
|
470
|
-
e->anchor_placed = nb;
|
|
471
|
-
e->anchor_placed_cap = cap;
|
|
491
|
+
if (!anchor_placed_fit(e, id)) {
|
|
492
|
+
e->anchor_serial--;
|
|
493
|
+
return 0; /* OOM: the anchor stays undefined, its alias errors */
|
|
472
494
|
}
|
|
473
495
|
yep_nametab_set(&e->anchors, name, id);
|
|
496
|
+
/* A (re)definition changes the ordinal the table answers for THIS
|
|
497
|
+
* name: a memo still naming it would serve the OLD ordinal
|
|
498
|
+
* (violating last-definition-wins) and skip the new ordinal's
|
|
499
|
+
* unplaced check. */
|
|
500
|
+
if (e->alias_memo.len == name.len && name.len != 0 &&
|
|
501
|
+
yep_view_eq((yep_view){e->p + e->alias_memo.at, name.len}, name)) {
|
|
502
|
+
e->alias_memo.len = 0;
|
|
503
|
+
}
|
|
474
504
|
return id;
|
|
475
505
|
}
|
|
476
506
|
|
|
@@ -1341,9 +1371,12 @@ static yep_view e_resolve_tag(yep_engine* e, yep_view tag) {
|
|
|
1341
1371
|
/* Parses &anchor / !tag runs at the cursor into *anchor / *tag. A node
|
|
1342
1372
|
* carries at most one of each (c-ns-properties): a second property of
|
|
1343
1373
|
* the same kind is the suite's 4JVG error. Keeping the last one let a
|
|
1344
|
-
* mutated anchor run read differently from libyaml (catch 156).
|
|
1345
|
-
|
|
1346
|
-
|
|
1374
|
+
* mutated anchor run read differently from libyaml (catch 156).
|
|
1375
|
+
* *have_anchor / *have_tag carry that across CALLS — the flow node
|
|
1376
|
+
* parse re-runs the scan when a property rides the next line, and the
|
|
1377
|
+
* duplicate law must hold across the gap. */
|
|
1378
|
+
static void e_props_ex(yep_engine* e, yep_view* anchor, yep_view* tag, int* have_anchor,
|
|
1379
|
+
int* have_tag) {
|
|
1347
1380
|
for (;;) {
|
|
1348
1381
|
e_skip_inline_space(e);
|
|
1349
1382
|
if (e->pos >= e->len) {
|
|
@@ -1351,11 +1384,11 @@ static void e_props(yep_engine* e, yep_view* anchor, yep_view* tag) {
|
|
|
1351
1384
|
}
|
|
1352
1385
|
unsigned char c = (unsigned char)e->p[e->pos];
|
|
1353
1386
|
if (c == '&') {
|
|
1354
|
-
if (have_anchor) {
|
|
1387
|
+
if (*have_anchor) {
|
|
1355
1388
|
e_fail(e, YEP_ERR_UNEXPECTED, e->pos);
|
|
1356
1389
|
return;
|
|
1357
1390
|
}
|
|
1358
|
-
have_anchor = 1;
|
|
1391
|
+
*have_anchor = 1;
|
|
1359
1392
|
size_t start = e->pos + 1;
|
|
1360
1393
|
e->pos = yep_scan_prop_end(e->p, e->len, start);
|
|
1361
1394
|
anchor->p = e->p + start;
|
|
@@ -1380,7 +1413,24 @@ static void e_props(yep_engine* e, yep_view* anchor, yep_view* tag) {
|
|
|
1380
1413
|
* keep it (libyaml rejects those: "&a: key: v", W5VH's
|
|
1381
1414
|
* value position — suite-VALID, ledgered). The colon
|
|
1382
1415
|
* re-lexes as the key indicator and the existing colon
|
|
1383
|
-
* arm builds the anchored null key.
|
|
1416
|
+
* arm builds the anchored null key.
|
|
1417
|
+
*
|
|
1418
|
+
* The r228 nightly (run 42645063770, crash-8100227a)
|
|
1419
|
+
* caught the PROPS-LED follower: "&k2: ! {\n}" — the run
|
|
1420
|
+
* between the separator and the collection is the VALUE's
|
|
1421
|
+
* own properties, so libyaml still reads the anchored null
|
|
1422
|
+
* key (tag "<!>" on the flow map); yeptris instead rode
|
|
1423
|
+
* the colon into the name and stamped "k2:" + tag on the
|
|
1424
|
+
* map itself, and the anchor-led twin "&k2: &v {...}"
|
|
1425
|
+
* outright REJECTED (duplicate anchor) where libyaml
|
|
1426
|
+
* accepts. The follower scan now crosses ONE props run
|
|
1427
|
+
* ("!tag" / "&anch", verbatim "!<!..>" included —
|
|
1428
|
+
* scan_prop_end ends at a blank/break like the name scan)
|
|
1429
|
+
* before the indicator check, and a crossed run
|
|
1430
|
+
* un-consumes regardless of what follows: the tag/plain
|
|
1431
|
+
* member "&k2: ! t" reads the same pair in libyaml. The
|
|
1432
|
+
* plain-led twins (no props run — "&a: key", W5VH) never
|
|
1433
|
+
* cross one and keep riding. */
|
|
1384
1434
|
if (e->p[e->pos - 1] == ':') {
|
|
1385
1435
|
/* the follower scan crosses blanks, breaks AND
|
|
1386
1436
|
* comments: the pair separator at line end still opens
|
|
@@ -1393,6 +1443,7 @@ static void e_props(yep_engine* e, yep_view* anchor, yep_view* tag) {
|
|
|
1393
1443
|
* blank-equivalent here: skip it to its break and keep
|
|
1394
1444
|
* scanning. */
|
|
1395
1445
|
size_t t = e->pos;
|
|
1446
|
+
int rode_props = 0;
|
|
1396
1447
|
for (;;) {
|
|
1397
1448
|
while (t < e->len && (e->p[t] == ' ' || e->p[t] == '\t' || e->p[t] == '\n' ||
|
|
1398
1449
|
e->p[t] == '\r')) {
|
|
@@ -1404,12 +1455,28 @@ static void e_props(yep_engine* e, yep_view* anchor, yep_view* tag) {
|
|
|
1404
1455
|
}
|
|
1405
1456
|
continue;
|
|
1406
1457
|
}
|
|
1458
|
+
/* the r228 props-led law: one props run between
|
|
1459
|
+
* the separator and the follower belongs to the
|
|
1460
|
+
* VALUE node — a second keeps the first's verdict
|
|
1461
|
+
* ("&k2: !t &a {" still un-consumes on the "!") */
|
|
1462
|
+
if (!rode_props && t < e->len && (e->p[t] == '!' || e->p[t] == '&')) {
|
|
1463
|
+
t = yep_scan_prop_end(e->p, e->len, t + 1);
|
|
1464
|
+
rode_props = 1;
|
|
1465
|
+
continue;
|
|
1466
|
+
}
|
|
1407
1467
|
break;
|
|
1408
1468
|
}
|
|
1409
1469
|
if (t < e->len &&
|
|
1410
1470
|
(e->p[t] == '[' || e->p[t] == '{' || e->p[t] == '|' || e->p[t] == '>')) {
|
|
1411
1471
|
anchor->len -= 1;
|
|
1412
1472
|
e->pos -= 1;
|
|
1473
|
+
} else if (rode_props) {
|
|
1474
|
+
/* a crossed props run is the value's own: libyaml
|
|
1475
|
+
* reads the pair whatever follows the run — the
|
|
1476
|
+
* tag-led plain ("&k2: ! t") and the bare-tag/EOF
|
|
1477
|
+
* tail ("&k2: !") included */
|
|
1478
|
+
anchor->len -= 1;
|
|
1479
|
+
e->pos -= 1;
|
|
1413
1480
|
}
|
|
1414
1481
|
}
|
|
1415
1482
|
if (e->pos < e->len && e->p[e->pos] == '#') {
|
|
@@ -1424,11 +1491,11 @@ static void e_props(yep_engine* e, yep_view* anchor, yep_view* tag) {
|
|
|
1424
1491
|
return;
|
|
1425
1492
|
}
|
|
1426
1493
|
} else if (c == '!') {
|
|
1427
|
-
if (have_tag) {
|
|
1494
|
+
if (*have_tag) {
|
|
1428
1495
|
e_fail(e, YEP_ERR_UNEXPECTED, e->pos);
|
|
1429
1496
|
return;
|
|
1430
1497
|
}
|
|
1431
|
-
have_tag = 1;
|
|
1498
|
+
*have_tag = 1;
|
|
1432
1499
|
size_t start = e->pos;
|
|
1433
1500
|
e->pos++;
|
|
1434
1501
|
if (e->pos < e->len && e->p[e->pos] == '<') {
|
|
@@ -1476,6 +1543,13 @@ static void e_props(yep_engine* e, yep_view* anchor, yep_view* tag) {
|
|
|
1476
1543
|
}
|
|
1477
1544
|
}
|
|
1478
1545
|
|
|
1546
|
+
/* The one-call form: fresh duplicate state (the block node parse
|
|
1547
|
+
* consumes the whole run in a single scan). */
|
|
1548
|
+
static void e_props(yep_engine* e, yep_view* anchor, yep_view* tag) {
|
|
1549
|
+
int have_anchor = 0, have_tag = 0;
|
|
1550
|
+
e_props_ex(e, anchor, tag, &have_anchor, &have_tag);
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1479
1553
|
/* ------------------------------------------------------------- aliases */
|
|
1480
1554
|
|
|
1481
1555
|
static int e_alias(yep_engine* e, yep_event* ev) {
|
|
@@ -1737,7 +1811,8 @@ static int e_flow_node(yep_engine* e, yep_event* ev, int keyish) {
|
|
|
1737
1811
|
ev->line = e->line;
|
|
1738
1812
|
ev->col = e_col(e, e->pos) + 1;
|
|
1739
1813
|
yep_view anchor = {0}, tag = {0};
|
|
1740
|
-
|
|
1814
|
+
int have_anchor = 0, have_tag = 0;
|
|
1815
|
+
e_props_ex(e, &anchor, &tag, &have_anchor, &have_tag);
|
|
1741
1816
|
if (e->err.code != YEP_ERR_NONE) {
|
|
1742
1817
|
return -1; /* e_props failed (empty anchor name, unresolved tag) */
|
|
1743
1818
|
}
|
|
@@ -1764,6 +1839,38 @@ static int e_flow_node(yep_engine* e, yep_event* ev, int keyish) {
|
|
|
1764
1839
|
return e_fail(e, YEP_ERR_UNEXPECTED, e->pos);
|
|
1765
1840
|
}
|
|
1766
1841
|
c = (unsigned char)e->p[e->pos];
|
|
1842
|
+
/* Properties may span line breaks in flow (libyaml scans the
|
|
1843
|
+
* anchor/tag run across breaks: "&a\n!!t v" carries the tag with
|
|
1844
|
+
* value v; "!t\n&a x" carries the anchor). The run above skips
|
|
1845
|
+
* INLINE space only, so the cursor stopped at the break and the
|
|
1846
|
+
* property byte led the plain branch instead — a plain scalar
|
|
1847
|
+
* glued from tag/anchor bytes (the nightly's round 211,
|
|
1848
|
+
* crash-925daa54, "&anchor\n !!312 3123]"). Re-lex the riding
|
|
1849
|
+
* run with the have_* state threaded so a second property of one
|
|
1850
|
+
* kind still errors (the 4JVG law). Each iteration consumes at
|
|
1851
|
+
* least one byte or fails, so the loop is bounded. */
|
|
1852
|
+
while (c == '&' || c == '!') {
|
|
1853
|
+
e_props_ex(e, &anchor, &tag, &have_anchor, &have_tag);
|
|
1854
|
+
if (e->err.code != YEP_ERR_NONE) {
|
|
1855
|
+
return -1;
|
|
1856
|
+
}
|
|
1857
|
+
if (!yep_view_is_empty(anchor) && (memchr(anchor.p, '"', anchor.len) != NULL ||
|
|
1858
|
+
memchr(anchor.p, '\'', anchor.len) != NULL)) {
|
|
1859
|
+
return (int)e_fail(e, YEP_ERR_UNEXPECTED, e->pos);
|
|
1860
|
+
}
|
|
1861
|
+
ev->anchor = anchor;
|
|
1862
|
+
ev->tag = tag;
|
|
1863
|
+
if (!yep_view_is_empty(anchor)) {
|
|
1864
|
+
ev->anchor_id = anchor_define(e, anchor);
|
|
1865
|
+
}
|
|
1866
|
+
if (e_flow_ws(e) != 0) {
|
|
1867
|
+
return -1;
|
|
1868
|
+
}
|
|
1869
|
+
if (e->pos >= e->len) {
|
|
1870
|
+
return e_fail(e, YEP_ERR_UNEXPECTED, e->pos);
|
|
1871
|
+
}
|
|
1872
|
+
c = (unsigned char)e->p[e->pos];
|
|
1873
|
+
}
|
|
1767
1874
|
if ((c == ',' || c == ']' || c == '}' || c == ':') &&
|
|
1768
1875
|
(!yep_view_is_empty(anchor) || !yep_view_is_empty(tag))) {
|
|
1769
1876
|
ev->implicit = 1; /* properties with no node: a tagged null */
|
|
@@ -4235,12 +4342,35 @@ yep_pool* yep_engine_detach_pool(yep_engine* e) {
|
|
|
4235
4342
|
return p;
|
|
4236
4343
|
}
|
|
4237
4344
|
|
|
4345
|
+
char* yep_engine_detach_norm_buf(yep_engine* e, size_t* len_out) {
|
|
4346
|
+
if (e == NULL) {
|
|
4347
|
+
if (len_out != NULL) {
|
|
4348
|
+
*len_out = 0;
|
|
4349
|
+
}
|
|
4350
|
+
return NULL;
|
|
4351
|
+
}
|
|
4352
|
+
char* b = e->norm_buf;
|
|
4353
|
+
if (len_out != NULL) {
|
|
4354
|
+
*len_out = e->norm_buf_len;
|
|
4355
|
+
}
|
|
4356
|
+
e->norm_buf = NULL;
|
|
4357
|
+
e->norm_buf_len = 0;
|
|
4358
|
+
return b;
|
|
4359
|
+
}
|
|
4360
|
+
|
|
4238
4361
|
void yep_engine_prepare(yep_engine* e, const yep_text_stats* st) {
|
|
4239
4362
|
if (e == NULL || st == NULL) {
|
|
4240
4363
|
return;
|
|
4241
4364
|
}
|
|
4242
4365
|
if (st->amp > 0) {
|
|
4243
4366
|
yep_nametab_reserve(&e->anchors, (uint32_t)st->amp);
|
|
4367
|
+
/* every definition bumps the serial exactly once and '&' marks
|
|
4368
|
+
* every definition, so amp is the serial's exact ceiling: the
|
|
4369
|
+
* placed flags pre-fit here and the parse never pays the
|
|
4370
|
+
* doubling chain (alloc + copy + memset per growth). Best
|
|
4371
|
+
* effort — anchor_define's growth stays as the fallback for
|
|
4372
|
+
* engines driven without prepare. */
|
|
4373
|
+
anchor_placed_fit(e, (uint32_t)st->amp + 1);
|
|
4244
4374
|
}
|
|
4245
4375
|
}
|
|
4246
4376
|
|
|
@@ -4315,6 +4445,7 @@ const yep_stopset yep_norm_break_leads = {
|
|
|
4315
4445
|
* headers). Verified against libyaml by the NormLsPs pins and the
|
|
4316
4446
|
* fuzz-diff LS/PS comparator. */
|
|
4317
4447
|
static int step_bs_header(const char* p, size_t len, size_t i);
|
|
4448
|
+
static size_t norm_next_fold_break(const char* p, size_t len, size_t i, size_t* br_len);
|
|
4318
4449
|
|
|
4319
4450
|
typedef struct yep_norm_ctx {
|
|
4320
4451
|
int quote; /* 0 none, else the opening quote char */
|
|
@@ -4326,15 +4457,44 @@ typedef struct yep_norm_ctx {
|
|
|
4326
4457
|
int at_break;
|
|
4327
4458
|
int bs_open;
|
|
4328
4459
|
int bs_content;
|
|
4329
|
-
uint32_t bs_indent;
|
|
4330
|
-
|
|
4331
|
-
uint8_t started;
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
unsigned char prev;
|
|
4336
|
-
|
|
4337
|
-
|
|
4460
|
+
uint32_t bs_indent; /* the header line's indent; (uint32_t)-1 = the
|
|
4461
|
+
* doc-inline root rule (markers only) */
|
|
4462
|
+
uint8_t started; /* at least one byte consumed: the walk's i == 0
|
|
4463
|
+
* clauses are stream-start, not buffer-start —
|
|
4464
|
+
* the chunked route resumes mid-stream at a ---
|
|
4465
|
+
* cut, and the carried context must say so */
|
|
4466
|
+
unsigned char prev; /* the last consumed byte (valid when started):
|
|
4467
|
+
* the '#' and line-start tests peek p[i - 1],
|
|
4468
|
+
* which at a resumed buffer is carried state */
|
|
4469
|
+
unsigned char bb; /* the byte immediately before the last FOLDED
|
|
4470
|
+
* break (0 = not armed): the r133 law — a
|
|
4471
|
+
* tok_start armed by a fold whose before-break
|
|
4472
|
+
* byte was plain content is a continuation
|
|
4473
|
+
* line, and its "!<" must not open a verbatim
|
|
4474
|
+
* tag (cleared wherever an indicator arms the
|
|
4475
|
+
* slot instead) */
|
|
4476
|
+
unsigned char plain_open; /* a plain scalar VALUE word is in
|
|
4477
|
+
* progress (set by every non-indicator content
|
|
4478
|
+
* byte, preserved across breaks): the r147
|
|
4479
|
+
* law — the bb gate's single-byte slice misses
|
|
4480
|
+
* the run-tail shapes ("- \n<NEL>!" arms
|
|
4481
|
+
* bb='\n', in the indicator set), so the open
|
|
4482
|
+
* keys on the value-in-progress fact: a
|
|
4483
|
+
* fold-armed tok_start over an open plain is a
|
|
4484
|
+
* continuation line whose "!<" is content,
|
|
4485
|
+
* never props */
|
|
4486
|
+
int phantom_flow; /* openers armed by the glued ':'-twin
|
|
4487
|
+
* ("a:{b]" — the #836-accepted prev==':'
|
|
4488
|
+
* clause) alone: libyaml keeps those bytes
|
|
4489
|
+
* INTERIOR to the plain (no flow collection
|
|
4490
|
+
* exists), so their depth must never arm the
|
|
4491
|
+
* r155 real-flow clear on ']' / '}' — the
|
|
4492
|
+
* walk's in_flow is monotone and the phantom
|
|
4493
|
+
* opens inflate it, which defeated the
|
|
4494
|
+
* "block context keeps the fact" law (the
|
|
4495
|
+
* r169 nightly: the ']' cleared plain_open
|
|
4496
|
+
* through the phantom and the next fold's
|
|
4497
|
+
* "!<" opened a never-closed verbatim) */
|
|
4338
4498
|
} yep_norm_ctx;
|
|
4339
4499
|
|
|
4340
4500
|
typedef struct yep_norm_tok {
|
|
@@ -4482,6 +4642,7 @@ static yep_norm_tok norm_step(yep_norm_ctx* c, const char* p, size_t len, size_t
|
|
|
4482
4642
|
t.n = 2;
|
|
4483
4643
|
t.fold_off = 0;
|
|
4484
4644
|
t.fold_len = 2;
|
|
4645
|
+
c->bb = (i > 0) ? (unsigned char)p[i - 1] : '\n';
|
|
4485
4646
|
norm_break_arms(c);
|
|
4486
4647
|
return t;
|
|
4487
4648
|
}
|
|
@@ -4489,6 +4650,7 @@ static yep_norm_tok norm_step(yep_norm_ctx* c, const char* p, size_t len, size_t
|
|
|
4489
4650
|
t.n = 3;
|
|
4490
4651
|
t.fold_off = 0;
|
|
4491
4652
|
t.fold_len = 3;
|
|
4653
|
+
c->bb = (i > 0) ? (unsigned char)p[i - 1] : '\n';
|
|
4492
4654
|
norm_break_arms(c);
|
|
4493
4655
|
return t;
|
|
4494
4656
|
}
|
|
@@ -4502,19 +4664,22 @@ static yep_norm_tok norm_step(yep_norm_ctx* c, const char* p, size_t len, size_t
|
|
|
4502
4664
|
c->at_break = 0;
|
|
4503
4665
|
return t;
|
|
4504
4666
|
}
|
|
4505
|
-
if (ch == ' ' || ch == '\t') {
|
|
4506
|
-
/* a value position survives spaces in block context ("k: 'x'"
|
|
4507
|
-
* opens; the plain continuation "a 'b'" does not — its word
|
|
4508
|
-
* did not begin with an indicator) */
|
|
4509
|
-
c->tok_start = (c->in_flow > 0) ? 1 : (c->word_led || c->tok_start);
|
|
4510
|
-
return t;
|
|
4511
|
-
}
|
|
4512
|
-
|
|
4513
4667
|
int line_start = (!c->started || c->at_break || c->prev == '\n' || c->prev == '\r');
|
|
4514
4668
|
|
|
4515
4669
|
/* block scalars: inside the fold no quote opens and every break
|
|
4516
4670
|
* keeps its fold; the region ends at a col-0 marker, a %-line
|
|
4517
|
-
* after content, or a dedent to the header line's indent
|
|
4671
|
+
* after content, or a dedent to the header line's indent. It runs
|
|
4672
|
+
* BEFORE the token-space arm: a fold line's leading spaces are its
|
|
4673
|
+
* INDENT, and the space arm consumed them one byte at a time (the
|
|
4674
|
+
* at_break stays armed) so the indent walk below counted from the
|
|
4675
|
+
* FIRST NON-SPACE byte — a one-space-indented content line read
|
|
4676
|
+
* ind=0, the dedent rule (ind <= bs_indent) ended the fold
|
|
4677
|
+
* mid-content, and the byte lexed as a token: "!<" armed a phantom
|
|
4678
|
+
* verbatim whose breaks-ride-raw law left the whole tail
|
|
4679
|
+
* unnormalized, the raw NEL run classified as one content line,
|
|
4680
|
+
* and the framing walk spawned a phantom empty plain second
|
|
4681
|
+
* document libyaml never emits (the r194 nightly,
|
|
4682
|
+
* ">\n ! \n !<aaa: bbb\n...\n<NEL><NEL>"). */
|
|
4518
4683
|
if (line_start && c->in_flow == 0 && c->bs_open) {
|
|
4519
4684
|
size_t k = i;
|
|
4520
4685
|
uint32_t ind = 0;
|
|
@@ -4528,12 +4693,52 @@ static yep_norm_tok norm_step(yep_norm_ctx* c, const char* p, size_t len, size_t
|
|
|
4528
4693
|
return t; /* a final line without its break */
|
|
4529
4694
|
}
|
|
4530
4695
|
if (p[k] == '\n' || p[k] == '\r' || p[k] == '#') {
|
|
4696
|
+
/* the line ends at ANY break spelling: a multibyte break
|
|
4697
|
+
* (NEL/LS/PS) FOLDS at the token tail, exactly like the
|
|
4698
|
+
* '#' comment arm ends its line (the pre-r194 path: the
|
|
4699
|
+
* token-space arm consumed the leading spaces one byte at
|
|
4700
|
+
* a time and the line's '#' hit the comment arm, whose
|
|
4701
|
+
* nel/lps case folds). Riding the break raw inside the
|
|
4702
|
+
* wholesale token leaked it to the engine's verbatim
|
|
4703
|
+
* block-scalar reader, and the r19-family indent
|
|
4704
|
+
* transform's verify (sub ">\n #ML<NEL>\n") stopped
|
|
4705
|
+
* flipping to parity — the r195 nightly ">\n#ML<NEL>". */
|
|
4531
4706
|
size_t e = k;
|
|
4532
|
-
|
|
4707
|
+
size_t bs = 0;
|
|
4708
|
+
size_t br = 0;
|
|
4709
|
+
while (e < len) {
|
|
4710
|
+
if (p[e] == '\n') {
|
|
4711
|
+
bs = e;
|
|
4712
|
+
br = 1;
|
|
4713
|
+
e++;
|
|
4714
|
+
break;
|
|
4715
|
+
}
|
|
4716
|
+
if (p[e] == '\r') {
|
|
4717
|
+
bs = e;
|
|
4718
|
+
br = (e + 1 < len && p[e + 1] == '\n') ? 2 : 1;
|
|
4719
|
+
e += br;
|
|
4720
|
+
break;
|
|
4721
|
+
}
|
|
4722
|
+
size_t mb = yep_scan_mb_break_len(p, len, e);
|
|
4723
|
+
if (mb > 0) {
|
|
4724
|
+
bs = e;
|
|
4725
|
+
br = mb;
|
|
4726
|
+
e += mb;
|
|
4727
|
+
break;
|
|
4728
|
+
}
|
|
4533
4729
|
e++;
|
|
4534
4730
|
}
|
|
4535
|
-
|
|
4536
|
-
|
|
4731
|
+
if (br == 0) {
|
|
4732
|
+
t.n = len - i;
|
|
4733
|
+
c->at_break = 0;
|
|
4734
|
+
return t; /* the tail rides the line to EOF */
|
|
4735
|
+
}
|
|
4736
|
+
t.n = e - i;
|
|
4737
|
+
if (p[bs] != '\n' && p[bs] != '\r') {
|
|
4738
|
+
t.fold_off = (int)(bs - i);
|
|
4739
|
+
t.fold_len = (int)br;
|
|
4740
|
+
}
|
|
4741
|
+
c->at_break = 1;
|
|
4537
4742
|
return t; /* blank or comment-content line */
|
|
4538
4743
|
}
|
|
4539
4744
|
int marker = (ind == 0 && k + 2 < len &&
|
|
@@ -4561,6 +4766,14 @@ static yep_norm_tok norm_step(yep_norm_ctx* c, const char* p, size_t len, size_t
|
|
|
4561
4766
|
}
|
|
4562
4767
|
}
|
|
4563
4768
|
|
|
4769
|
+
if (ch == ' ' || ch == '\t') {
|
|
4770
|
+
/* a value position survives spaces in block context ("k: 'x'"
|
|
4771
|
+
* opens; the plain continuation "a 'b'" does not — its word
|
|
4772
|
+
* did not begin with an indicator) */
|
|
4773
|
+
c->tok_start = (c->in_flow > 0) ? 1 : (c->word_led || c->tok_start);
|
|
4774
|
+
return t;
|
|
4775
|
+
}
|
|
4776
|
+
|
|
4564
4777
|
/* the header: a '>' / '|' at a value position with a valid
|
|
4565
4778
|
* follower opens the fold (the engine's own floor is the parent's
|
|
4566
4779
|
* column, which the walk cannot know — the header LINE's indent
|
|
@@ -4585,12 +4798,29 @@ static yep_norm_tok norm_step(yep_norm_ctx* c, const char* p, size_t len, size_t
|
|
|
4585
4798
|
c->bs_open = 1;
|
|
4586
4799
|
c->bs_indent = ind;
|
|
4587
4800
|
c->bs_content = 0;
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4801
|
+
/* the header line ends at ANY fold break: the tail past
|
|
4802
|
+
* the indicators (usually the comment) is OUTSIDE the
|
|
4803
|
+
* block-content area, so the #638 fold law governs it — a
|
|
4804
|
+
* NEL/LS/PS there ends the header line and the next line
|
|
4805
|
+
* rides the bs branch from its own indent (the r171
|
|
4806
|
+
* nightly: the '\n'-only scan swallowed " #<"+NEL+" t"
|
|
4807
|
+
* whole, the NEL rode unnormalized to the engine, whose
|
|
4808
|
+
* comment skip then ate the content line — empty where
|
|
4809
|
+
* libyaml's IS_BREAKZ comment law reads "t") */
|
|
4810
|
+
size_t br_len = 0;
|
|
4811
|
+
size_t e = norm_next_fold_break(p, len, i, &br_len);
|
|
4812
|
+
if (br_len > 0) {
|
|
4813
|
+
t.n = (e + br_len) - i;
|
|
4814
|
+
t.fold_off = (int)(e - i); /* the break FOLDS: the copy
|
|
4815
|
+
* splices the '\n' (a
|
|
4816
|
+
* plain-consumed multibyte
|
|
4817
|
+
* break would ride raw) */
|
|
4818
|
+
t.fold_len = (int)br_len;
|
|
4819
|
+
c->at_break = 1;
|
|
4820
|
+
} else {
|
|
4821
|
+
t.n = len - i;
|
|
4822
|
+
c->at_break = 0;
|
|
4591
4823
|
}
|
|
4592
|
-
t.n = (e < len) ? (e - i + 1) : (len - i);
|
|
4593
|
-
c->at_break = (e < len);
|
|
4594
4824
|
return t;
|
|
4595
4825
|
}
|
|
4596
4826
|
/* not a header ("| : [" is a mapping key): fall through */
|
|
@@ -4616,24 +4846,55 @@ static yep_norm_tok norm_step(yep_norm_ctx* c, const char* p, size_t len, size_t
|
|
|
4616
4846
|
c->bs_open = 1;
|
|
4617
4847
|
c->bs_indent = (uint32_t)-1;
|
|
4618
4848
|
c->bs_content = 0;
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4849
|
+
c->plain_open = 0; /* the marker is a document boundary */
|
|
4850
|
+
/* the marker line's tail ends at any fold break (the same
|
|
4851
|
+
* law as the plain header above -- the comment tail is
|
|
4852
|
+
* outside the content area) */
|
|
4853
|
+
size_t br_len = 0;
|
|
4854
|
+
size_t e = norm_next_fold_break(p, len, i, &br_len);
|
|
4855
|
+
if (br_len > 0) {
|
|
4856
|
+
t.n = (e + br_len) - i;
|
|
4857
|
+
t.fold_off = (int)(e - i); /* the break folds (the header twin) */
|
|
4858
|
+
t.fold_len = (int)br_len;
|
|
4859
|
+
c->at_break = 1;
|
|
4860
|
+
} else {
|
|
4861
|
+
t.n = len - i;
|
|
4862
|
+
c->at_break = 0;
|
|
4622
4863
|
}
|
|
4623
|
-
t.n = (e < len) ? (e - i + 1) : (len - i);
|
|
4624
|
-
c->at_break = (e < len);
|
|
4625
4864
|
return t;
|
|
4626
4865
|
}
|
|
4627
|
-
t.n = 3;
|
|
4866
|
+
t.n = 3; /* the marker rides; the line's tail processes normally */
|
|
4867
|
+
c->plain_open = 0; /* a document boundary: the next node's
|
|
4868
|
+
* props position must not inherit the
|
|
4869
|
+
* previous document's open plain */
|
|
4628
4870
|
return t;
|
|
4629
4871
|
}
|
|
4630
4872
|
|
|
4631
4873
|
if (c->tok_start) {
|
|
4632
4874
|
c->at_break = 0; /* any content byte ends the line-start state */
|
|
4633
4875
|
if (ch == '!' && i + 1 < len && p[i + 1] == '<') {
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4876
|
+
/* the r133 law: a tok_start armed by a FOLDED break whose
|
|
4877
|
+
* before-break byte was plain content is a continuation
|
|
4878
|
+
* line — its "!<" is plain content, not props; only a
|
|
4879
|
+
* new-node position (an indicator like ':' armed the slot)
|
|
4880
|
+
* opens a verbatim tag. Unconditioned, the continuation's
|
|
4881
|
+
* "!<" opened a phantom verbatim that swallowed the rest
|
|
4882
|
+
* of the input: later NELs rode unnormalized and the plain
|
|
4883
|
+
* fold emitted raw lead-stripped 0x85 into the value. The
|
|
4884
|
+
* r147 law extends the gate to the run-tail shapes the
|
|
4885
|
+
* single-byte bb probe misses ("- \n<NEL>!" arms bb='\n',
|
|
4886
|
+
* in the indicator set; "key: <NEL><NEL>!" arms bb=0x85,
|
|
4887
|
+
* outside it — both while a plain VALUE is in progress,
|
|
4888
|
+
* which plain_open carries): a plain value word open
|
|
4889
|
+
* across the fold means the line is a continuation, and
|
|
4890
|
+
* libyaml's 1.1 read folds the same NELs to newlines
|
|
4891
|
+
* (READ_LINE spells NEL -> LF, the fold law joins). */
|
|
4892
|
+
int bb_plain = c->bb != 0 && !strchr("&*!-?:,[]{}#%'\"|> \t\n\r", c->bb);
|
|
4893
|
+
if (!bb_plain && !c->plain_open) {
|
|
4894
|
+
c->in_verbatim = 1;
|
|
4895
|
+
t.n = 2;
|
|
4896
|
+
return t;
|
|
4897
|
+
}
|
|
4637
4898
|
}
|
|
4638
4899
|
c->word_led = (ch == '&' || ch == '*' || ch == '!' || ch == '-' || ch == '?' || ch == ':' ||
|
|
4639
4900
|
ch == ',' || ch == '[' || ch == '{' || ch == ']' || ch == '}');
|
|
@@ -4655,10 +4916,29 @@ static yep_norm_tok norm_step(yep_norm_ctx* c, const char* p, size_t len, size_t
|
|
|
4655
4916
|
* fold rendered one fold-SPACE per break instead of the n-1
|
|
4656
4917
|
* newline tally (the r98 nightly — the #836 phantom's flow
|
|
4657
4918
|
* half; the comma half landed in #836 itself). */
|
|
4919
|
+
int phantom = !c->tok_start; /* the glued ':'-twin alone (the
|
|
4920
|
+
* #836-accepted prev==':' state):
|
|
4921
|
+
* libyaml keeps the opener interior
|
|
4922
|
+
* to the plain, so its depth rides
|
|
4923
|
+
* phantom_flow, never the real count */
|
|
4658
4924
|
c->tok_start = 1;
|
|
4925
|
+
if (phantom) {
|
|
4926
|
+
c->phantom_flow++;
|
|
4927
|
+
/* the phantom opener is INTERIOR to the open plain VALUE
|
|
4928
|
+
* word (libyaml's read keeps the bytes content) — the fact
|
|
4929
|
+
* must survive it, or the r147 gate dies two shapes later:
|
|
4930
|
+
* the slot the opener armed says "new node" while the plain
|
|
4931
|
+
* is still open, and a following "!<" opened a phantom
|
|
4932
|
+
* verbatim that swallowed the rest of the input (the r217
|
|
4933
|
+
* nightly: "a:{!<x>"+NEL — "k:{" armed by the ':' indicator
|
|
4934
|
+
* clears a live plain_open). The r155/r169 law's opener
|
|
4935
|
+
* twin: block context keeps the fact. */
|
|
4936
|
+
} else {
|
|
4937
|
+
c->plain_open = 0; /* the slot was armed by an indicator */
|
|
4938
|
+
}
|
|
4659
4939
|
c->in_flow++;
|
|
4660
4940
|
} else if (ch == ',') {
|
|
4661
|
-
/* flow separators glue the next token — THE COMMA IN FLOW
|
|
4941
|
+
/* flow separators glue the next token — THE COMMA IN REAL FLOW
|
|
4662
4942
|
* ONLY. The unconditioned arm let a BLOCK plain's interior
|
|
4663
4943
|
* comma arm tok_start, a following "!<" opened a phantom
|
|
4664
4944
|
* verbatim tag that swallowed the rest of the input (breaks
|
|
@@ -4667,22 +4947,66 @@ static yep_norm_tok norm_step(yep_norm_ctx* c, const char* p, size_t len, size_t
|
|
|
4667
4947
|
* fold's blank-line tally lost them (the r96 nightly,
|
|
4668
4948
|
* yeptris#836, "b,,,!<!<"+NEL^3). ':' stays unconditioned:
|
|
4669
4949
|
* the BLOCK value position rides it ("k: 'x'" opens the
|
|
4670
|
-
* quote, the NormLsPs pins).
|
|
4671
|
-
|
|
4950
|
+
* quote, the NormLsPs pins). The r217 law: "in flow" means
|
|
4951
|
+
* REAL flow depth (the r155/r169 gate) — the glued ':'-twin's
|
|
4952
|
+
* phantom opens inflate in_flow without any flow collection
|
|
4953
|
+
* existing in libyaml's read, so their commas are INTERIOR
|
|
4954
|
+
* plain content ("o&a-:{*,,,!<!<"+NEL^3: the phantom '{'
|
|
4955
|
+
* inflated in_flow, the interior ','s armed a props slot, and
|
|
4956
|
+
* the "!<" opened the phantom verbatim again). */
|
|
4957
|
+
if (c->in_flow > c->phantom_flow) {
|
|
4672
4958
|
c->tok_start = 1;
|
|
4959
|
+
c->bb = 0; /* the slot was armed by an indicator, not a fold */
|
|
4960
|
+
c->plain_open = 0;
|
|
4673
4961
|
}
|
|
4674
4962
|
} else if (ch == ':') {
|
|
4675
4963
|
/* the separator law (#833's own predicate): a ':' arms the
|
|
4676
4964
|
* next token slot only before a blank/EOL/EOF — "k: 'x'"
|
|
4677
4965
|
* opens the value quote (the NormLsPs pins) while an
|
|
4678
4966
|
* interior "x:!<" of a block plain does NOT (the phantom
|
|
4679
|
-
* verbatim again, the #836 colon-led twin)
|
|
4967
|
+
* verbatim again, the #836 colon-led twin). The r217 law for
|
|
4968
|
+
* the DECLINED ':': a ':' before a non-blank byte is interior
|
|
4969
|
+
* to a plain, or the plain's own LEAD ("k:\t:{!<" — the
|
|
4970
|
+
* separating ':'+tab left plain_open dead, the value plain's
|
|
4971
|
+
* lead ':' declines, and the phantom '{' behind it armed a
|
|
4972
|
+
* props slot both of whose gates were dead — the "!<" opened
|
|
4973
|
+
* the phantom verbatim and the NEL run rode raw). The decline
|
|
4974
|
+
* IS the plain-context fact: arm the value word here. */
|
|
4680
4975
|
if (i + 1 >= len || p[i + 1] == ' ' || p[i + 1] == '\t' || p[i + 1] == '\n' ||
|
|
4681
4976
|
p[i + 1] == '\r') {
|
|
4682
4977
|
c->tok_start = 1;
|
|
4978
|
+
c->bb = 0; /* the slot was armed by an indicator, not a fold */
|
|
4979
|
+
c->plain_open = 0;
|
|
4980
|
+
} else {
|
|
4981
|
+
c->plain_open = 1;
|
|
4683
4982
|
}
|
|
4684
4983
|
} else if (ch == ']' || ch == '}') {
|
|
4685
4984
|
c->tok_start = 1;
|
|
4985
|
+
c->bb = 0; /* the slot was armed by an indicator, not a fold */
|
|
4986
|
+
if (c->in_flow > c->phantom_flow) {
|
|
4987
|
+
c->plain_open = 0;
|
|
4988
|
+
}
|
|
4989
|
+
/* block context keeps the fact: a plain cannot start with
|
|
4990
|
+
* ']' / '}' (c-indicator), so reaching this byte with the value
|
|
4991
|
+
* word open means it is INTERIOR content (the catch-85 law's
|
|
4992
|
+
* indicator twin) — the r155 law. The unconditional clear let
|
|
4993
|
+
* the next fold-armed "!<" open a phantom verbatim (the r147
|
|
4994
|
+
* gate's blind-spot twin: the ']' byte also blanks bb_plain —
|
|
4995
|
+
* it is in the bb indicator set — so both gate inputs said
|
|
4996
|
+
* "new node") and the NELs after it rode unnormalized raw into
|
|
4997
|
+
* the plain fold ("(999999;!<1]" +NEL+ "!<" +NEL+ "¥" +NEL^2).
|
|
4998
|
+
* The clear keys on REAL flow (in_flow above the phantom
|
|
4999
|
+
* depth): the glued ':'-twin's phantom opens inflate in_flow
|
|
5000
|
+
* without any flow collection existing in libyaml's read, and
|
|
5001
|
+
* the inflated count defeated the law on a plain's interior ']'
|
|
5002
|
+
* ("a:{b]" +NEL — the r169 nightly's fifth arming shape). */
|
|
5003
|
+
}
|
|
5004
|
+
/* the r147 law: a non-indicator content byte begins/continues a
|
|
5005
|
+
* plain scalar VALUE word — the fact survives breaks (breaks only
|
|
5006
|
+
* arm tok_start), so a later fold-armed "!<" reads it (indicator
|
|
5007
|
+
* bytes leave the fact to their own arm above) */
|
|
5008
|
+
if (!strchr("&*!-?:,[]{}#%'\"|>", ch)) {
|
|
5009
|
+
c->plain_open = 1;
|
|
4686
5010
|
}
|
|
4687
5011
|
return t;
|
|
4688
5012
|
}
|
|
@@ -4798,6 +5122,24 @@ static char* norm_breaks_run(const yep_allocator* sys, const char* p, size_t len
|
|
|
4798
5122
|
} else {
|
|
4799
5123
|
memcpy(out + o, p + j, (size_t)t.fold_off);
|
|
4800
5124
|
o += (size_t)t.fold_off;
|
|
5125
|
+
/* A raw CR copied just before this rewrite must not pair
|
|
5126
|
+
* with the replacement '\n' into a phantom CRLF: the byte
|
|
5127
|
+
* readers count CR LF as ONE break (SKIP_LINE's pair law)
|
|
5128
|
+
* while the input's CR + NEL/LS/PS were TWO — the rewrite
|
|
5129
|
+
* silently halved the fold's break tally (";!\r<NEL>\r;\r"
|
|
5130
|
+
* read ";!\\n;" where the (n-1) newline law says
|
|
5131
|
+
* ";!\\n\\n;", the r188 nightly). Rewrite the WHOLE
|
|
5132
|
+
* trailing run of raw CRs to '\n' — one CR is one break,
|
|
5133
|
+
* and only the run's last byte could ever touch the
|
|
5134
|
+
* replacement, but a shallower rewrite would just move the
|
|
5135
|
+
* phantom pair one byte left ("a\r\r<NEL>" -> "a\r\n\n"
|
|
5136
|
+
* re-pairs on the first CR; the run makes it "a\n\n\n",
|
|
5137
|
+
* four breaks in, four breaks out). LFs never pair with
|
|
5138
|
+
* each other, so the run's count survives everywhere the
|
|
5139
|
+
* fold law counts breaks. */
|
|
5140
|
+
for (size_t t2 = o; t2 > 0 && out[t2 - 1] == '\r'; t2--) {
|
|
5141
|
+
out[t2 - 1] = '\n';
|
|
5142
|
+
}
|
|
4801
5143
|
out[o++] = '\n';
|
|
4802
5144
|
memcpy(out + o, p + j + t.fold_off + t.fold_len,
|
|
4803
5145
|
t.n - (size_t)t.fold_off - (size_t)t.fold_len);
|
|
@@ -4822,6 +5164,7 @@ static const char* e_normalize_breaks(yep_engine* e, const char* p, size_t len,
|
|
|
4822
5164
|
return p;
|
|
4823
5165
|
}
|
|
4824
5166
|
e->norm_buf = out;
|
|
5167
|
+
e->norm_buf_len = out ? *out_len : 0;
|
|
4825
5168
|
return out;
|
|
4826
5169
|
}
|
|
4827
5170
|
|
|
@@ -4981,6 +5324,41 @@ void yep_engine_destroy(yep_engine* e) {
|
|
|
4981
5324
|
* that flow to the depth cap, chunked cut and errored at 2:1).
|
|
4982
5325
|
* Returns 1 valid, 0 definitely not a header, -1 truncated (the tail
|
|
4983
5326
|
* may still complete a valid header). */
|
|
5327
|
+
|
|
5328
|
+
/* The next FOLD break at or after i under the #638 fold law outside
|
|
5329
|
+
* quotes ('\n', lone '\r' / CRLF, NEL, LS/PS): returns its start
|
|
5330
|
+
* offset and stores its consumed length, or returns 0 with *br_len 0
|
|
5331
|
+
* when the tail holds none. A truncated multibyte lead at the end
|
|
5332
|
+
* reads as "none": the one-shot walk runs on validated complete input
|
|
5333
|
+
* (a dangling lead never arrives), and the streaming scanner holds the
|
|
5334
|
+
* header line for the bytes that may still complete it. */
|
|
5335
|
+
static size_t norm_next_fold_break(const char* p, size_t len, size_t i, size_t* br_len) {
|
|
5336
|
+
size_t e = i;
|
|
5337
|
+
*br_len = 0;
|
|
5338
|
+
while (e < len) {
|
|
5339
|
+
unsigned char ec = (unsigned char)p[e];
|
|
5340
|
+
if (ec == '\n') {
|
|
5341
|
+
*br_len = 1;
|
|
5342
|
+
return e;
|
|
5343
|
+
}
|
|
5344
|
+
if (ec == '\r') {
|
|
5345
|
+
*br_len = (e + 1 < len && p[e + 1] == '\n') ? 2 : 1;
|
|
5346
|
+
return e;
|
|
5347
|
+
}
|
|
5348
|
+
if (ec == 0xC2 && e + 1 < len && (unsigned char)p[e + 1] == 0x85) {
|
|
5349
|
+
*br_len = 2;
|
|
5350
|
+
return e;
|
|
5351
|
+
}
|
|
5352
|
+
if (ec == 0xE2 && e + 2 < len && (unsigned char)p[e + 1] == 0x80 &&
|
|
5353
|
+
((unsigned char)p[e + 2] & 0xFE) == 0xA8) {
|
|
5354
|
+
*br_len = 3;
|
|
5355
|
+
return e;
|
|
5356
|
+
}
|
|
5357
|
+
e++;
|
|
5358
|
+
}
|
|
5359
|
+
return 0;
|
|
5360
|
+
}
|
|
5361
|
+
|
|
4984
5362
|
static int step_bs_header(const char* p, size_t len, size_t i) {
|
|
4985
5363
|
size_t k = i + 1;
|
|
4986
5364
|
int chomp = 0, indent = 0, space = 0;
|
|
@@ -5174,6 +5552,12 @@ static size_t step_scan(yep_stepstate* st) {
|
|
|
5174
5552
|
* ate the '---' marker, chunked errored on the unterminated
|
|
5175
5553
|
* prefix — the nightly's run 38534965021) */
|
|
5176
5554
|
st->tok_start = (st->in_flow > 0) ? 1 : st->word_led;
|
|
5555
|
+
/* the one-shot walk's law: the first post-break byte
|
|
5556
|
+
* clears the line-start fact — spaces included, or an
|
|
5557
|
+
* INDENTED " ---" (a plain/seq position) read as a
|
|
5558
|
+
* col-0 marker through the line-start gate and the cut
|
|
5559
|
+
* landed inside the line (the r171 gate twin) */
|
|
5560
|
+
st->at_break = 0;
|
|
5177
5561
|
continue;
|
|
5178
5562
|
}
|
|
5179
5563
|
if (st->tok_start) {
|
|
@@ -5250,7 +5634,11 @@ static size_t step_scan(yep_stepstate* st) {
|
|
|
5250
5634
|
}
|
|
5251
5635
|
if (st->in_flow == 0) {
|
|
5252
5636
|
char prev = i > 0 ? p[i - 1] : '\n';
|
|
5253
|
-
if (prev != '\n' && prev != '\r') {
|
|
5637
|
+
if (prev != '\n' && prev != '\r' && !st->at_break) {
|
|
5638
|
+
/* the one-shot walk's line_start law honors at_break
|
|
5639
|
+
* (-- the mb-break arms arm it); the prev-only check
|
|
5640
|
+
* missed every line that opens after a NEL/LS/PS, so
|
|
5641
|
+
* the ride-along never fired there (the r171 twin) */
|
|
5254
5642
|
continue;
|
|
5255
5643
|
}
|
|
5256
5644
|
/* Block scalars: once a '>' / '|' header is seen, its
|
|
@@ -5326,15 +5714,26 @@ static size_t step_scan(yep_stepstate* st) {
|
|
|
5326
5714
|
}
|
|
5327
5715
|
st->bs_open = 1;
|
|
5328
5716
|
st->bs_indent = ind;
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5717
|
+
/* the header line ends at ANY fold break (the
|
|
5718
|
+
* one-shot walk's law, norm_next_fold_break): the
|
|
5719
|
+
* tail past the indicators is outside the
|
|
5720
|
+
* block-content area, so the #638 fold law
|
|
5721
|
+
* governs it. The break arms' state rides here
|
|
5722
|
+
* too — at_break opens the content line's
|
|
5723
|
+
* ride-along through the line-start gate (the
|
|
5724
|
+
* r171 nightly: the '\n'-only scan never
|
|
5725
|
+
* completed a NEL-terminated header line and
|
|
5726
|
+
* held the window at the '>' forever) */
|
|
5727
|
+
size_t br_len = 0;
|
|
5728
|
+
size_t e = norm_next_fold_break(p, st->len, i, &br_len);
|
|
5729
|
+
if (br_len == 0) {
|
|
5334
5730
|
hold = i; /* an incomplete header line */
|
|
5335
5731
|
break;
|
|
5336
5732
|
}
|
|
5337
|
-
|
|
5733
|
+
st->tok_start = 1;
|
|
5734
|
+
st->word_led = 0;
|
|
5735
|
+
st->at_break = 1;
|
|
5736
|
+
i = e + br_len - 1; /* the loop's i++ lands past the break */
|
|
5338
5737
|
continue;
|
|
5339
5738
|
}
|
|
5340
5739
|
/* Not a header ("| : [" is a mapping key): fall through
|
|
@@ -5512,6 +5911,7 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
|
|
|
5512
5911
|
}
|
|
5513
5912
|
yep_free(e->sys, e->norm_buf);
|
|
5514
5913
|
e->norm_buf = NULL;
|
|
5914
|
+
e->norm_buf_len = 0;
|
|
5515
5915
|
/* enc_buf is NOT reset here: yep_engine_run's front-end may have
|
|
5516
5916
|
* transcoded THIS call's input into it microseconds ago -- buf
|
|
5517
5917
|
* points into it, and freeing it before the break-normalize scan
|
|
@@ -5536,7 +5936,7 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
|
|
|
5536
5936
|
if (e->anchor_placed != NULL) {
|
|
5537
5937
|
memset(e->anchor_placed, 0, e->anchor_placed_cap);
|
|
5538
5938
|
}
|
|
5539
|
-
e->
|
|
5939
|
+
e->alias_memo.len = 0;
|
|
5540
5940
|
e->tagmap_n = 0;
|
|
5541
5941
|
e->saw_yaml = 0;
|
|
5542
5942
|
e->doc_begin = (size_t)-1;
|
|
@@ -5771,11 +6171,11 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
|
|
|
5771
6171
|
if (e->anchor_placed != NULL) {
|
|
5772
6172
|
memset(e->anchor_placed, 0, e->anchor_placed_cap);
|
|
5773
6173
|
}
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
|
|
6174
|
+
/* so are anchors — and the repeat-alias memo: doc 1's
|
|
6175
|
+
* "*ORIGIN" memoized the ordinal and doc 2's identical
|
|
6176
|
+
* name answered from it ACROSS the boundary (the
|
|
6177
|
+
* nightly's run 38266487549) */
|
|
6178
|
+
e->alias_memo.len = 0;
|
|
5779
6179
|
}
|
|
5780
6180
|
e_event_init(&ev, YEP_EV_DOCUMENT_START);
|
|
5781
6181
|
ev.style = 1; /* explicit marker */
|
|
@@ -5862,7 +6262,7 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
|
|
|
5862
6262
|
if (e->anchor_placed != NULL) {
|
|
5863
6263
|
memset(e->anchor_placed, 0, e->anchor_placed_cap);
|
|
5864
6264
|
}
|
|
5865
|
-
e->
|
|
6265
|
+
e->alias_memo.len = 0;
|
|
5866
6266
|
if (emit_now(e, &ev) != 0) {
|
|
5867
6267
|
return -2;
|
|
5868
6268
|
}
|
|
@@ -6101,7 +6501,7 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
|
|
|
6101
6501
|
if (e->anchor_placed != NULL) {
|
|
6102
6502
|
memset(e->anchor_placed, 0, e->anchor_placed_cap);
|
|
6103
6503
|
}
|
|
6104
|
-
e->
|
|
6504
|
+
e->alias_memo.len = 0;
|
|
6105
6505
|
}
|
|
6106
6506
|
if (emit_end) {
|
|
6107
6507
|
e_event_init(&ev, YEP_EV_STREAM_END);
|