yeptris 0.6.26.2-arm-linux-eabihf → 0.6.28.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/lib/yeptris.rb +1 -1
- data/libyeptris.so +0 -0
- data/vendor/libyeptris/CMakeLists.txt +1 -1
- data/vendor/libyeptris/src/yeptris/dom/ytape.c +1382 -19
- data/vendor/libyeptris/src/yeptris/dom/ytape.h +20 -1
- data/vendor/libyeptris/src/yeptris/parse.c +26 -2
- data/vendor/libyeptris/src/yeptris/scan/json.c +10 -7
- data/vendor/libyeptris/src/yeptris/tape.c +724 -395
- data/vendor/libyeptris/src/yeptris/tape_in.h +2 -1
- metadata +1 -1
|
@@ -19,8 +19,12 @@
|
|
|
19
19
|
|
|
20
20
|
#include "dom/dom.h"
|
|
21
21
|
#include "memory/allocator.h"
|
|
22
|
+
#include "memory/pool.h"
|
|
23
|
+
#include "resolve/resolver.h"
|
|
22
24
|
#include "scan/json.h"
|
|
23
25
|
#include "scan/scan.h"
|
|
26
|
+
#include "tape_in.h"
|
|
27
|
+
#include "yeptris/tape.h"
|
|
24
28
|
#include "ytape.h"
|
|
25
29
|
|
|
26
30
|
/* ---- word packing ---- */
|
|
@@ -58,6 +62,11 @@ int ytap_init(yep_ytape* t, const char* input, size_t len, int max_depth) {
|
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
void ytap_free(yep_ytape* t) {
|
|
65
|
+
if (t->flow_scratch != NULL) {
|
|
66
|
+
yeptris_tape_free((yeptris_json_tape*)t->flow_scratch);
|
|
67
|
+
yep_free(yep_system_allocator(), t->flow_scratch);
|
|
68
|
+
t->flow_scratch = NULL;
|
|
69
|
+
}
|
|
61
70
|
if (t->w != NULL) {
|
|
62
71
|
yep_free(yep_system_allocator(), t->w);
|
|
63
72
|
t->w = NULL;
|
|
@@ -315,36 +324,207 @@ static int yt_on_block_item(void* ctx, const yep_block_value* v) {
|
|
|
315
324
|
return 1;
|
|
316
325
|
}
|
|
317
326
|
|
|
327
|
+
/* the >1024 simple-key law, read off the scratch records: a STR at a
|
|
328
|
+
* map's key slot over the limit answers the general walk's long_key
|
|
329
|
+
* verdict (the fused walk carries no such flag). Members alternate
|
|
330
|
+
* key/value in a map frame; a container in the value slot completes
|
|
331
|
+
* at its CLOSE. len == 0xFFFFFF (a CONT-extended token, >16 MiB) is
|
|
332
|
+
* over the limit by definition. */
|
|
333
|
+
static uint32_t yt_flow_scan(const yeptris_json_tape* s, int* long_key) {
|
|
334
|
+
/* the record-walk verdicts the fused walk does not carry: the
|
|
335
|
+
* >1024 simple-key law (a STR at a map's key slot over the limit;
|
|
336
|
+
* the law counts the RAW token — a quoted key's record holds the
|
|
337
|
+
* INNER span, so the two quotes add back on; 0xFFFFFF = a
|
|
338
|
+
* CONT-extended >16 MiB token, over by definition) and the span's
|
|
339
|
+
* maximum nesting (the fused walk's depth cap is its own, not the
|
|
340
|
+
* engine's max_depth — the caller falls back when exceeded) */
|
|
341
|
+
struct {
|
|
342
|
+
uint8_t map;
|
|
343
|
+
uint8_t key_next;
|
|
344
|
+
} st[257];
|
|
345
|
+
int d = 0;
|
|
346
|
+
uint32_t maxd = 0;
|
|
347
|
+
st[0].map = 0;
|
|
348
|
+
st[0].key_next = 0;
|
|
349
|
+
for (uint32_t i = 1; i < s->count; i++) { /* recs[0] is the DOC */
|
|
350
|
+
uint64_t r = s->recs[i];
|
|
351
|
+
uint8_t kind = (uint8_t)(r & 0xFFu);
|
|
352
|
+
if (kind == YEP_T_MAP_OPEN || kind == YEP_T_SEQ_OPEN) {
|
|
353
|
+
if (d >= 256) {
|
|
354
|
+
*long_key = 0;
|
|
355
|
+
return 0xFFFFu; /* deeper than the scratch stack: the
|
|
356
|
+
* general kernel's depth path decides */
|
|
357
|
+
}
|
|
358
|
+
d++;
|
|
359
|
+
if ((uint32_t)d > maxd) {
|
|
360
|
+
maxd = (uint32_t)d;
|
|
361
|
+
}
|
|
362
|
+
st[d].map = (uint8_t)(kind == YEP_T_MAP_OPEN);
|
|
363
|
+
st[d].key_next = 0;
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
if (kind == YEP_T_CLOSE) {
|
|
367
|
+
if (d > 0) {
|
|
368
|
+
d--;
|
|
369
|
+
}
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
if (st[d].map && st[d].key_next == 0) {
|
|
373
|
+
uint32_t mlen = (uint32_t)(r >> 8) & 0xFFFFFFu;
|
|
374
|
+
if (kind == YEP_T_STR && mlen + 2u > 1024u) {
|
|
375
|
+
*long_key = 1;
|
|
376
|
+
}
|
|
377
|
+
st[d].key_next = 1;
|
|
378
|
+
} else if (st[d].map) {
|
|
379
|
+
st[d].key_next = 0;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return maxd;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
static int yt_flow_classify_record(yep_ytape* t, const char* p, size_t open, size_t len,
|
|
386
|
+
const yep_view* anchor, const yep_view* tag, uint32_t anchor_id,
|
|
387
|
+
int max_depth, size_t* close);
|
|
388
|
+
|
|
318
389
|
static int yt_on_flow_build(void* ctx, const char* p, size_t open, size_t len, uint32_t line,
|
|
319
390
|
size_t line_start, yep_view anchor, yep_view tag, uint32_t anchor_id,
|
|
320
391
|
int max_depth, size_t* close) {
|
|
321
392
|
(void)line;
|
|
322
393
|
(void)line_start; /* the flow builder reads neither */
|
|
323
|
-
|
|
394
|
+
return yt_flow_classify_record((yep_ytape*)ctx, p, open, len, &anchor, &tag, anchor_id,
|
|
395
|
+
max_depth, close);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/* the shared flow-span classification + ONE-record emission (the
|
|
399
|
+
* sink's entry and the flow-rooted fast path both land here). Returns
|
|
400
|
+
* the sink's verdict codes: 0 = not JSON-class (the general kernel),
|
|
401
|
+
* 1 = recorded (with *close set), 2 = long-key (pass 2 owns the
|
|
402
|
+
* error). */
|
|
403
|
+
static int yt_flow_classify_record(yep_ytape* t, const char* p, size_t open, size_t len,
|
|
404
|
+
const yep_view* anchor, const yep_view* tag, uint32_t anchor_id,
|
|
405
|
+
int max_depth, size_t* close) {
|
|
324
406
|
if (t->depth >= YEP_DOM_MAX_DEPTH) {
|
|
325
407
|
return 0; /* the event path owns the error shape */
|
|
326
408
|
}
|
|
327
409
|
/* classification = the DOM's own walk with the builds stripped:
|
|
328
410
|
* the same reject/long-key verdicts, then ONE record for the
|
|
329
411
|
* whole staged span (replay runs the full build through
|
|
330
|
-
* dom_on_flow_build).
|
|
412
|
+
* dom_on_flow_build). The verdict comes from the FUSED lenient
|
|
413
|
+
* walk into a reused scratch tape — 3.5x the naive token loop on
|
|
414
|
+
* the spike corpora (item 86); any refusal keeps the naive loop,
|
|
415
|
+
* whose accept/reject contract is the same by construction. */
|
|
416
|
+
if (t->flow_scratch == NULL) {
|
|
417
|
+
t->flow_scratch = yep_alloc(yep_system_allocator(), sizeof(yeptris_json_tape));
|
|
418
|
+
if (t->flow_scratch != NULL) {
|
|
419
|
+
memset(t->flow_scratch, 0, sizeof(yeptris_json_tape));
|
|
420
|
+
}
|
|
421
|
+
}
|
|
331
422
|
t->max_depth = max_depth; /* replay re-walks at the engine's limit */
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
423
|
+
/* the naive token loop with a BYTE BUDGET: small spans (the common
|
|
424
|
+
* per-line flow map) finish it — the loop carries the exact close
|
|
425
|
+
* and long_key verdicts for free; a budget exhaustion hands the
|
|
426
|
+
* span to the fused lenient walk, which amortizes its fixed entry
|
|
427
|
+
* cost on large spans (2.1x the naive loop at 6.6 MB, item 86) */
|
|
428
|
+
{
|
|
429
|
+
yep_json_walk w;
|
|
430
|
+
yep_json_tok tok;
|
|
431
|
+
yep_json_walk_init(&w, p, len, open, max_depth);
|
|
432
|
+
w.strict = t->flow_strict;
|
|
433
|
+
int exhausted = 0;
|
|
434
|
+
for (;;) {
|
|
435
|
+
if (w.i - open > 256) {
|
|
436
|
+
exhausted = 1;
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
439
|
+
yep_jw_status st = yep_json_walk_next(&w, &tok);
|
|
440
|
+
if (st == YEP_JW_REJECT) {
|
|
441
|
+
return 0; /* not JSON-class: the general kernel */
|
|
442
|
+
}
|
|
443
|
+
if (st == YEP_JW_DONE) {
|
|
444
|
+
if (w.long_key) {
|
|
445
|
+
return 2; /* pass 2 owns the simple-key error */
|
|
446
|
+
}
|
|
447
|
+
*close = w.close; /* the walk's own position: exact */
|
|
448
|
+
goto record;
|
|
449
|
+
}
|
|
340
450
|
}
|
|
341
|
-
if (
|
|
342
|
-
|
|
451
|
+
if (exhausted) {
|
|
452
|
+
yeptris_json_tape* s = t->flow_scratch;
|
|
453
|
+
if (s == NULL) {
|
|
454
|
+
s = (yeptris_json_tape*)yep_alloc(yep_system_allocator(),
|
|
455
|
+
sizeof(yeptris_json_tape));
|
|
456
|
+
if (s != NULL) {
|
|
457
|
+
memset(s, 0, sizeof(yeptris_json_tape));
|
|
458
|
+
t->flow_scratch = s;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
if (s != NULL) {
|
|
462
|
+
/* the carve reuses the block through the _srclen
|
|
463
|
+
* watermark — no per-span free (flow-json walks 200k
|
|
464
|
+
* spans per parse) */
|
|
465
|
+
/* strict_nums=1: the general walk validates number runs
|
|
466
|
+
* even at strict=0 (M5DY's 2001-07-02 dates — an
|
|
467
|
+
* unvalidated accept here diverges from the engine's
|
|
468
|
+
* own reject) */
|
|
469
|
+
if (s->_block != NULL && s->_srclen < len + 2) {
|
|
470
|
+
/* the block cannot hold this span: release it so the
|
|
471
|
+
* walk's carve sizes a fresh one (carve's own growth
|
|
472
|
+
* semantics belong to the strict route's live
|
|
473
|
+
* pointers) */
|
|
474
|
+
yeptris_tape_free(s);
|
|
475
|
+
memset(s, 0, sizeof(yeptris_json_tape));
|
|
476
|
+
}
|
|
477
|
+
if (yep_tape_walk_lenient_fused(p, len, open, s, 1, 0, 1) == YEPTRIS_OK) {
|
|
478
|
+
if (s->_srclen < len + 2) {
|
|
479
|
+
s->_srclen = len + 2; /* the reuse watermark */
|
|
480
|
+
}
|
|
481
|
+
int lk = 0;
|
|
482
|
+
uint32_t smax = yt_flow_scan(s, &lk);
|
|
483
|
+
if (lk) {
|
|
484
|
+
return 2; /* pass 2 owns the simple-key error */
|
|
485
|
+
}
|
|
486
|
+
if (smax > (uint32_t)max_depth) {
|
|
487
|
+
return 0; /* over the engine's depth limit: the
|
|
488
|
+
* general walk owns the exact DEPTH
|
|
489
|
+
* error shape */
|
|
490
|
+
}
|
|
491
|
+
goto record_fused;
|
|
492
|
+
}
|
|
493
|
+
return 0; /* the fused walk refused: the general kernel */
|
|
494
|
+
}
|
|
495
|
+
return 0; /* scratch alloc refused: the general kernel */
|
|
343
496
|
}
|
|
344
497
|
}
|
|
345
|
-
|
|
346
|
-
|
|
498
|
+
return -1; /* unreachable */
|
|
499
|
+
record_fused: {
|
|
500
|
+
size_t c = open;
|
|
501
|
+
int depth = 0;
|
|
502
|
+
for (;;) {
|
|
503
|
+
unsigned char ch = (unsigned char)p[c];
|
|
504
|
+
if (ch == '"') { /* the walk validated the string; skip runs */
|
|
505
|
+
c++;
|
|
506
|
+
while (p[c] != '"') {
|
|
507
|
+
if (p[c] == '\\') {
|
|
508
|
+
c++;
|
|
509
|
+
}
|
|
510
|
+
c++;
|
|
511
|
+
}
|
|
512
|
+
c++;
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
if (ch == '{' || ch == '[') {
|
|
516
|
+
depth++;
|
|
517
|
+
} else if (ch == '}' || ch == ']') {
|
|
518
|
+
depth--;
|
|
519
|
+
if (depth == 0) {
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
c++;
|
|
347
524
|
}
|
|
525
|
+
*close = c;
|
|
526
|
+
}
|
|
527
|
+
record:
|
|
348
528
|
t->flow_mark = t->count;
|
|
349
529
|
uint32_t anchor_hi = 0;
|
|
350
530
|
uint32_t aid = anchor_id;
|
|
@@ -352,8 +532,8 @@ static int yt_on_flow_build(void* ctx, const char* p, size_t open, size_t len, u
|
|
|
352
532
|
anchor_hi = 1;
|
|
353
533
|
aid = 0xFFFFFFu;
|
|
354
534
|
}
|
|
355
|
-
uint32_t tag_mode = (uint32_t)yt_mode(t,
|
|
356
|
-
uint32_t anchor_mode = (uint32_t)yt_mode(t,
|
|
535
|
+
uint32_t tag_mode = (uint32_t)yt_mode(t, tag);
|
|
536
|
+
uint32_t anchor_mode = (uint32_t)yt_mode(t, anchor);
|
|
357
537
|
uint32_t flags = tag_mode | (anchor_mode << 2) | (anchor_hi << 4);
|
|
358
538
|
if (yt_put(t, yt_props(YTP_FLOW, aid, flags)) != 0) {
|
|
359
539
|
return -1;
|
|
@@ -361,16 +541,15 @@ static int yt_on_flow_build(void* ctx, const char* p, size_t open, size_t len, u
|
|
|
361
541
|
if (yt_put(t, (uint64_t)open | ((uint64_t)len << 32)) != 0) {
|
|
362
542
|
return -1;
|
|
363
543
|
}
|
|
364
|
-
if (tag_mode != YTM_ABSENT && yt_span_by_mode(t,
|
|
544
|
+
if (tag_mode != YTM_ABSENT && yt_span_by_mode(t, tag) != 0) {
|
|
365
545
|
return -1;
|
|
366
546
|
}
|
|
367
|
-
if (anchor_mode != YTM_ABSENT && yt_span_by_mode(t,
|
|
547
|
+
if (anchor_mode != YTM_ABSENT && yt_span_by_mode(t, anchor) != 0) {
|
|
368
548
|
return -1;
|
|
369
549
|
}
|
|
370
550
|
if (anchor_hi && yt_put(t, (uint64_t)anchor_id) != 0) {
|
|
371
551
|
return -1;
|
|
372
552
|
}
|
|
373
|
-
*close = w.close;
|
|
374
553
|
return 1;
|
|
375
554
|
}
|
|
376
555
|
|
|
@@ -640,3 +819,1187 @@ int dom_from_ytape(yep_dom* d, const yep_ytape* t) {
|
|
|
640
819
|
}
|
|
641
820
|
return 0;
|
|
642
821
|
}
|
|
822
|
+
|
|
823
|
+
/* ---- the fused block runner (TODO.restructure/79, session 3) -------
|
|
824
|
+
*
|
|
825
|
+
* ONE SWAR sweep per line + inline classification + an indent stack,
|
|
826
|
+
* emitting the same record stream the engine's sink would — without
|
|
827
|
+
* the engine. Byte-exact against the engine over the block-family
|
|
828
|
+
* corpora (wide 600k / block 1.0M / deep 17k words, differential
|
|
829
|
+
* pinned by the FusedTape test). Any line the loop does not own bails
|
|
830
|
+
* to 1 and the caller re-runs the engine route (restart fallback).
|
|
831
|
+
*
|
|
832
|
+
* Bails (the engine route owns them): quoted/tagged/flow/folded/block
|
|
833
|
+
* scalar values, compact map items, anchored CONTAINER keys (the
|
|
834
|
+
* first pair inside one rides a two-SCALAR form with content-typed
|
|
835
|
+
* tag ids — capture before owning), doc markers/directives, empty
|
|
836
|
+
* "key:" at EOF or mid-doc, undefined aliases, root sequences. */
|
|
837
|
+
|
|
838
|
+
#define YT_FUSED_MAX_FRAMES 256
|
|
839
|
+
#define YT_FUSED_ANCHORS 65536
|
|
840
|
+
|
|
841
|
+
typedef struct {
|
|
842
|
+
uint32_t indent; /* the frame's key column */
|
|
843
|
+
uint8_t kind; /* 0 map, 1 seq */
|
|
844
|
+
uint8_t pending; /* a "key:" awaiting its child */
|
|
845
|
+
uint8_t started; /* the content container's start event went out */
|
|
846
|
+
uint8_t
|
|
847
|
+
own_map; /* the frame carries its own map (OPEN/root/seq); the key-SCALAR form does not */
|
|
848
|
+
uint8_t phantom; /* a content map opened by this frame's pairs is still live */
|
|
849
|
+
uint32_t content_col; /* the column this frame's pairs live at, +1 (0 = none) */
|
|
850
|
+
uint32_t key_off, key_len;
|
|
851
|
+
uint32_t aid; /* anchor ordinal on the pending container */
|
|
852
|
+
uint32_t a_off, a_len; /* the pending anchor's name span */
|
|
853
|
+
uint8_t anchored_first; /* the first pair/item rides the two-SCALAR form */
|
|
854
|
+
} yt_frame;
|
|
855
|
+
|
|
856
|
+
typedef struct {
|
|
857
|
+
yep_ytape* t;
|
|
858
|
+
const char* p;
|
|
859
|
+
size_t len;
|
|
860
|
+
uint32_t anchor_seq;
|
|
861
|
+
const yep_resolver* resolver; /* the first pair inside an anchored container
|
|
862
|
+
* bakes the engine's tag classification */
|
|
863
|
+
yep_pool* pool; /* block-scalar content (transferred to the doc) */
|
|
864
|
+
/* the repeat-alias memo (engine anchor_id_of): the last alias
|
|
865
|
+
* resolution answers by name bytes before any probe, and anchor
|
|
866
|
+
* definitions never invalidate it — re-aliasing after a
|
|
867
|
+
* redefinition still reports the memoized ordinal */
|
|
868
|
+
uint32_t memo_off, memo_len, memo_ord;
|
|
869
|
+
/* anchor name -> ordinal (the alias records carry the target's
|
|
870
|
+
* id; a miss bails: the engine owns undefined aliases). The table
|
|
871
|
+
* is heap-allocated on the first definition — small parses never
|
|
872
|
+
* pay for the 64k slots anchor-heavy documents need. */
|
|
873
|
+
struct {
|
|
874
|
+
uint32_t off, len, aid, tag;
|
|
875
|
+
}* anchors;
|
|
876
|
+
uint8_t* anchors_opened; /* per-aid: the anchored container's start event went out */
|
|
877
|
+
} yt_fused;
|
|
878
|
+
|
|
879
|
+
/* Frame model (engine-verified): st[] frames are the engine's *silent*
|
|
880
|
+
* containers — one OPEN record per frame (or one key SCALAR for the
|
|
881
|
+
* sibling form, which carries no map of its own). Pairs inside a frame
|
|
882
|
+
* open a *phantom* content map at the pair column (one start event per
|
|
883
|
+
* column); a later pair at the frame's own indent closes the phantom
|
|
884
|
+
* and rides the frame silently (the engine's sibling-continue). Maps
|
|
885
|
+
* pop strictly shallower; seqs also leave at their column when a
|
|
886
|
+
* non-dash arrives. The root closes only when its start event fired. */
|
|
887
|
+
|
|
888
|
+
/* chunked name hash: 8 bytes per round, one mix per round (the
|
|
889
|
+
* byte-wise FNV chain cost ~6 cycles/byte on this corpus's 80k
|
|
890
|
+
* lookups+puts per parse). The tail masks to the real bytes so only
|
|
891
|
+
* equal names hash equal. */
|
|
892
|
+
static uint32_t yt_anchor_hash(const char* p, uint32_t off, uint32_t len) {
|
|
893
|
+
uint64_t h = 2166136261u;
|
|
894
|
+
uint32_t i = 0;
|
|
895
|
+
for (; i < len;) {
|
|
896
|
+
uint32_t room = len - i;
|
|
897
|
+
uint64_t w;
|
|
898
|
+
if (room >= 8) {
|
|
899
|
+
memcpy(&w, p + off + i, 8);
|
|
900
|
+
i += 8;
|
|
901
|
+
} else {
|
|
902
|
+
uint64_t tail = 0;
|
|
903
|
+
memcpy(&tail, p + off + i, room);
|
|
904
|
+
w = tail;
|
|
905
|
+
i = len;
|
|
906
|
+
}
|
|
907
|
+
h = (h ^ w) * 11400714819323198485ull;
|
|
908
|
+
h ^= h >> 29;
|
|
909
|
+
}
|
|
910
|
+
return (uint32_t)(h ^ (h >> 32));
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
static int yt_anchor_table(yt_fused* F) {
|
|
914
|
+
if (F->anchors == NULL) {
|
|
915
|
+
F->anchors =
|
|
916
|
+
(void*)yep_alloc(yep_system_allocator(), YT_FUSED_ANCHORS * sizeof(*F->anchors));
|
|
917
|
+
if (F->anchors == NULL) {
|
|
918
|
+
return 0;
|
|
919
|
+
}
|
|
920
|
+
memset(F->anchors, 0, YT_FUSED_ANCHORS * sizeof(*F->anchors));
|
|
921
|
+
F->anchors_opened =
|
|
922
|
+
(void*)yep_alloc(yep_system_allocator(), YT_FUSED_ANCHORS * sizeof(uint8_t));
|
|
923
|
+
if (F->anchors_opened == NULL) {
|
|
924
|
+
return 0;
|
|
925
|
+
}
|
|
926
|
+
memset(F->anchors_opened, 0, YT_FUSED_ANCHORS * sizeof(uint8_t));
|
|
927
|
+
}
|
|
928
|
+
return 1;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
static void yt_anchor_open(yt_fused* F, uint32_t aid) {
|
|
932
|
+
if (F->anchors_opened != NULL && aid != 0 && aid <= YT_FUSED_ANCHORS) {
|
|
933
|
+
F->anchors_opened[aid - 1] = 1;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
static void yt_anchor_put(yt_fused* F, uint32_t off, uint32_t len, uint32_t aid) {
|
|
938
|
+
uint32_t m = YT_FUSED_ANCHORS - 1;
|
|
939
|
+
uint32_t tag = yt_anchor_hash(F->p, off, len);
|
|
940
|
+
uint32_t i = tag & m;
|
|
941
|
+
for (uint32_t n = 0; n < 64; n++) {
|
|
942
|
+
if (F->anchors[i].len == 0) {
|
|
943
|
+
F->anchors[i].off = off;
|
|
944
|
+
F->anchors[i].len = len;
|
|
945
|
+
F->anchors[i].aid = aid;
|
|
946
|
+
F->anchors[i].tag = tag;
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
if (F->anchors[i].tag == tag && F->anchors[i].len == len &&
|
|
950
|
+
memcmp(F->p + F->anchors[i].off, F->p + off, len) == 0) {
|
|
951
|
+
F->anchors[i].aid = aid; /* redefinition: latest wins */
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
i = (i + 1) & m;
|
|
955
|
+
}
|
|
956
|
+
/* chain too long: leave unfindable — aliases to it will bail */
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
static int yt_anchor_get(yt_fused* F, uint32_t off, uint32_t len, uint32_t* aid) {
|
|
960
|
+
if (F->anchors == NULL) {
|
|
961
|
+
return 0; /* no definitions yet: the engine owns the error */
|
|
962
|
+
}
|
|
963
|
+
if (F->memo_len != 0 && F->memo_len == len &&
|
|
964
|
+
memcmp(F->p + F->memo_off, F->p + off, len) == 0) {
|
|
965
|
+
*aid = F->memo_ord;
|
|
966
|
+
return 1;
|
|
967
|
+
}
|
|
968
|
+
uint32_t m = YT_FUSED_ANCHORS - 1;
|
|
969
|
+
uint32_t tag = yt_anchor_hash(F->p, off, len);
|
|
970
|
+
uint32_t i = tag & m;
|
|
971
|
+
for (uint32_t n = 0; n < 64; n++) {
|
|
972
|
+
if (F->anchors[i].len == 0) {
|
|
973
|
+
return 0;
|
|
974
|
+
}
|
|
975
|
+
if (F->anchors[i].tag == tag && F->anchors[i].len == len &&
|
|
976
|
+
memcmp(F->p + F->anchors[i].off, F->p + off, len) == 0) {
|
|
977
|
+
*aid = F->anchors[i].aid;
|
|
978
|
+
F->memo_off = off;
|
|
979
|
+
F->memo_len = len;
|
|
980
|
+
F->memo_ord = *aid;
|
|
981
|
+
return 1;
|
|
982
|
+
}
|
|
983
|
+
i = (i + 1) & m;
|
|
984
|
+
}
|
|
985
|
+
return 0;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
static void yt_f_empty_span(yt_fused* F) {
|
|
989
|
+
/* the dead value-span pair the container events always carry */
|
|
990
|
+
(void)yt_put(F->t, ((uint64_t)YTP_SPAN_POOL << 56) | 0u);
|
|
991
|
+
(void)yt_put(F->t, 0);
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
static void yt_f_start(yt_fused* F, yt_frame* fr) {
|
|
995
|
+
if (fr->started) {
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
fr->started = 1;
|
|
999
|
+
(void)yt_put(F->t, yt_props(YTP_EVENT, 0, fr->kind == 1 ? 5u : 7u));
|
|
1000
|
+
yt_f_empty_span(F);
|
|
1001
|
+
F->t->depth++;
|
|
1002
|
+
if (fr->kind == 0) {
|
|
1003
|
+
fr->phantom = 1;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
static void yt_f_close(yt_fused* F, uint8_t kind) {
|
|
1008
|
+
(void)yt_put(F->t, yt_props(YTP_EVENT, 0, kind == 1 ? 6u : 8u));
|
|
1009
|
+
yt_f_empty_span(F);
|
|
1010
|
+
F->t->depth--;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
/* the OPEN-vs-SCALAR key form: the engine opens via on_block_open
|
|
1014
|
+
* unless its top frame is already a map continuing at this key's
|
|
1015
|
+
* column (a sibling key) — the contentless root always opens */
|
|
1016
|
+
static uint8_t yt_f_open_form(const yt_frame* parent, int parent_is_root, uint32_t key_col) {
|
|
1017
|
+
if (parent_is_root && parent->content_col == 0) {
|
|
1018
|
+
return 1;
|
|
1019
|
+
}
|
|
1020
|
+
if (parent->content_col != 0) {
|
|
1021
|
+
return (uint8_t)(key_col + 1 != parent->content_col && key_col != parent->indent);
|
|
1022
|
+
}
|
|
1023
|
+
return (uint8_t)(key_col != parent->indent);
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
/* resolve a pending "key:": the OPEN record materializes the key's
|
|
1027
|
+
* map (it closes later); the SCALAR form is the bare key — the value
|
|
1028
|
+
* container that follows IS the pair's, no map of its own */
|
|
1029
|
+
static void yt_f_open(yt_fused* F, yt_frame* fr, uint8_t open_form) {
|
|
1030
|
+
if (open_form && fr->aid == 0 && fr->key_len < 0x1000000u && fr->key_off <= F->t->input_len) {
|
|
1031
|
+
(void)yt_put(F->t, yt_span_in(fr->key_off, fr->key_len, YTP_OPEN));
|
|
1032
|
+
fr->own_map = 1;
|
|
1033
|
+
} else {
|
|
1034
|
+
(void)yt_put(F->t, yt_props(YTP_SCALAR, 0, 0x2900u));
|
|
1035
|
+
(void)yt_put(F->t, yt_span_in(fr->key_off, fr->key_len, YTP_SPAN_IN));
|
|
1036
|
+
fr->own_map = 0;
|
|
1037
|
+
}
|
|
1038
|
+
fr->started = 0;
|
|
1039
|
+
fr->phantom = 0;
|
|
1040
|
+
F->t->depth++;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
/* The flat-map specialist (item 86): plain `key: value` lines at one
|
|
1044
|
+
* fixed content column, one map frame, nothing else. A separate FUNCTION
|
|
1045
|
+
* so its code stays inside the I-cache — the equivalent inline loop
|
|
1046
|
+
* measured 26% SLOWER by bloating yt_f_run past the cache edge. Returns
|
|
1047
|
+
* the position it stopped at; the caller reprocesses that line through
|
|
1048
|
+
* the full arms, so every bail here is a strict subset of what yt_f_run
|
|
1049
|
+
* would decide — parity holds by construction. */
|
|
1050
|
+
static size_t yt_flat_run(yep_ytape* t, const char* p, size_t pos, size_t len, uint32_t run_cc) {
|
|
1051
|
+
const uint64_t k_nl = 0x0A0A0A0A0A0A0A0Aull, k_cr = 0x0D0D0D0D0D0D0D0Dull,
|
|
1052
|
+
k_sp = 0x2020202020202020ull, k_co = 0x3A3A3A3A3A3A3A3Aull,
|
|
1053
|
+
k_ha = 0x2323232323232323ull;
|
|
1054
|
+
for (;;) {
|
|
1055
|
+
if (pos >= len) {
|
|
1056
|
+
return pos;
|
|
1057
|
+
}
|
|
1058
|
+
/* the sweep: the main loop's line facts, unchanged */
|
|
1059
|
+
size_t whole = len - pos;
|
|
1060
|
+
size_t end = whole, ind = whole;
|
|
1061
|
+
int have_ind = 0;
|
|
1062
|
+
size_t i = 0;
|
|
1063
|
+
size_t stop = whole;
|
|
1064
|
+
int stop_set = 0;
|
|
1065
|
+
while (i < whole) {
|
|
1066
|
+
size_t avail = whole - i < 8 ? whole - i : 8;
|
|
1067
|
+
uint64_t x;
|
|
1068
|
+
if (avail == 8) {
|
|
1069
|
+
memcpy(&x, p + pos + i, 8);
|
|
1070
|
+
} else {
|
|
1071
|
+
char buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
|
1072
|
+
memcpy(buf, p + pos + i, avail);
|
|
1073
|
+
memcpy(&x, buf, 8);
|
|
1074
|
+
}
|
|
1075
|
+
uint64_t valid = avail == 8 ? ~(uint64_t)0 : (((uint64_t)1 << (avail * 8)) - 1);
|
|
1076
|
+
uint64_t br = (yep_swar_eq8(x, k_nl) | yep_swar_eq8(x, k_cr)) & valid;
|
|
1077
|
+
uint64_t room = (br ? ((br & (~br + 1)) - 1) : valid) & YEP_SWAR_FLAGS & valid;
|
|
1078
|
+
if (!have_ind) {
|
|
1079
|
+
uint64_t nons = ~(yep_swar_eq8(x, k_sp)) & room;
|
|
1080
|
+
if (nons) {
|
|
1081
|
+
ind = i + (size_t)(yep_ctz64(nons) >> 3);
|
|
1082
|
+
have_ind = 1;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
if (have_ind && !stop_set) {
|
|
1086
|
+
uint64_t stm = (yep_swar_eq8(x, k_co) | yep_swar_eq8(x, k_ha)) & room;
|
|
1087
|
+
if (stm) {
|
|
1088
|
+
size_t cand = i + (size_t)(yep_ctz64(stm) >> 3);
|
|
1089
|
+
if (cand >= ind) {
|
|
1090
|
+
stop = cand;
|
|
1091
|
+
stop_set = 1;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
if (br) {
|
|
1096
|
+
end = i + (size_t)(yep_ctz64(br) >> 3);
|
|
1097
|
+
break;
|
|
1098
|
+
}
|
|
1099
|
+
i += 8;
|
|
1100
|
+
}
|
|
1101
|
+
if (!have_ind) {
|
|
1102
|
+
ind = end;
|
|
1103
|
+
}
|
|
1104
|
+
if (!stop_set) {
|
|
1105
|
+
stop = end;
|
|
1106
|
+
}
|
|
1107
|
+
uint32_t le = (uint32_t)(pos + end);
|
|
1108
|
+
uint32_t li = (uint32_t)(pos + ind);
|
|
1109
|
+
uint32_t ls = (uint32_t)(pos + stop);
|
|
1110
|
+
uint32_t col = (uint32_t)(li - pos);
|
|
1111
|
+
/* blank and comment lines ride silently — the main loop skips
|
|
1112
|
+
* them with no state change */
|
|
1113
|
+
if (ind >= end || (p[li] == '#' && (li == 0 || p[li - 1] == ' ' || p[li - 1] == '\t' ||
|
|
1114
|
+
p[li - 1] == '\n'))) {
|
|
1115
|
+
pos = le < len ? (size_t)le + 1 : len;
|
|
1116
|
+
continue;
|
|
1117
|
+
}
|
|
1118
|
+
if (col + 1 != run_cc) {
|
|
1119
|
+
return pos; /* off-column: the pop/nest logic owns it */
|
|
1120
|
+
}
|
|
1121
|
+
unsigned char c = (unsigned char)p[li];
|
|
1122
|
+
if (c == '\t' || c == '-' || c == '&' || c == '!' || c == '*' || c == '\'' || c == '"' ||
|
|
1123
|
+
c == '[' || c == '{' || c == '|' || c == '>' || c == '%' || c == '?') {
|
|
1124
|
+
return pos; /* indicators, tab-led: the full arms */
|
|
1125
|
+
}
|
|
1126
|
+
if (!stop_set || p[ls] != ':' || (ls + 1 < le && p[ls + 1] != ' ' && p[ls + 1] != '\t')) {
|
|
1127
|
+
return pos; /* not a plain key: value line */
|
|
1128
|
+
}
|
|
1129
|
+
size_t t0 = li;
|
|
1130
|
+
uint32_t kend = ls;
|
|
1131
|
+
while (kend > t0 && (p[kend - 1] == ' ' || p[kend - 1] == '\t')) {
|
|
1132
|
+
kend--;
|
|
1133
|
+
}
|
|
1134
|
+
if (kend == t0 || (uint32_t)(kend - t0) > 1024u) {
|
|
1135
|
+
return pos; /* empty key / the simple-key length law */
|
|
1136
|
+
}
|
|
1137
|
+
size_t vt = ls + 1;
|
|
1138
|
+
while (vt < le && (p[vt] == ' ' || p[vt] == '\t')) {
|
|
1139
|
+
vt++;
|
|
1140
|
+
}
|
|
1141
|
+
if (vt >= le || p[vt] == '#') {
|
|
1142
|
+
return pos; /* "key:" pending: the main loop's frame arm */
|
|
1143
|
+
}
|
|
1144
|
+
unsigned char vc = (unsigned char)p[vt];
|
|
1145
|
+
if (vc == '"' || vc == '\'') {
|
|
1146
|
+
/* the quoted plain-value arm, same law as the main loop:
|
|
1147
|
+
* same-line close, no backslash, no '' doubling, a comment
|
|
1148
|
+
* needs separating whitespace */
|
|
1149
|
+
size_t ce = vt + 1;
|
|
1150
|
+
int esc = 0;
|
|
1151
|
+
while (ce < le) {
|
|
1152
|
+
if (p[ce] == '\\') {
|
|
1153
|
+
esc = 1;
|
|
1154
|
+
break;
|
|
1155
|
+
}
|
|
1156
|
+
if (p[ce] == vc) {
|
|
1157
|
+
break;
|
|
1158
|
+
}
|
|
1159
|
+
ce++;
|
|
1160
|
+
}
|
|
1161
|
+
if (ce >= le || esc) {
|
|
1162
|
+
return pos; /* unterminated or escaped: the engine */
|
|
1163
|
+
}
|
|
1164
|
+
if (vc == '\'' && ce + 1 < le && p[ce + 1] == '\'') {
|
|
1165
|
+
return pos; /* the '' escape: the engine */
|
|
1166
|
+
}
|
|
1167
|
+
size_t te = ce + 1;
|
|
1168
|
+
while (te < le && (p[te] == ' ' || p[te] == '\t')) {
|
|
1169
|
+
te++;
|
|
1170
|
+
}
|
|
1171
|
+
if (te < le && (p[te] != '#' || te == ce + 1)) {
|
|
1172
|
+
return pos; /* trailing content after the close */
|
|
1173
|
+
}
|
|
1174
|
+
(void)yt_put(t, yt_props(YTP_SCALAR, 0, 0x2900u));
|
|
1175
|
+
(void)yt_put(t, yt_span_in((uint32_t)t0, kend - (uint32_t)t0, YTP_SPAN_IN));
|
|
1176
|
+
(void)yt_put(t, yt_props(YTP_SCALAR, 0, vc == '"' ? 0x2300u : 0x2200u));
|
|
1177
|
+
(void)yt_put(t, yt_span_in((uint32_t)(vt + 1), (uint32_t)(ce - vt - 1), YTP_SPAN_IN));
|
|
1178
|
+
pos = le < len ? (size_t)le + 1 : len;
|
|
1179
|
+
continue;
|
|
1180
|
+
}
|
|
1181
|
+
if (vc == '*' || vc == '|' || vc == '>' || vc == '[' || vc == '{' || vc == '!' ||
|
|
1182
|
+
vc == '%' || vc == '&' ||
|
|
1183
|
+
((vc == '-' || vc == '?') &&
|
|
1184
|
+
(vt + 1 >= le || p[vt + 1] == ' ' || p[vt + 1] == '\t' || p[vt + 1] == '#'))) {
|
|
1185
|
+
return pos; /* block/flow/anchor values: the full arms */
|
|
1186
|
+
}
|
|
1187
|
+
/* a terminating ':' inside the value is the mapping-values error */
|
|
1188
|
+
{
|
|
1189
|
+
const char* h = (const char*)memchr(p + vt, ':', le - vt);
|
|
1190
|
+
while (h != NULL) {
|
|
1191
|
+
if (h + 1 >= p + le || h[1] == ' ' || h[1] == '\t') {
|
|
1192
|
+
return pos; /* the engine's error route */
|
|
1193
|
+
}
|
|
1194
|
+
h = (const char*)memchr(h + 1, ':', le - (size_t)(h + 1 - p));
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
uint32_t vend = le;
|
|
1198
|
+
{
|
|
1199
|
+
const char* hh = (const char*)memchr(p + vt, '#', le - vt);
|
|
1200
|
+
while (hh != NULL) {
|
|
1201
|
+
if (hh > p + vt && (hh[-1] == ' ' || hh[-1] == '\t')) {
|
|
1202
|
+
vend = (uint32_t)(hh - p);
|
|
1203
|
+
break;
|
|
1204
|
+
}
|
|
1205
|
+
hh = (const char*)memchr(hh + 1, '#', le - (size_t)(hh + 1 - p));
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
while (vend > vt && (p[vend - 1] == ' ' || p[vend - 1] == '\t')) {
|
|
1209
|
+
vend--;
|
|
1210
|
+
}
|
|
1211
|
+
(void)yt_put(t, yt_props(YTP_PAIR, 0, 2u | (1u << 3)));
|
|
1212
|
+
(void)yt_put(t, yt_span_in((uint32_t)t0, kend - (uint32_t)t0, YTP_SPAN_IN));
|
|
1213
|
+
(void)yt_put(t, yt_span_in((uint32_t)vt, vend - (uint32_t)vt, YTP_SPAN_IN));
|
|
1214
|
+
pos = le < len ? (size_t)le + 1 : len;
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
static int yt_f_run(yt_fused* F) {
|
|
1219
|
+
const char* p = F->p;
|
|
1220
|
+
size_t len = F->len;
|
|
1221
|
+
yep_ytape* t = F->t;
|
|
1222
|
+
yt_frame st[YT_FUSED_MAX_FRAMES];
|
|
1223
|
+
int depth = 0;
|
|
1224
|
+
memset(&st[0], 0, sizeof(st[0]));
|
|
1225
|
+
st[0].started = 1; /* the root's start event defers to its first pair */
|
|
1226
|
+
int root_open = 0;
|
|
1227
|
+
int root_evented = 0;
|
|
1228
|
+
(void)yt_put(t, ((uint64_t)YTP_EV_COMPACT << 56) | 1u);
|
|
1229
|
+
(void)yt_put(t, ((uint64_t)YTP_EV_COMPACT << 56) | 3u);
|
|
1230
|
+
size_t pos = 0;
|
|
1231
|
+
while (pos < len) {
|
|
1232
|
+
/* the sweep: one NUL-padded SWAR walk per line */
|
|
1233
|
+
const uint64_t k_nl = 0x0A0A0A0A0A0A0A0Aull, k_cr = 0x0D0D0D0D0D0D0D0Dull,
|
|
1234
|
+
k_sp = 0x2020202020202020ull, k_co = 0x3A3A3A3A3A3A3A3Aull,
|
|
1235
|
+
k_ha = 0x2323232323232323ull;
|
|
1236
|
+
size_t whole = len - pos;
|
|
1237
|
+
size_t end = whole, indent = whole, stop = whole;
|
|
1238
|
+
int have_indent = 0, stop_set = 0;
|
|
1239
|
+
size_t i = 0;
|
|
1240
|
+
while (i < whole) {
|
|
1241
|
+
size_t avail = whole - i < 8 ? whole - i : 8;
|
|
1242
|
+
uint64_t x;
|
|
1243
|
+
if (avail == 8) {
|
|
1244
|
+
memcpy(&x, p + pos + i, 8);
|
|
1245
|
+
} else {
|
|
1246
|
+
char buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
|
1247
|
+
memcpy(buf, p + pos + i, avail);
|
|
1248
|
+
memcpy(&x, buf, 8);
|
|
1249
|
+
}
|
|
1250
|
+
uint64_t valid = avail == 8 ? ~(uint64_t)0 : (((uint64_t)1 << (avail * 8)) - 1);
|
|
1251
|
+
uint64_t br = (yep_swar_eq8(x, k_nl) | yep_swar_eq8(x, k_cr)) & valid;
|
|
1252
|
+
uint64_t room = (br ? ((br & (~br + 1)) - 1) : valid) & YEP_SWAR_FLAGS & valid;
|
|
1253
|
+
if (!have_indent) {
|
|
1254
|
+
uint64_t nons = ~(yep_swar_eq8(x, k_sp)) & room;
|
|
1255
|
+
if (nons) {
|
|
1256
|
+
indent = i + (size_t)(yep_ctz64(nons) >> 3);
|
|
1257
|
+
have_indent = 1;
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
if (have_indent && !stop_set) {
|
|
1261
|
+
uint64_t stm = (yep_swar_eq8(x, k_co) | yep_swar_eq8(x, k_ha)) & room;
|
|
1262
|
+
if (stm) {
|
|
1263
|
+
size_t cand = i + (size_t)(yep_ctz64(stm) >> 3);
|
|
1264
|
+
if (cand >= indent) {
|
|
1265
|
+
stop = cand;
|
|
1266
|
+
stop_set = 1;
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
if (br) {
|
|
1271
|
+
end = i + (size_t)(yep_ctz64(br) >> 3);
|
|
1272
|
+
break;
|
|
1273
|
+
}
|
|
1274
|
+
i += 8;
|
|
1275
|
+
}
|
|
1276
|
+
if (!have_indent) {
|
|
1277
|
+
indent = end;
|
|
1278
|
+
}
|
|
1279
|
+
if (!stop_set) {
|
|
1280
|
+
stop = end;
|
|
1281
|
+
}
|
|
1282
|
+
uint32_t line_end = (uint32_t)(pos + end);
|
|
1283
|
+
uint32_t line_indent = (uint32_t)(pos + indent);
|
|
1284
|
+
uint32_t line_stop = (uint32_t)(pos + stop);
|
|
1285
|
+
uint8_t blank = (uint8_t)(indent >= end);
|
|
1286
|
+
unsigned char c = blank ? 0 : (unsigned char)p[line_indent];
|
|
1287
|
+
uint8_t comment =
|
|
1288
|
+
(uint8_t)(c == '#' && (line_indent == 0 || p[line_indent - 1] == ' ' ||
|
|
1289
|
+
p[line_indent - 1] == '\t' || p[line_indent - 1] == '\n'));
|
|
1290
|
+
uint8_t dash = 0;
|
|
1291
|
+
if (c == '-' && line_indent + 1 < line_end) {
|
|
1292
|
+
unsigned char n1 = (unsigned char)p[line_indent + 1];
|
|
1293
|
+
if (n1 == ' ' || n1 == '\t') {
|
|
1294
|
+
dash = 1;
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
size_t next = line_end < len ? (size_t)line_end + 1 : len;
|
|
1298
|
+
if (!blank && !comment) {
|
|
1299
|
+
size_t t0 = line_indent;
|
|
1300
|
+
uint32_t col = (uint32_t)(line_indent - pos);
|
|
1301
|
+
if (c == '\t') {
|
|
1302
|
+
return 1; /* tab-led content: the engine's error */
|
|
1303
|
+
}
|
|
1304
|
+
if (dash && depth > 0 && st[depth].pending && col >= st[depth].indent) {
|
|
1305
|
+
/* the pending key resolves into a sequence: its own
|
|
1306
|
+
* frame (the key's map survives below it) */
|
|
1307
|
+
if (depth >= YT_FUSED_MAX_FRAMES - 1) {
|
|
1308
|
+
return 1; /* the frame stack is full: the engine route */
|
|
1309
|
+
}
|
|
1310
|
+
int anchored = st[depth].aid != 0;
|
|
1311
|
+
if (anchored) {
|
|
1312
|
+
if (col == st[depth].indent) {
|
|
1313
|
+
return 1; /* indentless anchored seq: the engine owns it
|
|
1314
|
+
* (the frame-close pairing assumes the seq's
|
|
1315
|
+
* own column, deeper than the key's) */
|
|
1316
|
+
}
|
|
1317
|
+
/* anchored sequence: S2900 key + the anchored SEQ start */
|
|
1318
|
+
if (depth == 1) {
|
|
1319
|
+
if (!root_open) {
|
|
1320
|
+
(void)yt_put(t, yt_props(YTP_EVENT, 0, 7u));
|
|
1321
|
+
yt_f_empty_span(F);
|
|
1322
|
+
t->depth++;
|
|
1323
|
+
root_open = 1;
|
|
1324
|
+
root_evented = 1;
|
|
1325
|
+
st[0].started = 1;
|
|
1326
|
+
}
|
|
1327
|
+
} else if (!st[depth - 1].started && col != st[depth - 1].indent) {
|
|
1328
|
+
yt_f_start(F, &st[depth - 1]);
|
|
1329
|
+
}
|
|
1330
|
+
uint32_t xaid = st[depth].aid;
|
|
1331
|
+
uint32_t xoff = st[depth].a_off;
|
|
1332
|
+
uint32_t xlen = st[depth].a_len;
|
|
1333
|
+
(void)yt_put(t, yt_props(YTP_SCALAR, 0, 0x2900u));
|
|
1334
|
+
(void)yt_put(t, yt_span_in(st[depth].key_off, st[depth].key_len, YTP_SPAN_IN));
|
|
1335
|
+
(void)yt_put(t, yt_props(YTP_EVENT, xaid, 5u | (1u << 13)));
|
|
1336
|
+
yt_f_empty_span(F);
|
|
1337
|
+
(void)yt_put(t, yt_span_in(xoff, xlen, YTP_SPAN_IN));
|
|
1338
|
+
yt_anchor_open(F, xaid);
|
|
1339
|
+
st[depth].pending = 0; /* the seq frame shadows this slot */
|
|
1340
|
+
} else {
|
|
1341
|
+
uint8_t of = yt_f_open_form(&st[depth - 1], depth == 1, st[depth].indent);
|
|
1342
|
+
yt_f_open(F, &st[depth], of);
|
|
1343
|
+
root_open = 1;
|
|
1344
|
+
st[depth].pending = 0;
|
|
1345
|
+
}
|
|
1346
|
+
depth++;
|
|
1347
|
+
memset(&st[depth], 0, sizeof(st[depth]));
|
|
1348
|
+
st[depth].kind = 1;
|
|
1349
|
+
st[depth].indent = col;
|
|
1350
|
+
st[depth].own_map = 1;
|
|
1351
|
+
st[depth].anchored_first = (uint8_t)anchored;
|
|
1352
|
+
if (anchored) {
|
|
1353
|
+
st[depth].started = 1; /* the E5 went out above */
|
|
1354
|
+
} else {
|
|
1355
|
+
yt_f_start(F, &st[depth]);
|
|
1356
|
+
}
|
|
1357
|
+
} else {
|
|
1358
|
+
while (depth > 0 && (st[depth].kind == 1 ? (col < st[depth].indent ||
|
|
1359
|
+
(col <= st[depth].indent && !dash))
|
|
1360
|
+
: col < st[depth].indent)) {
|
|
1361
|
+
if (st[depth].pending) {
|
|
1362
|
+
return 1; /* empty "key:" mid-doc: the engine owns it */
|
|
1363
|
+
}
|
|
1364
|
+
if (st[depth].phantom) {
|
|
1365
|
+
yt_f_close(F, st[depth].kind);
|
|
1366
|
+
st[depth].phantom = 0;
|
|
1367
|
+
}
|
|
1368
|
+
if (st[depth].own_map) {
|
|
1369
|
+
yt_f_close(F, st[depth].kind);
|
|
1370
|
+
}
|
|
1371
|
+
depth--;
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
if (dash) {
|
|
1375
|
+
if (st[depth].kind == 1 && col == st[depth].indent) {
|
|
1376
|
+
yt_f_start(F, &st[depth]);
|
|
1377
|
+
size_t vt = t0 + 1;
|
|
1378
|
+
while (vt < line_end && (p[vt] == ' ' || p[vt] == '\t')) {
|
|
1379
|
+
vt++;
|
|
1380
|
+
}
|
|
1381
|
+
uint32_t vend = line_end;
|
|
1382
|
+
while (vend > vt && (p[vend - 1] == ' ' || p[vend - 1] == '\t')) {
|
|
1383
|
+
vend--;
|
|
1384
|
+
}
|
|
1385
|
+
if (vend == vt) {
|
|
1386
|
+
return 1; /* empty item */
|
|
1387
|
+
}
|
|
1388
|
+
unsigned char vc = (unsigned char)p[vt];
|
|
1389
|
+
if (vc == '"' || vc == '\'' || vc == '*' || vc == '&' || vc == '[' ||
|
|
1390
|
+
vc == '{' || vc == '!' || vc == '|' || vc == '>' || vc == '%' ||
|
|
1391
|
+
vc == '?') {
|
|
1392
|
+
return 1;
|
|
1393
|
+
}
|
|
1394
|
+
if (vc == '-' && vt + 1 < line_end && (p[vt + 1] == ' ' || p[vt + 1] == '\t')) {
|
|
1395
|
+
return 1; /* nested dash: the engine's nested seq */
|
|
1396
|
+
}
|
|
1397
|
+
/* compact map item "- k: v"? */
|
|
1398
|
+
for (size_t ic = vt; ic < vend; ic++) {
|
|
1399
|
+
if (p[ic] == ':') {
|
|
1400
|
+
size_t nn = ic + 1;
|
|
1401
|
+
if (nn >= vend || p[nn] == ' ' || p[nn] == '\t') {
|
|
1402
|
+
return 1; /* compact items: the engine */
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
if (st[depth].anchored_first && F->resolver != NULL) {
|
|
1407
|
+
yep_tag_id tid =
|
|
1408
|
+
F->resolver->resolve(F->resolver->ctx, p + vt, (uint32_t)(vend - vt));
|
|
1409
|
+
(void)yt_put(t, yt_props(YTP_SCALAR, 0, 0x2900u | (uint32_t)tid));
|
|
1410
|
+
(void)yt_put(t, yt_span_in((uint32_t)vt, vend - (uint32_t)vt, YTP_SPAN_IN));
|
|
1411
|
+
st[depth].anchored_first = 0;
|
|
1412
|
+
} else {
|
|
1413
|
+
(void)yt_put(t, yt_span_in((uint32_t)vt, vend - (uint32_t)vt, YTP_ITEM));
|
|
1414
|
+
}
|
|
1415
|
+
if (!st[depth].content_col) {
|
|
1416
|
+
st[depth].content_col = col + 1;
|
|
1417
|
+
}
|
|
1418
|
+
} else {
|
|
1419
|
+
return 1;
|
|
1420
|
+
}
|
|
1421
|
+
} else if (stop_set && p[line_stop] == ':' &&
|
|
1422
|
+
(line_stop + 1 >= line_end || p[line_stop + 1] == ' ' ||
|
|
1423
|
+
p[line_stop + 1] == '\t') &&
|
|
1424
|
+
!(c == '&' || c == '!' || c == '*' || c == '\'' || c == '"' || c == '[' ||
|
|
1425
|
+
c == '{' || c == '|' || c == '>' || c == '%' || c == '?' || c == '-')) {
|
|
1426
|
+
uint32_t kend = line_stop;
|
|
1427
|
+
while (kend > t0 && (p[kend - 1] == ' ' || p[kend - 1] == '\t')) {
|
|
1428
|
+
kend--;
|
|
1429
|
+
}
|
|
1430
|
+
if (kend == t0) {
|
|
1431
|
+
return 1; /* empty plain key (": v"): the engine's two-scalar form */
|
|
1432
|
+
}
|
|
1433
|
+
if ((uint32_t)(kend - t0) > 1024u) {
|
|
1434
|
+
return 1; /* the simple-key length law: the engine errors */
|
|
1435
|
+
}
|
|
1436
|
+
size_t vt = line_stop + 1;
|
|
1437
|
+
while (vt < line_end && (p[vt] == ' ' || p[vt] == '\t')) {
|
|
1438
|
+
vt++;
|
|
1439
|
+
}
|
|
1440
|
+
uint32_t aoff = 0, alen = 0, aid = 0;
|
|
1441
|
+
if (vt < line_end && p[vt] == '&') {
|
|
1442
|
+
size_t ne = vt + 1;
|
|
1443
|
+
while (ne < line_end && ne < len) {
|
|
1444
|
+
unsigned char pc = (unsigned char)p[ne];
|
|
1445
|
+
if (pc <= ' ' || pc == ',' || pc == '[' || pc == ']' || pc == '{' ||
|
|
1446
|
+
pc == '}' || pc == '#') {
|
|
1447
|
+
break;
|
|
1448
|
+
}
|
|
1449
|
+
ne++;
|
|
1450
|
+
}
|
|
1451
|
+
aoff = (uint32_t)(vt + 1);
|
|
1452
|
+
alen = (uint32_t)(ne - vt - 1);
|
|
1453
|
+
F->anchor_seq++;
|
|
1454
|
+
aid = F->anchor_seq;
|
|
1455
|
+
if (!yt_anchor_table(F)) {
|
|
1456
|
+
return 1;
|
|
1457
|
+
}
|
|
1458
|
+
yt_anchor_put(F, aoff, alen, aid);
|
|
1459
|
+
vt = ne;
|
|
1460
|
+
while (vt < line_end && (p[vt] == ' ' || p[vt] == '\t')) {
|
|
1461
|
+
vt++;
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
if (vt >= line_end || p[vt] == '#') {
|
|
1465
|
+
/* "key:" with a following-lines container: push pending
|
|
1466
|
+
* (aid rides it: an anchored container resolves through
|
|
1467
|
+
* the S2900 + anchored-start form, not on_block_open) */
|
|
1468
|
+
if (st[depth].kind == 0 && st[depth].content_col != 0 &&
|
|
1469
|
+
col + 1 != st[depth].content_col && col != st[depth].indent) {
|
|
1470
|
+
return 1; /* off-column: a continuation line — the multiline arm */
|
|
1471
|
+
}
|
|
1472
|
+
if (st[depth].kind == 0 && st[depth].content_col != 0 &&
|
|
1473
|
+
col + 1 != st[depth].content_col && st[depth].phantom) {
|
|
1474
|
+
yt_f_close(F, st[depth].kind);
|
|
1475
|
+
st[depth].phantom = 0;
|
|
1476
|
+
}
|
|
1477
|
+
if (depth > 0 && st[depth].pending) {
|
|
1478
|
+
uint8_t of = yt_f_open_form(&st[depth - 1], depth == 1, st[depth].indent);
|
|
1479
|
+
yt_f_open(F, &st[depth], of);
|
|
1480
|
+
root_open = 1;
|
|
1481
|
+
st[depth].pending = 0;
|
|
1482
|
+
}
|
|
1483
|
+
/* a spent key-SCALAR frame (resolved, phantom closed,
|
|
1484
|
+
* no map of its own) gives its slot to the sibling —
|
|
1485
|
+
* chained same-column pendings would otherwise grow
|
|
1486
|
+
* the stack by one per record (the frame-full bail) */
|
|
1487
|
+
if (!(depth > 0 && !st[depth].pending && !st[depth].phantom &&
|
|
1488
|
+
!st[depth].own_map)) {
|
|
1489
|
+
if (depth >= YT_FUSED_MAX_FRAMES - 1) {
|
|
1490
|
+
return 1;
|
|
1491
|
+
}
|
|
1492
|
+
depth++;
|
|
1493
|
+
}
|
|
1494
|
+
memset(&st[depth], 0, sizeof(st[depth]));
|
|
1495
|
+
st[depth].indent = col;
|
|
1496
|
+
st[depth].pending = 1;
|
|
1497
|
+
st[depth].key_off = (uint32_t)t0;
|
|
1498
|
+
st[depth].key_len = kend - (uint32_t)t0;
|
|
1499
|
+
st[depth].aid = aid;
|
|
1500
|
+
st[depth].a_off = aoff;
|
|
1501
|
+
st[depth].a_len = alen;
|
|
1502
|
+
st[depth].anchored_first = (uint8_t)(aid != 0);
|
|
1503
|
+
} else {
|
|
1504
|
+
if (st[depth].kind == 0 && st[depth].content_col != 0 &&
|
|
1505
|
+
col + 1 != st[depth].content_col && col != st[depth].indent) {
|
|
1506
|
+
return 1; /* off-column: a continuation line — the multiline arm */
|
|
1507
|
+
}
|
|
1508
|
+
if (depth > 0 && st[depth].pending && st[depth].aid != 0) {
|
|
1509
|
+
if (col <= st[depth].indent) {
|
|
1510
|
+
return 1; /* same-column "content": the anchored value is
|
|
1511
|
+
* null and this line is a sibling — the engine */
|
|
1512
|
+
}
|
|
1513
|
+
/* an anchored container resolves through the event
|
|
1514
|
+
* path: the parent's content map opens for the key
|
|
1515
|
+
* first, then the key SCALAR + the anchored start */
|
|
1516
|
+
if (depth == 1) {
|
|
1517
|
+
if (!root_open) {
|
|
1518
|
+
(void)yt_put(t, yt_props(YTP_EVENT, 0, 7u));
|
|
1519
|
+
yt_f_empty_span(F);
|
|
1520
|
+
t->depth++;
|
|
1521
|
+
root_open = 1;
|
|
1522
|
+
root_evented = 1;
|
|
1523
|
+
st[0].started = 1;
|
|
1524
|
+
}
|
|
1525
|
+
/* the root now has content: later sibling pendings
|
|
1526
|
+
* take the key-SCALAR form, not OPEN */
|
|
1527
|
+
if (st[0].content_col == 0) {
|
|
1528
|
+
st[0].content_col = st[depth].indent + 1;
|
|
1529
|
+
}
|
|
1530
|
+
} else if (!st[depth - 1].started && col != st[depth - 1].indent) {
|
|
1531
|
+
yt_f_start(F, &st[depth - 1]);
|
|
1532
|
+
}
|
|
1533
|
+
uint32_t xaid = st[depth].aid;
|
|
1534
|
+
uint32_t xoff = st[depth].a_off;
|
|
1535
|
+
uint32_t xlen = st[depth].a_len;
|
|
1536
|
+
(void)yt_put(t, yt_props(YTP_SCALAR, 0, 0x2900u));
|
|
1537
|
+
(void)yt_put(t,
|
|
1538
|
+
yt_span_in(st[depth].key_off, st[depth].key_len, YTP_SPAN_IN));
|
|
1539
|
+
(void)yt_put(t, yt_props(YTP_EVENT, xaid, 7u | (1u << 13)));
|
|
1540
|
+
yt_f_empty_span(F);
|
|
1541
|
+
(void)yt_put(t, yt_span_in(xoff, xlen, YTP_SPAN_IN));
|
|
1542
|
+
yt_anchor_open(F, xaid);
|
|
1543
|
+
memset(&st[depth], 0, sizeof(st[depth]));
|
|
1544
|
+
st[depth].indent = col; /* the engine's frame pops on the CONTENT
|
|
1545
|
+
* column, not the anchored key's */
|
|
1546
|
+
st[depth].own_map = 1;
|
|
1547
|
+
st[depth].started = 1;
|
|
1548
|
+
st[depth].anchored_first = 1;
|
|
1549
|
+
t->depth++;
|
|
1550
|
+
} else if (depth > 0 && st[depth].pending) {
|
|
1551
|
+
uint8_t of = yt_f_open_form(&st[depth - 1], depth == 1, st[depth].indent);
|
|
1552
|
+
yt_f_open(F, &st[depth], of);
|
|
1553
|
+
root_open = 1;
|
|
1554
|
+
st[depth].pending = 0;
|
|
1555
|
+
if (col == st[depth].indent) {
|
|
1556
|
+
/* a same-column sibling pair resolves the pending
|
|
1557
|
+
* key to null (the engine's empty-value scalar) */
|
|
1558
|
+
(void)yt_put(t, yt_props(YTP_SCALAR, 0, 0x0904u));
|
|
1559
|
+
yt_f_empty_span(F);
|
|
1560
|
+
}
|
|
1561
|
+
} else if (!root_open && depth == 0) {
|
|
1562
|
+
(void)yt_put(t, yt_props(YTP_EVENT, 0, 7u));
|
|
1563
|
+
yt_f_empty_span(F);
|
|
1564
|
+
t->depth++;
|
|
1565
|
+
root_open = 1;
|
|
1566
|
+
root_evented = 1;
|
|
1567
|
+
st[0].started = 1;
|
|
1568
|
+
}
|
|
1569
|
+
if (col == st[depth].indent) {
|
|
1570
|
+
/* the engine's sibling-continue: the live phantom
|
|
1571
|
+
* content map closes, the pair rides the frame's
|
|
1572
|
+
* own map without a start event */
|
|
1573
|
+
if (st[depth].phantom) {
|
|
1574
|
+
yt_f_close(F, st[depth].kind);
|
|
1575
|
+
st[depth].phantom = 0;
|
|
1576
|
+
}
|
|
1577
|
+
} else {
|
|
1578
|
+
yt_f_start(F, &st[depth]);
|
|
1579
|
+
}
|
|
1580
|
+
if (st[depth].kind != 0) {
|
|
1581
|
+
return 1;
|
|
1582
|
+
}
|
|
1583
|
+
unsigned char vc = (unsigned char)p[vt];
|
|
1584
|
+
uint32_t flags;
|
|
1585
|
+
if ((vc == '*' && aid != 0) || (vc == '*' && st[depth].anchored_first)) {
|
|
1586
|
+
return 1; /* an anchored/first alias: the engine owns it */
|
|
1587
|
+
}
|
|
1588
|
+
if (vc == '*') {
|
|
1589
|
+
size_t ne = vt + 1;
|
|
1590
|
+
while (ne < line_end) {
|
|
1591
|
+
unsigned char pc = (unsigned char)p[ne];
|
|
1592
|
+
if (pc <= ' ' || pc == ',' || pc == '[' || pc == ']' || pc == '{' ||
|
|
1593
|
+
pc == '}' || pc == '#') {
|
|
1594
|
+
break;
|
|
1595
|
+
}
|
|
1596
|
+
ne++;
|
|
1597
|
+
}
|
|
1598
|
+
uint32_t taid = 0;
|
|
1599
|
+
if (!yt_anchor_get(F, (uint32_t)(vt + 1), (uint32_t)(ne - vt - 1), &taid)) {
|
|
1600
|
+
return 1; /* undefined alias: the engine errors */
|
|
1601
|
+
}
|
|
1602
|
+
if (taid == 0 || taid > YT_FUSED_ANCHORS || F->anchors_opened == NULL ||
|
|
1603
|
+
!F->anchors_opened[taid - 1]) {
|
|
1604
|
+
return 1; /* alias to an anchor whose container never opened
|
|
1605
|
+
* (null-valued or still pending): the engine */
|
|
1606
|
+
}
|
|
1607
|
+
(void)yt_put(t, yt_props(YTP_PAIR, taid, 3u /*ALIAS*/));
|
|
1608
|
+
(void)yt_put(t, yt_span_in((uint32_t)t0, kend - (uint32_t)t0, YTP_SPAN_IN));
|
|
1609
|
+
(void)yt_put(t, yt_span_in((uint32_t)(vt + 1), (uint32_t)(ne - vt - 1),
|
|
1610
|
+
YTP_SPAN_IN));
|
|
1611
|
+
if (!st[depth].content_col) {
|
|
1612
|
+
st[depth].content_col = col + 1;
|
|
1613
|
+
}
|
|
1614
|
+
goto line_done;
|
|
1615
|
+
}
|
|
1616
|
+
if ((vc == '"' || vc == '\'') && aid == 0) {
|
|
1617
|
+
/* same-line quoted value: the two-SCALAR form (the
|
|
1618
|
+
* key plain + the styled value, quotes stripped);
|
|
1619
|
+
* escapes and multiline quotes stay with the engine */
|
|
1620
|
+
size_t ce = vt + 1;
|
|
1621
|
+
int esc = 0;
|
|
1622
|
+
while (ce < line_end) {
|
|
1623
|
+
if (p[ce] == '\\') {
|
|
1624
|
+
esc = 1;
|
|
1625
|
+
break;
|
|
1626
|
+
}
|
|
1627
|
+
if (p[ce] == vc) {
|
|
1628
|
+
break;
|
|
1629
|
+
}
|
|
1630
|
+
ce++;
|
|
1631
|
+
}
|
|
1632
|
+
if (ce >= line_end || esc) {
|
|
1633
|
+
return 1; /* unterminated or escaped: the engine */
|
|
1634
|
+
}
|
|
1635
|
+
if (vc == '\'' && ce + 1 < line_end && p[ce + 1] == '\'') {
|
|
1636
|
+
return 1; /* the '' escape: the engine */
|
|
1637
|
+
}
|
|
1638
|
+
size_t te = ce + 1;
|
|
1639
|
+
while (te < line_end && (p[te] == ' ' || p[te] == '\t')) {
|
|
1640
|
+
te++;
|
|
1641
|
+
}
|
|
1642
|
+
/* a comment needs separating whitespace — "#"
|
|
1643
|
+
* glued to the quote is content (the engine errors) */
|
|
1644
|
+
if (te < line_end && (p[te] != '#' || te == ce + 1)) {
|
|
1645
|
+
return 1; /* trailing content after the close */
|
|
1646
|
+
}
|
|
1647
|
+
(void)yt_put(t, yt_props(YTP_SCALAR, 0, 0x2900u));
|
|
1648
|
+
(void)yt_put(t, yt_span_in((uint32_t)t0, kend - (uint32_t)t0, YTP_SPAN_IN));
|
|
1649
|
+
(void)yt_put(t, yt_props(YTP_SCALAR, 0, vc == '"' ? 0x2300u : 0x2200u));
|
|
1650
|
+
(void)yt_put(t, yt_span_in((uint32_t)(vt + 1), (uint32_t)(ce - vt - 1),
|
|
1651
|
+
YTP_SPAN_IN));
|
|
1652
|
+
st[depth].anchored_first = 0;
|
|
1653
|
+
if (!st[depth].content_col) {
|
|
1654
|
+
st[depth].content_col = col + 1;
|
|
1655
|
+
}
|
|
1656
|
+
goto line_done;
|
|
1657
|
+
}
|
|
1658
|
+
if (vc == '|' && aid == 0 && !st[depth].anchored_first &&
|
|
1659
|
+
(vt + 1 >= line_end || p[vt + 1] == ' ' || p[vt + 1] == '\t')) {
|
|
1660
|
+
/* bare literal block, clip chomp: measure the block,
|
|
1661
|
+
* copy it into the finish pool, emit the pool form */
|
|
1662
|
+
size_t scan = next;
|
|
1663
|
+
uint32_t bindent = 0;
|
|
1664
|
+
int have_bi = 0, have_content = 0;
|
|
1665
|
+
size_t clen = 0, tb = 0;
|
|
1666
|
+
size_t end_scan = scan;
|
|
1667
|
+
/* per-line copy facts: blocks whose lines fit
|
|
1668
|
+
* the array copy straight from it — the second,
|
|
1669
|
+
* boundary-rederiving walk disappears. Larger
|
|
1670
|
+
* blocks (nested in block-heavy) keep the walk
|
|
1671
|
+
* below. */
|
|
1672
|
+
struct {
|
|
1673
|
+
uint32_t off;
|
|
1674
|
+
uint32_t n;
|
|
1675
|
+
uint8_t blank;
|
|
1676
|
+
} ln[16];
|
|
1677
|
+
size_t nl = 0;
|
|
1678
|
+
int spilled = 0;
|
|
1679
|
+
while (scan < len) {
|
|
1680
|
+
size_t ls = scan;
|
|
1681
|
+
size_t le = ls;
|
|
1682
|
+
while (le < len && p[le] != '\n' && p[le] != '\r') {
|
|
1683
|
+
le++;
|
|
1684
|
+
}
|
|
1685
|
+
size_t ie = ls;
|
|
1686
|
+
while (ie < le && p[ie] == ' ') {
|
|
1687
|
+
ie++;
|
|
1688
|
+
}
|
|
1689
|
+
uint32_t cpy_off = 0, cpy_n = 0;
|
|
1690
|
+
uint8_t cpy_blank = 0;
|
|
1691
|
+
if (ie == le) {
|
|
1692
|
+
/* a blank line: spaces past the block indent are
|
|
1693
|
+
* CONTENT; only stripped-empty lines clip away */
|
|
1694
|
+
size_t ind = ie - ls;
|
|
1695
|
+
size_t res = have_bi && ind > bindent ? ind - bindent : 0;
|
|
1696
|
+
clen += res + 1;
|
|
1697
|
+
if (res == 0) {
|
|
1698
|
+
tb += 1;
|
|
1699
|
+
} else {
|
|
1700
|
+
tb = 0;
|
|
1701
|
+
}
|
|
1702
|
+
cpy_n = (uint32_t)res;
|
|
1703
|
+
cpy_blank = 1;
|
|
1704
|
+
} else {
|
|
1705
|
+
uint32_t ind = (uint32_t)(ie - ls);
|
|
1706
|
+
if (!have_bi) {
|
|
1707
|
+
if (ind <= col) {
|
|
1708
|
+
break; /* dedented past the block */
|
|
1709
|
+
}
|
|
1710
|
+
bindent = ind;
|
|
1711
|
+
have_bi = 1;
|
|
1712
|
+
} else if (ind < bindent) {
|
|
1713
|
+
break; /* the block ends */
|
|
1714
|
+
}
|
|
1715
|
+
if (memchr(p + ls, '\t', le - ls) != NULL) {
|
|
1716
|
+
return 1; /* tabs: the engine's error */
|
|
1717
|
+
}
|
|
1718
|
+
clen += (le - (ls + bindent)) + 1;
|
|
1719
|
+
have_content = 1;
|
|
1720
|
+
tb = 0;
|
|
1721
|
+
cpy_off = (uint32_t)(ls + bindent);
|
|
1722
|
+
cpy_n = (uint32_t)(le - (ls + bindent));
|
|
1723
|
+
}
|
|
1724
|
+
if (nl < 16) {
|
|
1725
|
+
ln[nl].off = cpy_off;
|
|
1726
|
+
ln[nl].n = cpy_n;
|
|
1727
|
+
ln[nl].blank = cpy_blank;
|
|
1728
|
+
nl++;
|
|
1729
|
+
} else {
|
|
1730
|
+
spilled = 1;
|
|
1731
|
+
}
|
|
1732
|
+
end_scan =
|
|
1733
|
+
(le < len && p[le] == '\r' && le + 1 < len) ? le + 2 : le + 1;
|
|
1734
|
+
scan = end_scan;
|
|
1735
|
+
}
|
|
1736
|
+
if (!have_content) {
|
|
1737
|
+
return 1; /* empty/blank-only block: the engine */
|
|
1738
|
+
}
|
|
1739
|
+
size_t flen = clen - tb; /* clip: the trailing stripped-empty lines */
|
|
1740
|
+
if (F->pool == NULL) {
|
|
1741
|
+
F->pool = yep_pool_create(yep_system_allocator(), 4096);
|
|
1742
|
+
if (F->pool == NULL) {
|
|
1743
|
+
return 1;
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
char* dst = (char*)yep_pool_alloc(F->pool, flen, 16);
|
|
1747
|
+
if (dst == NULL) {
|
|
1748
|
+
return 1;
|
|
1749
|
+
}
|
|
1750
|
+
{
|
|
1751
|
+
char* q = dst;
|
|
1752
|
+
if (!spilled) {
|
|
1753
|
+
/* the array path: sizing and copy derive
|
|
1754
|
+
* from the SAME facts — exact by
|
|
1755
|
+
* construction, no re-walk */
|
|
1756
|
+
for (size_t x = 0; x < nl; x++) {
|
|
1757
|
+
if (ln[x].blank) {
|
|
1758
|
+
if (ln[x].n > 0) {
|
|
1759
|
+
memset(q, ' ', ln[x].n);
|
|
1760
|
+
q += ln[x].n;
|
|
1761
|
+
}
|
|
1762
|
+
} else {
|
|
1763
|
+
memcpy(q, p + ln[x].off, ln[x].n);
|
|
1764
|
+
q += ln[x].n;
|
|
1765
|
+
}
|
|
1766
|
+
*q++ = '\n';
|
|
1767
|
+
}
|
|
1768
|
+
} else {
|
|
1769
|
+
size_t s2 = next;
|
|
1770
|
+
while (s2 < scan) {
|
|
1771
|
+
size_t ls = s2;
|
|
1772
|
+
size_t le = ls;
|
|
1773
|
+
while (le < len && p[le] != '\n' && p[le] != '\r') {
|
|
1774
|
+
le++;
|
|
1775
|
+
}
|
|
1776
|
+
size_t ie = ls;
|
|
1777
|
+
while (ie < le && p[ie] == ' ') {
|
|
1778
|
+
ie++;
|
|
1779
|
+
}
|
|
1780
|
+
if (ie == le) {
|
|
1781
|
+
size_t ind = ie - ls;
|
|
1782
|
+
size_t res = have_bi && ind > bindent ? ind - bindent : 0;
|
|
1783
|
+
if (res > 0) {
|
|
1784
|
+
memset(q, ' ', res);
|
|
1785
|
+
q += res;
|
|
1786
|
+
}
|
|
1787
|
+
*q++ = '\n';
|
|
1788
|
+
} else {
|
|
1789
|
+
memcpy(q, p + ls + bindent, le - (ls + bindent));
|
|
1790
|
+
q += le - (ls + bindent);
|
|
1791
|
+
*q++ = '\n';
|
|
1792
|
+
}
|
|
1793
|
+
s2 = (le < len && p[le] == '\r' && le + 1 < len) ? le + 2
|
|
1794
|
+
: le + 1;
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
if ((size_t)(q - dst) != clen) {
|
|
1798
|
+
return 1; /* drift: bail, not corrupt */
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
(void)yt_put(t, yt_props(YTP_SCALAR, 0, 0x2900u));
|
|
1802
|
+
(void)yt_put(t, yt_span_in((uint32_t)t0, kend - (uint32_t)t0, YTP_SPAN_IN));
|
|
1803
|
+
(void)yt_put(t, yt_props(YTP_SCALAR, 0, 0x0400u));
|
|
1804
|
+
(void)yt_put(t, ((uint64_t)YTP_SPAN_POOL << 56) | (uint64_t)flen);
|
|
1805
|
+
(void)yt_put(t, (uint64_t)(uintptr_t)dst);
|
|
1806
|
+
if (!st[depth].content_col) {
|
|
1807
|
+
st[depth].content_col = col + 1;
|
|
1808
|
+
}
|
|
1809
|
+
next = scan;
|
|
1810
|
+
goto line_done;
|
|
1811
|
+
}
|
|
1812
|
+
if (vc == '"' || vc == '\'' || vc == '|' || vc == '>' || vc == '[' ||
|
|
1813
|
+
vc == '{' || vc == '!' || vc == '%') {
|
|
1814
|
+
return 1; /* quoted/block/flow/tag values: the engine */
|
|
1815
|
+
}
|
|
1816
|
+
if ((vc == '-' || vc == '?') && (vt + 1 >= line_end || p[vt + 1] == ' ' ||
|
|
1817
|
+
p[vt + 1] == '\t' || p[vt + 1] == '#')) {
|
|
1818
|
+
return 1; /* an indicator-as-value: the engine errors */
|
|
1819
|
+
}
|
|
1820
|
+
/* a terminating ':' inside the value is the
|
|
1821
|
+
* mapping-values error — the engine owns it */
|
|
1822
|
+
for (const char* h = (const char*)memchr(p + vt, ':', line_end - vt);
|
|
1823
|
+
h != NULL && h < p + line_end;
|
|
1824
|
+
h = (const char*)memchr(h + 1, ':', line_end - (size_t)(h + 1 - p))) {
|
|
1825
|
+
if (h + 1 >= p + line_end || h[1] == ' ' || h[1] == '\t') {
|
|
1826
|
+
return 1;
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
/* trailing comment bounds the plain value */
|
|
1830
|
+
uint32_t vend = line_end;
|
|
1831
|
+
{
|
|
1832
|
+
const char* h = (const char*)memchr(p + vt, '#', line_end - vt);
|
|
1833
|
+
while (h != NULL) {
|
|
1834
|
+
if (h > p + vt && (h[-1] == ' ' || h[-1] == '\t')) {
|
|
1835
|
+
vend = (uint32_t)(h - p);
|
|
1836
|
+
break;
|
|
1837
|
+
}
|
|
1838
|
+
h = (const char*)memchr(h + 1, '#', line_end - (size_t)(h + 1 - p));
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
while (vend > vt && (p[vend - 1] == ' ' || p[vend - 1] == '\t')) {
|
|
1842
|
+
vend--;
|
|
1843
|
+
}
|
|
1844
|
+
if (st[depth].anchored_first) {
|
|
1845
|
+
/* the first pair inside an anchored container: the
|
|
1846
|
+
* two-SCALAR form with the engine's tag bake */
|
|
1847
|
+
if (aid != 0 || F->resolver == NULL) {
|
|
1848
|
+
return 1;
|
|
1849
|
+
}
|
|
1850
|
+
yep_tag_id tid =
|
|
1851
|
+
F->resolver->resolve(F->resolver->ctx, p + vt, (uint32_t)(vend - vt));
|
|
1852
|
+
(void)yt_put(t, yt_props(YTP_SCALAR, 0, 0x2900u));
|
|
1853
|
+
(void)yt_put(t, yt_span_in((uint32_t)t0, kend - (uint32_t)t0, YTP_SPAN_IN));
|
|
1854
|
+
(void)yt_put(t, yt_props(YTP_SCALAR, 0, 0x2900u | (uint32_t)tid));
|
|
1855
|
+
(void)yt_put(t, yt_span_in((uint32_t)vt, vend - (uint32_t)vt, YTP_SPAN_IN));
|
|
1856
|
+
st[depth].anchored_first = 0;
|
|
1857
|
+
if (!st[depth].content_col) {
|
|
1858
|
+
st[depth].content_col = col + 1;
|
|
1859
|
+
}
|
|
1860
|
+
goto line_done;
|
|
1861
|
+
}
|
|
1862
|
+
if (aid != 0) {
|
|
1863
|
+
flags = 4u | (1u << 3) | (1u << 4);
|
|
1864
|
+
} else {
|
|
1865
|
+
flags = 2u | (1u << 3);
|
|
1866
|
+
}
|
|
1867
|
+
(void)yt_put(t, yt_props(YTP_PAIR, aid, flags));
|
|
1868
|
+
(void)yt_put(t, yt_span_in((uint32_t)t0, kend - (uint32_t)t0, YTP_SPAN_IN));
|
|
1869
|
+
(void)yt_put(t, yt_span_in((uint32_t)vt, vend - (uint32_t)vt, YTP_SPAN_IN));
|
|
1870
|
+
if (aid != 0) {
|
|
1871
|
+
(void)yt_put(t, yt_span_in(aoff, alen, YTP_SPAN_IN));
|
|
1872
|
+
}
|
|
1873
|
+
if (!st[depth].content_col) {
|
|
1874
|
+
st[depth].content_col = col + 1;
|
|
1875
|
+
}
|
|
1876
|
+
if (aid == 0 && !st[depth].phantom && st[depth].content_col == col + 1) {
|
|
1877
|
+
/* the specialist takes the run at ANY frame's
|
|
1878
|
+
* content column: nested flat runs (anchored
|
|
1879
|
+
* containers, leaf maps) qualify; an off-column
|
|
1880
|
+
* line bails to the pop/nest arms as usual.
|
|
1881
|
+
* anchored_first is already cleared whenever a
|
|
1882
|
+
* plain emission reaches here (the anchored arm
|
|
1883
|
+
* leaves early), so no extra gate is owed. */
|
|
1884
|
+
size_t sp = yt_flat_run(t, p, next, len, st[depth].content_col);
|
|
1885
|
+
if (sp != next) {
|
|
1886
|
+
pos = sp;
|
|
1887
|
+
goto line_done_keep;
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
} else {
|
|
1892
|
+
return 1; /* unclassified line: the engine route */
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
line_done:
|
|
1896
|
+
pos = next;
|
|
1897
|
+
line_done_keep: /* the specialist's stop line: reprocess it in place */
|
|
1898
|
+
;
|
|
1899
|
+
}
|
|
1900
|
+
if (!root_open) {
|
|
1901
|
+
return 1; /* empty document: the engine owns it */
|
|
1902
|
+
}
|
|
1903
|
+
while (depth > 0) {
|
|
1904
|
+
if (st[depth].pending) {
|
|
1905
|
+
return 1; /* empty "key:" at EOF: the engine */
|
|
1906
|
+
}
|
|
1907
|
+
if (st[depth].phantom) {
|
|
1908
|
+
yt_f_close(F, st[depth].kind);
|
|
1909
|
+
st[depth].phantom = 0;
|
|
1910
|
+
}
|
|
1911
|
+
if (st[depth].own_map) {
|
|
1912
|
+
yt_f_close(F, st[depth].kind);
|
|
1913
|
+
}
|
|
1914
|
+
depth--;
|
|
1915
|
+
}
|
|
1916
|
+
if (root_evented) {
|
|
1917
|
+
yt_f_close(F, 0); /* only an event-started root closes */
|
|
1918
|
+
}
|
|
1919
|
+
(void)yt_put(t, ((uint64_t)YTP_EV_COMPACT << 56) | 4u);
|
|
1920
|
+
(void)yt_put(t, ((uint64_t)YTP_EV_COMPACT << 56) | 2u);
|
|
1921
|
+
t->docs = 1;
|
|
1922
|
+
return 0;
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
/* The flow-rooted fast path (item 86): a document whose entire content
|
|
1926
|
+
* is ONE flow collection plus whitespace skips both the block runner
|
|
1927
|
+
* and the engine — the budgeted classification runs once and the
|
|
1928
|
+
* engine's exact five-word scaffolding lands directly. Any marker,
|
|
1929
|
+
* comment, anchor-bearing prefix, or second content falls back. */
|
|
1930
|
+
int ytap_flow_rooted(yep_ytape* t) {
|
|
1931
|
+
const char* p = t->input;
|
|
1932
|
+
size_t len = t->input_len;
|
|
1933
|
+
size_t i = 0;
|
|
1934
|
+
while (i < len && (p[i] == ' ' || p[i] == '\t' || p[i] == '\n' || p[i] == '\r')) {
|
|
1935
|
+
i++;
|
|
1936
|
+
}
|
|
1937
|
+
if (i >= len || (p[i] != '[' && p[i] != '{')) {
|
|
1938
|
+
return 1; /* not flow-rooted: the block runner's turn */
|
|
1939
|
+
}
|
|
1940
|
+
size_t mark = t->count;
|
|
1941
|
+
size_t open = i;
|
|
1942
|
+
yep_view none = {NULL, 0};
|
|
1943
|
+
(void)yt_put(t, ((uint64_t)YTP_EV_COMPACT << 56) | 1u);
|
|
1944
|
+
(void)yt_put(t, ((uint64_t)YTP_EV_COMPACT << 56) | 3u);
|
|
1945
|
+
size_t close = 0;
|
|
1946
|
+
int v = yt_flow_classify_record(t, p, open, len - open, &none, &none, 0,
|
|
1947
|
+
1000 /* YEP_MAX_DEPTH: the engine's
|
|
1948
|
+
* default limit (engine.c) */
|
|
1949
|
+
,
|
|
1950
|
+
&close);
|
|
1951
|
+
if (v != 1) {
|
|
1952
|
+
t->count = (uint32_t)mark; /* unwind: the engine route owns it */
|
|
1953
|
+
t->depth = 0;
|
|
1954
|
+
return 1;
|
|
1955
|
+
}
|
|
1956
|
+
for (size_t e = close + 1; e < len; e++) {
|
|
1957
|
+
if (p[e] != ' ' && p[e] != '\t' && p[e] != '\n' && p[e] != '\r') {
|
|
1958
|
+
t->count = (uint32_t)mark; /* trailing content: the engine */
|
|
1959
|
+
t->depth = 0;
|
|
1960
|
+
return 1;
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
(void)yt_put(t, ((uint64_t)YTP_EV_COMPACT << 56) | 4u);
|
|
1964
|
+
(void)yt_put(t, ((uint64_t)YTP_EV_COMPACT << 56) | 2u);
|
|
1965
|
+
t->docs = 1;
|
|
1966
|
+
return 0;
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
int ytap_fused_run(yep_ytape* t, const yep_resolver* resolver) {
|
|
1970
|
+
yt_fused* F = (yt_fused*)yep_alloc(yep_system_allocator(), sizeof(*F));
|
|
1971
|
+
if (F == NULL) {
|
|
1972
|
+
return 1; /* allocation refused: the engine route */
|
|
1973
|
+
}
|
|
1974
|
+
memset(F, 0, sizeof(*F));
|
|
1975
|
+
F->t = t;
|
|
1976
|
+
F->p = t->input;
|
|
1977
|
+
F->len = t->input_len;
|
|
1978
|
+
F->resolver = resolver;
|
|
1979
|
+
size_t mark = t->count;
|
|
1980
|
+
int rc = yt_f_run(F);
|
|
1981
|
+
yep_pool* rpool = F->pool; /* capture before the runner frees */
|
|
1982
|
+
yep_free(yep_system_allocator(), F->anchors);
|
|
1983
|
+
yep_free(yep_system_allocator(), F->anchors_opened);
|
|
1984
|
+
yep_free(yep_system_allocator(), F);
|
|
1985
|
+
if (rc != 0) {
|
|
1986
|
+
t->count = (uint32_t)mark; /* unwind: the caller resets and re-runs */
|
|
1987
|
+
t->depth = 0;
|
|
1988
|
+
if (rpool != NULL) {
|
|
1989
|
+
yep_pool_destroy(rpool);
|
|
1990
|
+
}
|
|
1991
|
+
return 1;
|
|
1992
|
+
}
|
|
1993
|
+
if (rpool != NULL) {
|
|
1994
|
+
t->pool = rpool; /* transferred to the document with the tape */
|
|
1995
|
+
}
|
|
1996
|
+
return 0;
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
void ytap_reset(yep_ytape* t) {
|
|
2000
|
+
t->count = 0;
|
|
2001
|
+
t->depth = 0;
|
|
2002
|
+
t->docs = 0;
|
|
2003
|
+
t->oom = 0;
|
|
2004
|
+
t->flow_mark = 0;
|
|
2005
|
+
}
|