yeptris 0.6.52.0-arm-linux-eabihf → 0.6.53.0-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.rb +1 -1
- data/libyeptris.so +0 -0
- data/vendor/libyeptris/CMakeLists.txt +1 -1
- data/vendor/libyeptris/src/yeptris/cbor/from_marshal.c +7 -0
- data/vendor/libyeptris/src/yeptris/dom/dom.c +15 -8
- data/vendor/libyeptris/src/yeptris/dom/dom.h +8 -2
- data/vendor/libyeptris/src/yeptris/dom/ytape.c +2 -2
- data/vendor/libyeptris/src/yeptris/emit/emit.c +4 -0
- data/vendor/libyeptris/src/yeptris/emit/style.c +9 -191
- data/vendor/libyeptris/src/yeptris/emit/writer.c +149 -35
- data/vendor/libyeptris/src/yeptris/marshal.c +10 -5
- data/vendor/libyeptris/src/yeptris/parse/engine.c +185 -67
- data/vendor/libyeptris/src/yeptris/parse/events.h +2 -2
- data/vendor/libyeptris/src/yeptris/resolve/compat11.c +2 -1
- data/vendor/libyeptris/src/yeptris/resolve/core12.c +3 -1
- data/vendor/libyeptris/src/yeptris/scan/json.c +6 -0
- data/vendor/libyeptris/src/yeptris/scan/scan.c +202 -1
- data/vendor/libyeptris/src/yeptris/scan/scan.h +12 -1
- metadata +1 -1
|
@@ -49,7 +49,7 @@ typedef enum {
|
|
|
49
49
|
|
|
50
50
|
/* One open collection frame (the engine's indentation stack). */
|
|
51
51
|
typedef struct {
|
|
52
|
-
|
|
52
|
+
uint32_t col;
|
|
53
53
|
uint8_t kind;
|
|
54
54
|
uint8_t inline_doc; /* opened on the --- line: deeper keys only */
|
|
55
55
|
} yep_frame;
|
|
@@ -163,7 +163,7 @@ struct yep_engine {
|
|
|
163
163
|
int last_root_flow; /* a root-level flow node just completed */
|
|
164
164
|
int tag_undef; /* an unresolved !handle! was seen (QLJ7) */
|
|
165
165
|
int doc_inline; /* content node opened on the --- line */
|
|
166
|
-
|
|
166
|
+
uint32_t flow_floor; /* parent column of the current block-level flow */
|
|
167
167
|
int flow_enforce; /* flow continuation lines must out-indent it */
|
|
168
168
|
int compat_grammar; /* 11-COMPAT: libyaml/psych grammar parity —
|
|
169
169
|
* the flow indent floor (9C9N/VJP3) is a
|
|
@@ -176,8 +176,8 @@ struct yep_engine {
|
|
|
176
176
|
|
|
177
177
|
/* ------------------------------------------------------------ forwards */
|
|
178
178
|
|
|
179
|
-
static int e_node(yep_engine* e, yep_ctx ctx,
|
|
180
|
-
static int e_parse_value(yep_engine* e, yep_ctx ctx,
|
|
179
|
+
static int e_node(yep_engine* e, yep_ctx ctx, uint32_t floor_col);
|
|
180
|
+
static int e_parse_value(yep_engine* e, yep_ctx ctx, uint32_t floor_col);
|
|
181
181
|
|
|
182
182
|
/* ---------------------------------------------------------------- util */
|
|
183
183
|
|
|
@@ -462,7 +462,7 @@ static uint32_t anchor_define(yep_engine* e, yep_view name) {
|
|
|
462
462
|
/* Opens a collection frame unless the top frame already continues at
|
|
463
463
|
* exactly this column (sibling entries reuse it). anchor/tag ride the
|
|
464
464
|
* START event. Returns 0 on success. */
|
|
465
|
-
static int e_open_seq(yep_engine* e,
|
|
465
|
+
static int e_open_seq(yep_engine* e, uint32_t col, uint32_t line, uint32_t coln, yep_view anchor,
|
|
466
466
|
yep_view tag, uint32_t anchor_id) {
|
|
467
467
|
if (e->depth > 0 && e->frames[e->depth - 1].kind == YEP_FRAME_SEQ &&
|
|
468
468
|
e->frames[e->depth - 1].col == col) {
|
|
@@ -500,7 +500,7 @@ static int e_open_seq(yep_engine* e, uint16_t col, uint32_t line, uint32_t coln,
|
|
|
500
500
|
|
|
501
501
|
/* silent: the sink's on_block_open built the node — push the frame
|
|
502
502
|
* without emitting (TODO.restructure/57). */
|
|
503
|
-
static int e_open_map(yep_engine* e,
|
|
503
|
+
static int e_open_map(yep_engine* e, uint32_t col, uint32_t line, uint32_t coln, yep_view anchor,
|
|
504
504
|
yep_view tag, uint32_t anchor_id, int silent) {
|
|
505
505
|
if (e->depth > 0 && e->frames[e->depth - 1].kind == YEP_FRAME_MAP &&
|
|
506
506
|
e->frames[e->depth - 1].col == col) {
|
|
@@ -555,7 +555,7 @@ static int e_flush_q_value(yep_engine* e) {
|
|
|
555
555
|
* value arrived inline) the innermost '?' pending resolves — without
|
|
556
556
|
* this pop the stack keeps a stale entry and the outer pair's null
|
|
557
557
|
* flushes inside the wrong map (the nightly's run 38387614146). */
|
|
558
|
-
static int e_pair_value_done(yep_engine* e, yep_ctx ctx,
|
|
558
|
+
static int e_pair_value_done(yep_engine* e, yep_ctx ctx, uint32_t key_col) {
|
|
559
559
|
/* the pair's own level, BEFORE its value parse: the value may open
|
|
560
560
|
* deeper frames ("? a:\n ? b<EOF>") and a post-parse depth read
|
|
561
561
|
* then matches the DEEPER pair's pending slot, popping the wrong
|
|
@@ -604,7 +604,7 @@ static int e_close_to(yep_engine* e, int to_depth) {
|
|
|
604
604
|
/* ------------------------------------------------------------- scalars */
|
|
605
605
|
|
|
606
606
|
/* Quoted scalar at the opening quote; spans lines when needed. */
|
|
607
|
-
static int e_quoted_floor(yep_engine* e, yep_event* ev,
|
|
607
|
+
static int e_quoted_floor(yep_engine* e, yep_event* ev, uint32_t min_indent, int enforce) {
|
|
608
608
|
unsigned char q = (unsigned char)e->p[e->pos];
|
|
609
609
|
size_t content_start = e->pos + 1;
|
|
610
610
|
int has_esc = 0;
|
|
@@ -885,12 +885,12 @@ static int e_block_scalar(yep_engine* e, yep_event* ev, int parent_col) {
|
|
|
885
885
|
if (content_indent <= parent_col) {
|
|
886
886
|
break; /* no block content */
|
|
887
887
|
}
|
|
888
|
-
} else if (li.indent <= parent_col) {
|
|
888
|
+
} else if ((int)li.indent <= parent_col) {
|
|
889
889
|
break; /* dedent ends the block */
|
|
890
|
-
} else if (li.indent < content_indent && li.indent <= parent_col) {
|
|
890
|
+
} else if ((int)li.indent < content_indent && (int)li.indent <= parent_col) {
|
|
891
891
|
break;
|
|
892
892
|
}
|
|
893
|
-
if (li.indent < content_indent) {
|
|
893
|
+
if ((int)li.indent < content_indent) {
|
|
894
894
|
break;
|
|
895
895
|
}
|
|
896
896
|
}
|
|
@@ -902,10 +902,10 @@ static int e_block_scalar(yep_engine* e, yep_event* ev, int parent_col) {
|
|
|
902
902
|
if (content_indent <= parent_col) {
|
|
903
903
|
break;
|
|
904
904
|
}
|
|
905
|
-
} else if (li.indent < content_indent) {
|
|
905
|
+
} else if ((int)li.indent < content_indent) {
|
|
906
906
|
break;
|
|
907
907
|
}
|
|
908
|
-
if (li.indent >= content_indent) {
|
|
908
|
+
if ((int)li.indent >= content_indent) {
|
|
909
909
|
uint32_t from2 = li.offset + (uint32_t)content_indent;
|
|
910
910
|
if (e->fold_n >= YEP_MAX_FOLD_LINES) {
|
|
911
911
|
return e_fail(e, YEP_ERR_MEMORY, e->pos);
|
|
@@ -945,7 +945,7 @@ static int e_block_scalar(yep_engine* e, yep_event* ev, int parent_col) {
|
|
|
945
945
|
}
|
|
946
946
|
/* a blank line whose spaces extend past the content indent is
|
|
947
947
|
* CONTENT (kept verbatim); otherwise it is a pure break */
|
|
948
|
-
if (content_indent >= 0 && li.indent > content_indent) {
|
|
948
|
+
if (content_indent >= 0 && (int)li.indent > content_indent) {
|
|
949
949
|
if (e->fold_n >= YEP_MAX_FOLD_LINES) {
|
|
950
950
|
return e_fail(e, YEP_ERR_MEMORY, e->pos);
|
|
951
951
|
}
|
|
@@ -996,7 +996,7 @@ static int e_block_scalar(yep_engine* e, yep_event* ev, int parent_col) {
|
|
|
996
996
|
/* leading blank lines belong to the block content */
|
|
997
997
|
e->fold[e->fold_n].breaks_before = saw_content ? pending_breaks + 1 : pending_breaks;
|
|
998
998
|
e->fold[e->fold_n].more_indented =
|
|
999
|
-
li.indent > content_indent ||
|
|
999
|
+
(int)li.indent > content_indent ||
|
|
1000
1000
|
(from < li.end && (e->p[from] == ' ' || e->p[from] == '\t'));
|
|
1001
1001
|
e->fold_n++;
|
|
1002
1002
|
saw_content = 1;
|
|
@@ -1893,7 +1893,7 @@ static int e_flow_key_after(const char* p, size_t len, size_t close) {
|
|
|
1893
1893
|
* rejects it, and the fast path must agree (the nightly's run
|
|
1894
1894
|
* 38280372447: whole vs chunked split across the fast/slow paths and
|
|
1895
1895
|
* produced two different verdicts for the same bytes). */
|
|
1896
|
-
static int e_flow_floor_ok(const char* p, size_t open, size_t close,
|
|
1896
|
+
static int e_flow_floor_ok(const char* p, size_t open, size_t close, uint32_t floor) {
|
|
1897
1897
|
size_t j = open;
|
|
1898
1898
|
while (j < close) {
|
|
1899
1899
|
/* the break rule is the scan's: \n, or a \r the next byte does
|
|
@@ -3036,7 +3036,7 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
|
|
|
3036
3036
|
|
|
3037
3037
|
/* Plain (optionally anchored) value: emit, fold continuations, land at
|
|
3038
3038
|
* the line end. root_ctx is 0 — every arm has pushed a frame. */
|
|
3039
|
-
static int e_shape_plain_value(yep_engine* e, const yep_line_shape* sh,
|
|
3039
|
+
static int e_shape_plain_value(yep_engine* e, const yep_line_shape* sh, uint32_t floor,
|
|
3040
3040
|
yep_view anchor, uint32_t anchor_id) {
|
|
3041
3041
|
yep_event ev;
|
|
3042
3042
|
e_event_init(&ev, YEP_EV_SCALAR);
|
|
@@ -3078,7 +3078,7 @@ static int e_shape_plain_value(yep_engine* e, const yep_line_shape* sh, uint16_t
|
|
|
3078
3078
|
|
|
3079
3079
|
/* Flow value: the JSON fast path first; anything else restores the
|
|
3080
3080
|
* cursor and runs the value chain (which re-derives the flow arms). */
|
|
3081
|
-
static int e_shape_flow_value(yep_engine* e, const yep_line_shape* sh,
|
|
3081
|
+
static int e_shape_flow_value(yep_engine* e, const yep_line_shape* sh, uint32_t floor,
|
|
3082
3082
|
yep_ctx next) {
|
|
3083
3083
|
yep_view none = {NULL, 0};
|
|
3084
3084
|
e->pos = sh->val_start;
|
|
@@ -3119,7 +3119,7 @@ static int e_shape_alias_value(yep_engine* e, const yep_line_shape* sh, int unde
|
|
|
3119
3119
|
if (e_simple_key_ok(e, sh->val_start, e->pos) != 0) {
|
|
3120
3120
|
return -1;
|
|
3121
3121
|
}
|
|
3122
|
-
|
|
3122
|
+
uint32_t key_col = e_col(e, sh->val_start);
|
|
3123
3123
|
int rc = e_open_map(e, key_col, e->line, key_col + 1, none, none, 0, 0);
|
|
3124
3124
|
if (rc != 0) {
|
|
3125
3125
|
return rc;
|
|
@@ -3141,7 +3141,7 @@ static int e_shape_alias_value(yep_engine* e, const yep_line_shape* sh, int unde
|
|
|
3141
3141
|
* emit it: the pair path takes the whole line without events, and
|
|
3142
3142
|
* building kv up front discarded ~48 stores per classified line
|
|
3143
3143
|
* (TODO.restructure/63 phase 1). */
|
|
3144
|
-
static void e_key_event(const yep_engine* e, const yep_line_shape* sh,
|
|
3144
|
+
static void e_key_event(const yep_engine* e, const yep_line_shape* sh, uint32_t key_col,
|
|
3145
3145
|
uint32_t line, yep_event* kv) {
|
|
3146
3146
|
e_event_init(kv, YEP_EV_SCALAR);
|
|
3147
3147
|
kv->style = YEP_STYLE_PLAIN;
|
|
@@ -3156,7 +3156,7 @@ static void e_key_event(const yep_engine* e, const yep_line_shape* sh, uint16_t
|
|
|
3156
3156
|
e_pos_mark(e, sh->key_end, &kv->end_line, &kv->end_col);
|
|
3157
3157
|
}
|
|
3158
3158
|
|
|
3159
|
-
static int e_classified(yep_engine* e,
|
|
3159
|
+
static int e_classified(yep_engine* e, uint32_t floor_col) {
|
|
3160
3160
|
yep_line_info li = e_line_info_here(e);
|
|
3161
3161
|
if (e->pos != e->line_start + li.indent) {
|
|
3162
3162
|
return 0; /* mid-line entry: the chain keeps its dispatch */
|
|
@@ -3177,7 +3177,7 @@ static int e_classified(yep_engine* e, uint16_t floor_col) {
|
|
|
3177
3177
|
default:
|
|
3178
3178
|
return 0;
|
|
3179
3179
|
}
|
|
3180
|
-
|
|
3180
|
+
uint32_t col = e_col(e, e->pos);
|
|
3181
3181
|
int rc = e_open_seq(e, col, e->line, col + 1, none, none, 0);
|
|
3182
3182
|
if (rc != 0) {
|
|
3183
3183
|
return rc;
|
|
@@ -3203,7 +3203,7 @@ static int e_classified(yep_engine* e, uint16_t floor_col) {
|
|
|
3203
3203
|
if (e_simple_key_ok(e, sh->key_start, sh->key_end) != 0) {
|
|
3204
3204
|
return -1;
|
|
3205
3205
|
}
|
|
3206
|
-
|
|
3206
|
+
uint32_t key_col = e_col(e, e->pos);
|
|
3207
3207
|
/* `key:` with the value on following lines, opening a FRESH map:
|
|
3208
3208
|
* the sink may build map+key in one call (TODO.restructure/57) —
|
|
3209
3209
|
* the engine then opens its frame silently. Sibling keys (the map
|
|
@@ -3241,7 +3241,7 @@ static int e_classified(yep_engine* e, uint16_t floor_col) {
|
|
|
3241
3241
|
/* the pair facts are captured BEFORE the fold: e_plain_multiline
|
|
3242
3242
|
* advances line/pos across continuations */
|
|
3243
3243
|
uint32_t pair_line = e->line;
|
|
3244
|
-
|
|
3244
|
+
uint32_t pair_val_col = e_col(e, sh->val_start);
|
|
3245
3245
|
yep_block_value v;
|
|
3246
3246
|
memset(&v, 0, sizeof(v));
|
|
3247
3247
|
v.cls = (uint8_t)sh->val;
|
|
@@ -3375,7 +3375,7 @@ static int e_classified(yep_engine* e, uint16_t floor_col) {
|
|
|
3375
3375
|
* pend props (parsed at the parent's value position on an earlier line)
|
|
3376
3376
|
* belong to the VALUE node as a whole — a collection START event when
|
|
3377
3377
|
* the value is a collection. */
|
|
3378
|
-
static int e_node(yep_engine* e, yep_ctx ctx,
|
|
3378
|
+
static int e_node(yep_engine* e, yep_ctx ctx, uint32_t floor_col) {
|
|
3379
3379
|
size_t node_at = e->pos;
|
|
3380
3380
|
yep_view pend_a = e->pend_anchor, pend_t = e->pend_tag;
|
|
3381
3381
|
uint32_t pend_aid = e->pend_anchor_id;
|
|
@@ -3482,7 +3482,7 @@ static int e_node(yep_engine* e, yep_ctx ctx, uint16_t floor_col) {
|
|
|
3482
3482
|
if (!yep_view_is_empty(anchor) || !yep_view_is_empty(tag)) {
|
|
3483
3483
|
return e_fail(e, YEP_ERR_UNEXPECTED, e->pos); /* "&a - x" */
|
|
3484
3484
|
}
|
|
3485
|
-
|
|
3485
|
+
uint32_t col = e_col(e, e->pos);
|
|
3486
3486
|
int rc = e_open_seq(e, col, e->line, col + 1, node_a, node_t, node_aid);
|
|
3487
3487
|
if (rc != 0) {
|
|
3488
3488
|
return rc;
|
|
@@ -3515,7 +3515,7 @@ static int e_node(yep_engine* e, yep_ctx ctx, uint16_t floor_col) {
|
|
|
3515
3515
|
if (e->pos > 0 && e->p[e->pos - 1] == '\t') {
|
|
3516
3516
|
return e_fail(e, YEP_ERR_UNEXPECTED, e->pos); /* "?\t-" (Y79Y) */
|
|
3517
3517
|
}
|
|
3518
|
-
|
|
3518
|
+
uint32_t col = e_col(e, e->pos);
|
|
3519
3519
|
int rc = e_open_map(e, col, e->line, col + 1, pend_a, pend_t, pend_aid, 0);
|
|
3520
3520
|
if (rc != 0) {
|
|
3521
3521
|
return rc;
|
|
@@ -3639,7 +3639,7 @@ static int e_node(yep_engine* e, yep_ctx ctx, uint16_t floor_col) {
|
|
|
3639
3639
|
if (e_simple_key_ok(e, node_at, e->pos) != 0) {
|
|
3640
3640
|
return -1;
|
|
3641
3641
|
}
|
|
3642
|
-
|
|
3642
|
+
uint32_t key_col = e_col(e, node_at);
|
|
3643
3643
|
int rc = e_open_map(e, key_col, e->line, key_col + 1, pend_a, pend_t, pend_aid, 0);
|
|
3644
3644
|
if (rc != 0) {
|
|
3645
3645
|
return rc;
|
|
@@ -3683,7 +3683,7 @@ static int e_node(yep_engine* e, yep_ctx ctx, uint16_t floor_col) {
|
|
|
3683
3683
|
if (e_simple_key_ok(e, node_at, e->pos) != 0) {
|
|
3684
3684
|
return -1;
|
|
3685
3685
|
}
|
|
3686
|
-
|
|
3686
|
+
uint32_t key_col = e_col(e, node_at);
|
|
3687
3687
|
int rc = e_open_map(e, key_col, e->line, key_col + 1, pend_a, pend_t, pend_aid, 0);
|
|
3688
3688
|
if (rc != 0) {
|
|
3689
3689
|
return rc;
|
|
@@ -3722,7 +3722,7 @@ static int e_node(yep_engine* e, yep_ctx ctx, uint16_t floor_col) {
|
|
|
3722
3722
|
if (e_simple_key_ok(e, node_at, e->pos) != 0) {
|
|
3723
3723
|
return -1;
|
|
3724
3724
|
}
|
|
3725
|
-
|
|
3725
|
+
uint32_t key_col = e_col(e, node_at);
|
|
3726
3726
|
int rc = e_open_map(e, key_col, e->line, key_col + 1, pend_a, pend_t, pend_aid, 0);
|
|
3727
3727
|
if (rc != 0) {
|
|
3728
3728
|
return rc;
|
|
@@ -3777,7 +3777,7 @@ static int e_node(yep_engine* e, yep_ctx ctx, uint16_t floor_col) {
|
|
|
3777
3777
|
if (e->doc_inline && (!yep_view_is_empty(anchor) || !yep_view_is_empty(tag))) {
|
|
3778
3778
|
return e_fail(e, YEP_ERR_UNEXPECTED, e->pos); /* "--- &a k: v" */
|
|
3779
3779
|
}
|
|
3780
|
-
|
|
3780
|
+
uint32_t key_col = e_col(e, node_at);
|
|
3781
3781
|
int rc = e_open_map(e, key_col, e->line, key_col + 1, pend_a, pend_t, pend_aid, 0);
|
|
3782
3782
|
if (rc != 0) {
|
|
3783
3783
|
return rc;
|
|
@@ -3837,7 +3837,7 @@ static int e_node(yep_engine* e, yep_ctx ctx, uint16_t floor_col) {
|
|
|
3837
3837
|
}
|
|
3838
3838
|
|
|
3839
3839
|
/* Value after "key:" / "-" / "?": on this line, or on following lines. */
|
|
3840
|
-
static int e_parse_value(yep_engine* e, yep_ctx ctx,
|
|
3840
|
+
static int e_parse_value(yep_engine* e, yep_ctx ctx, uint32_t floor_col) {
|
|
3841
3841
|
e_skip_inline_space(e);
|
|
3842
3842
|
if (!e_at_eol(e)) {
|
|
3843
3843
|
if (ctx == YEP_CTX_AFTER_COLON && e->p[e->pos] == '-' &&
|
|
@@ -3849,7 +3849,7 @@ static int e_parse_value(yep_engine* e, yep_ctx ctx, uint16_t floor_col) {
|
|
|
3849
3849
|
(e->pos + 1 >= e->len || e->p[e->pos + 1] == ' ' || e->p[e->pos + 1] == '\t' ||
|
|
3850
3850
|
e->p[e->pos + 1] == '\n' || e->p[e->pos + 1] == '\r')) {
|
|
3851
3851
|
/* "- :" — a compact pair with an empty key */
|
|
3852
|
-
|
|
3852
|
+
uint32_t col = e_col(e, e->pos);
|
|
3853
3853
|
int rc = e_open_map(e, col, e->line, col + 1, e->pend_anchor, e->pend_tag,
|
|
3854
3854
|
e->pend_anchor_id, 0);
|
|
3855
3855
|
if (rc != 0) {
|
|
@@ -4201,15 +4201,10 @@ yep_engine* yep_engine_create(const yep_allocator* sys) {
|
|
|
4201
4201
|
* length is not strlen()'s: the INPUT may carry NUL bytes of its own,
|
|
4202
4202
|
* and a strlen() of the copy truncates the run at the first one (the
|
|
4203
4203
|
* nightly's run 38524928004: "\0\n---\r<U+2028>" whole-parsed as an
|
|
4204
|
-
* empty stream while the chunked cut skipped the copy).
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
return p;
|
|
4209
|
-
}
|
|
4210
|
-
e->norm_buf = out;
|
|
4211
|
-
return out;
|
|
4212
|
-
}
|
|
4204
|
+
* empty stream while the chunked cut skipped the copy). The context
|
|
4205
|
+
* walk behind the copy lives below (issue #638); since #839 the
|
|
4206
|
+
* chunked route threads it across --- cuts so every document
|
|
4207
|
+
* normalizes to the same bytes the one-buffer walk produces. */
|
|
4213
4208
|
|
|
4214
4209
|
/* The NEL/LS/PS -> '\n' copy (the one-shot path rides this BEFORE the
|
|
4215
4210
|
* engine so the normalized bytes own the document's `transcoded` slot;
|
|
@@ -4258,6 +4253,13 @@ typedef struct yep_norm_ctx {
|
|
|
4258
4253
|
int bs_content;
|
|
4259
4254
|
uint32_t bs_indent; /* the header line's indent; (uint32_t)-1 = the
|
|
4260
4255
|
* doc-inline root rule (markers only) */
|
|
4256
|
+
uint8_t started; /* at least one byte consumed: the walk's i == 0
|
|
4257
|
+
* clauses are stream-start, not buffer-start —
|
|
4258
|
+
* the chunked route resumes mid-stream at a ---
|
|
4259
|
+
* cut, and the carried context must say so */
|
|
4260
|
+
unsigned char prev; /* the last consumed byte (valid when started):
|
|
4261
|
+
* the '#' and line-start tests peek p[i - 1],
|
|
4262
|
+
* which at a resumed buffer is carried state */
|
|
4261
4263
|
} yep_norm_ctx;
|
|
4262
4264
|
|
|
4263
4265
|
typedef struct yep_norm_tok {
|
|
@@ -4415,8 +4417,12 @@ static yep_norm_tok norm_step(yep_norm_ctx* c, const char* p, size_t len, size_t
|
|
|
4415
4417
|
norm_break_arms(c);
|
|
4416
4418
|
return t;
|
|
4417
4419
|
}
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
+
/* the i == 0 clauses below are STREAM start: `started`/`prev` carry
|
|
4421
|
+
* them across the chunked route's per-document resumes (issue #839)
|
|
4422
|
+
* — a fresh context at a --- cut would otherwise read the resumed
|
|
4423
|
+
* buffer's first byte as a line start the whole walk never saw */
|
|
4424
|
+
if (ch == '#' && (!c->started || c->at_break || c->prev == '\n' || c->prev == '\r' ||
|
|
4425
|
+
c->prev == ' ' || c->prev == '\t')) {
|
|
4420
4426
|
c->in_comment = 1;
|
|
4421
4427
|
c->at_break = 0;
|
|
4422
4428
|
return t;
|
|
@@ -4429,7 +4435,7 @@ static yep_norm_tok norm_step(yep_norm_ctx* c, const char* p, size_t len, size_t
|
|
|
4429
4435
|
return t;
|
|
4430
4436
|
}
|
|
4431
4437
|
|
|
4432
|
-
int line_start = (
|
|
4438
|
+
int line_start = (!c->started || c->at_break || c->prev == '\n' || c->prev == '\r');
|
|
4433
4439
|
|
|
4434
4440
|
/* block scalars: inside the fold no quote opens and every break
|
|
4435
4441
|
* keeps its fold; the region ends at a col-0 marker, a %-line
|
|
@@ -4519,7 +4525,7 @@ static yep_norm_tok norm_step(yep_norm_ctx* c, const char* p, size_t len, size_t
|
|
|
4519
4525
|
if (!c->bs_open && ch == '-' && i + 2 < len && p[i + 1] == '-' && p[i + 2] == '-' &&
|
|
4520
4526
|
(i + 3 >= len || p[i + 3] == ' ' || p[i + 3] == '\t' || p[i + 3] == '\n' ||
|
|
4521
4527
|
p[i + 3] == '\r') &&
|
|
4522
|
-
(c->at_break ||
|
|
4528
|
+
(c->at_break || !c->started)) {
|
|
4523
4529
|
c->in_flow = 0; /* the marker bounds the document even when the
|
|
4524
4530
|
* walk still believes a flow is open (the same
|
|
4525
4531
|
* round-35 law as the in-quote rescue) */
|
|
@@ -4563,22 +4569,80 @@ static yep_norm_tok norm_step(yep_norm_ctx* c, const char* p, size_t len, size_t
|
|
|
4563
4569
|
}
|
|
4564
4570
|
c->tok_start = 0;
|
|
4565
4571
|
}
|
|
4566
|
-
if (ch == '
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4572
|
+
if ((ch == '[' || ch == '{') && (c->tok_start || c->prev == ':')) {
|
|
4573
|
+
/* a flow opener begins a token slot — at a token position, or
|
|
4574
|
+
* directly after the value ':' ("k:{a: 1}" opens; the blank
|
|
4575
|
+
* twin "k: {" rides tok_start already). Unconditioned, a
|
|
4576
|
+
* plain's interior '[' ("ya200%[") opened a PHANTOM flow whose
|
|
4577
|
+
* ',' armed the next token slot and a following "!<" opened a
|
|
4578
|
+
* phantom verbatim — breaks inside verbatim ride unnormalized,
|
|
4579
|
+
* the raw NELs defeated the line-facts kernel, and the plain
|
|
4580
|
+
* fold rendered one fold-SPACE per break instead of the n-1
|
|
4581
|
+
* newline tally (the r98 nightly — the #836 phantom's flow
|
|
4582
|
+
* half; the comma half landed in #836 itself). */
|
|
4583
|
+
c->tok_start = 1;
|
|
4571
4584
|
c->in_flow++;
|
|
4572
|
-
} else if (ch == '
|
|
4585
|
+
} else if (ch == ',') {
|
|
4586
|
+
/* flow separators glue the next token — THE COMMA IN FLOW
|
|
4587
|
+
* ONLY. The unconditioned arm let a BLOCK plain's interior
|
|
4588
|
+
* comma arm tok_start, a following "!<" opened a phantom
|
|
4589
|
+
* verbatim tag that swallowed the rest of the input (breaks
|
|
4590
|
+
* inside ride unnormalized), and the raw NEL/LS/PS bytes then
|
|
4591
|
+
* defeated the line-facts kernel's \n/\r law — the plain
|
|
4592
|
+
* fold's blank-line tally lost them (the r96 nightly,
|
|
4593
|
+
* yeptris#836, "b,,,!<!<"+NEL^3). ':' stays unconditioned:
|
|
4594
|
+
* the BLOCK value position rides it ("k: 'x'" opens the
|
|
4595
|
+
* quote, the NormLsPs pins). */
|
|
4573
4596
|
if (c->in_flow > 0) {
|
|
4574
|
-
c->
|
|
4597
|
+
c->tok_start = 1;
|
|
4598
|
+
}
|
|
4599
|
+
} else if (ch == ':') {
|
|
4600
|
+
/* the separator law (#833's own predicate): a ':' arms the
|
|
4601
|
+
* next token slot only before a blank/EOL/EOF — "k: 'x'"
|
|
4602
|
+
* opens the value quote (the NormLsPs pins) while an
|
|
4603
|
+
* interior "x:!<" of a block plain does NOT (the phantom
|
|
4604
|
+
* verbatim again, the #836 colon-led twin) */
|
|
4605
|
+
if (i + 1 >= len || p[i + 1] == ' ' || p[i + 1] == '\t' || p[i + 1] == '\n' ||
|
|
4606
|
+
p[i + 1] == '\r') {
|
|
4607
|
+
c->tok_start = 1;
|
|
4575
4608
|
}
|
|
4609
|
+
} else if (ch == ']' || ch == '}') {
|
|
4610
|
+
c->tok_start = 1;
|
|
4576
4611
|
}
|
|
4577
4612
|
return t;
|
|
4578
4613
|
}
|
|
4579
4614
|
|
|
4615
|
+
char* yep_engine_normalize_breaks(const yep_allocator* sys, const char* p, size_t len,
|
|
4616
|
+
size_t* out_len, int* kept_raw);
|
|
4617
|
+
|
|
4618
|
+
static char* norm_breaks_run(const yep_allocator* sys, const char* p, size_t len, size_t* out_len,
|
|
4619
|
+
int* kept_raw, yep_norm_ctx* ctx);
|
|
4620
|
+
|
|
4580
4621
|
char* yep_engine_normalize_breaks(const yep_allocator* sys, const char* p, size_t len,
|
|
4581
4622
|
size_t* out_len, int* kept_raw) {
|
|
4623
|
+
return norm_breaks_run(sys, p, len, out_len, kept_raw, NULL);
|
|
4624
|
+
}
|
|
4625
|
+
|
|
4626
|
+
/* The context-threaded core (#839). ctx == NULL is the one-shot form:
|
|
4627
|
+
* fresh state, and the !exotic early exit stands (no walk, no state).
|
|
4628
|
+
* A non-NULL ctx rides in the step state: the chunked route parses
|
|
4629
|
+
* whole documents, so the walk never sees a mid-construct cut — the
|
|
4630
|
+
* divergence was the RESUME state. A --- cut lands exactly where the
|
|
4631
|
+
* whole walk holds some carried state (an open quote it has not been
|
|
4632
|
+
* rescued from, at_break, the raw prev byte); resuming fresh re-lexes
|
|
4633
|
+
* the marker line differently ("--- 'tail": whole's rescue leaves
|
|
4634
|
+
* tok_start 0 so the apostrophe is content, a fresh context's
|
|
4635
|
+
* tok_start 1 opens a quote). Carrying, never resetting: doc N's walk
|
|
4636
|
+
* sees the same bytes with the same state whole holds at the cut, so
|
|
4637
|
+
* doc N + 1's start state equals whole's there — the induction makes
|
|
4638
|
+
* the concatenated documents byte-identical to the one-buffer walk.
|
|
4639
|
+
* The probe ALWAYS runs in this form (even without exotic leads): the
|
|
4640
|
+
* carried state must advance over every byte, or the next resume
|
|
4641
|
+
* starts stale. Both outcomes keep zero-copy semantics: a document
|
|
4642
|
+
* whose exotic bytes all ride raw is used as-is, and those raw bytes
|
|
4643
|
+
* are exactly what the one-buffer walk's copy carries for them. */
|
|
4644
|
+
static char* norm_breaks_run(const yep_allocator* sys, const char* p, size_t len, size_t* out_len,
|
|
4645
|
+
int* kept_raw, yep_norm_ctx* ctx) {
|
|
4582
4646
|
if (kept_raw != NULL) {
|
|
4583
4647
|
*kept_raw = 0;
|
|
4584
4648
|
}
|
|
@@ -4595,15 +4659,21 @@ char* yep_engine_normalize_breaks(const yep_allocator* sys, const char* p, size_
|
|
|
4595
4659
|
exotic = 1; /* any NEL/LS/PS lead byte needs the context walk */
|
|
4596
4660
|
break;
|
|
4597
4661
|
}
|
|
4598
|
-
if (!exotic) {
|
|
4599
|
-
return NULL;
|
|
4600
|
-
}
|
|
4601
4662
|
yep_norm_ctx probe;
|
|
4602
|
-
|
|
4603
|
-
|
|
4663
|
+
if (ctx != NULL) {
|
|
4664
|
+
probe = *ctx;
|
|
4665
|
+
} else {
|
|
4666
|
+
if (!exotic) {
|
|
4667
|
+
return NULL;
|
|
4668
|
+
}
|
|
4669
|
+
memset(&probe, 0, sizeof(probe));
|
|
4670
|
+
probe.tok_start = 1;
|
|
4671
|
+
}
|
|
4604
4672
|
int found = 0;
|
|
4605
4673
|
for (size_t j = 0; j < len;) {
|
|
4606
4674
|
yep_norm_tok t = norm_step(&probe, p, len, j);
|
|
4675
|
+
probe.started = 1;
|
|
4676
|
+
probe.prev = (unsigned char)p[j + t.n - 1];
|
|
4607
4677
|
if (t.fold_off >= 0) {
|
|
4608
4678
|
found = 1;
|
|
4609
4679
|
break;
|
|
@@ -4611,22 +4681,34 @@ char* yep_engine_normalize_breaks(const yep_allocator* sys, const char* p, size_
|
|
|
4611
4681
|
j += t.n;
|
|
4612
4682
|
}
|
|
4613
4683
|
if (!found) {
|
|
4614
|
-
if (
|
|
4615
|
-
*
|
|
4684
|
+
if (ctx != NULL) {
|
|
4685
|
+
*ctx = probe; /* the carried state advanced even with no fold */
|
|
4686
|
+
} else {
|
|
4687
|
+
if (kept_raw != NULL) {
|
|
4688
|
+
*kept_raw = 1; /* every exotic byte rides raw */
|
|
4689
|
+
}
|
|
4690
|
+
return NULL; /* the exotic bytes all ride inside quoted regions:
|
|
4691
|
+
* the zero-copy path keeps them raw (the fix) */
|
|
4616
4692
|
}
|
|
4617
|
-
return NULL;
|
|
4618
|
-
* the zero-copy path keeps them raw (the fix) */
|
|
4693
|
+
return NULL;
|
|
4619
4694
|
}
|
|
4620
4695
|
char* out = yep_alloc(sys, len + 1);
|
|
4621
4696
|
if (out == NULL) {
|
|
4622
4697
|
return NULL;
|
|
4623
4698
|
}
|
|
4624
4699
|
yep_norm_ctx cp;
|
|
4625
|
-
|
|
4626
|
-
|
|
4700
|
+
if (ctx != NULL) {
|
|
4701
|
+
cp = *ctx; /* restart from the same carried state: the probe's
|
|
4702
|
+
* partial walk (it broke at the fold) is discarded */
|
|
4703
|
+
} else {
|
|
4704
|
+
memset(&cp, 0, sizeof(cp));
|
|
4705
|
+
cp.tok_start = 1;
|
|
4706
|
+
}
|
|
4627
4707
|
size_t o = 0;
|
|
4628
4708
|
for (size_t j = 0; j < len;) {
|
|
4629
4709
|
yep_norm_tok t = norm_step(&cp, p, len, j);
|
|
4710
|
+
cp.started = 1;
|
|
4711
|
+
cp.prev = (unsigned char)p[j + t.n - 1];
|
|
4630
4712
|
if (t.fold_off < 0) {
|
|
4631
4713
|
if (kept_raw != NULL && *kept_raw == 0) {
|
|
4632
4714
|
for (size_t m = 0; m + 1 < t.n; m++) {
|
|
@@ -4652,6 +4734,19 @@ char* yep_engine_normalize_breaks(const yep_allocator* sys, const char* p, size_
|
|
|
4652
4734
|
if (out_len != NULL) {
|
|
4653
4735
|
*out_len = o;
|
|
4654
4736
|
}
|
|
4737
|
+
if (ctx != NULL) {
|
|
4738
|
+
*ctx = cp;
|
|
4739
|
+
}
|
|
4740
|
+
return out;
|
|
4741
|
+
}
|
|
4742
|
+
|
|
4743
|
+
static const char* e_normalize_breaks(yep_engine* e, const char* p, size_t len, size_t* out_len,
|
|
4744
|
+
yep_norm_ctx* ctx) {
|
|
4745
|
+
char* out = norm_breaks_run(e->sys, p, len, out_len, NULL, ctx);
|
|
4746
|
+
if (out == NULL) {
|
|
4747
|
+
return p;
|
|
4748
|
+
}
|
|
4749
|
+
e->norm_buf = out;
|
|
4655
4750
|
return out;
|
|
4656
4751
|
}
|
|
4657
4752
|
|
|
@@ -4678,6 +4773,11 @@ typedef struct yep_stepstate {
|
|
|
4678
4773
|
int at_break; /* the previous position was a line break
|
|
4679
4774
|
* (multibyte breaks leave a non-break byte as
|
|
4680
4775
|
* p[i-1], so the '#' prev-byte test misses them) */
|
|
4776
|
+
yep_norm_ctx nctx; /* the break normalizer's carried context (#839):
|
|
4777
|
+
* each document's walk resumes with exactly the
|
|
4778
|
+
* state the whole-stream walk holds at the ---
|
|
4779
|
+
* cut, so per-document normalization is
|
|
4780
|
+
* byte-identical to the one-buffer walk */
|
|
4681
4781
|
} yep_stepstate;
|
|
4682
4782
|
|
|
4683
4783
|
static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep_sink* sink,
|
|
@@ -4834,6 +4934,19 @@ static size_t step_scan(yep_stepstate* st) {
|
|
|
4834
4934
|
st->tok_start = 1;
|
|
4835
4935
|
st->word_led = 0;
|
|
4836
4936
|
st->at_break = 1;
|
|
4937
|
+
} else if (c == '\r' && (i + 1 >= st->len || (unsigned char)p[i + 1] != '\n')) {
|
|
4938
|
+
/* a lone CR is a line break too (CRLF rides the \n arm
|
|
4939
|
+
* next iteration; the state is identical either way).
|
|
4940
|
+
* Missing this arm kept the scan inside a comment whose
|
|
4941
|
+
* line ended CR, the tab-led `{ {?` flow opener on the
|
|
4942
|
+
* next line went untracked, and the cut landed at the
|
|
4943
|
+
* following --- INSIDE the engine's open flow (the r97
|
|
4944
|
+
* nightly, yeptris#839: whole errored at the flow's ---
|
|
4945
|
+
* while chunked cut and errored at the cut edge) */
|
|
4946
|
+
st->in_comment = 0;
|
|
4947
|
+
st->tok_start = 1;
|
|
4948
|
+
st->word_led = 0;
|
|
4949
|
+
st->at_break = 1;
|
|
4837
4950
|
} else if (c == 0xC2 && i + 1 < st->len && (unsigned char)p[i + 1] == 0x85) {
|
|
4838
4951
|
i++;
|
|
4839
4952
|
st->in_comment = 0;
|
|
@@ -5191,6 +5304,10 @@ int yep_engine_step(yep_engine* e, const char* chunk, size_t len, int final, con
|
|
|
5191
5304
|
}
|
|
5192
5305
|
yep_stepstate* st = e->step;
|
|
5193
5306
|
st->tok_start = 1; /* the buffer starts at a line start */
|
|
5307
|
+
if (st->nctx.started == 0) {
|
|
5308
|
+
st->nctx.tok_start = 1; /* the stream's first walk: the same
|
|
5309
|
+
* fresh state the one-shot starts */
|
|
5310
|
+
}
|
|
5194
5311
|
if (len > 0) {
|
|
5195
5312
|
if (st->len + len > st->cap) {
|
|
5196
5313
|
size_t cap = st->cap ? st->cap : 4096;
|
|
@@ -5256,7 +5373,8 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
|
|
|
5256
5373
|
* it, and the next transcode replaces it. */
|
|
5257
5374
|
e->parsing_final = emit_end;
|
|
5258
5375
|
size_t norm_len = len;
|
|
5259
|
-
|
|
5376
|
+
yep_norm_ctx* nctx = e->step != NULL ? &((yep_stepstate*)e->step)->nctx : NULL;
|
|
5377
|
+
e->p = e_normalize_breaks(e, buf, len, &norm_len, nctx);
|
|
5260
5378
|
e->len = norm_len;
|
|
5261
5379
|
e->pos = 0;
|
|
5262
5380
|
e->line = 1 + e->line_base;
|
|
@@ -5314,7 +5432,7 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
|
|
|
5314
5432
|
e_fail(e, YEP_ERR_TAB_IN_INDENT, e->pos + li.indent);
|
|
5315
5433
|
goto fail;
|
|
5316
5434
|
}
|
|
5317
|
-
li.indent = (
|
|
5435
|
+
li.indent = (uint32_t)(t - li.offset);
|
|
5318
5436
|
}
|
|
5319
5437
|
if (li.flags & YEP_LF_DIRECTIVE) {
|
|
5320
5438
|
if (doc_open) {
|
|
@@ -5634,7 +5752,7 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
|
|
|
5634
5752
|
* dash-blank test is computed once per line (TODO.restructure/75
|
|
5635
5753
|
* — it was spelled out twice below); the top frame loads once
|
|
5636
5754
|
* per iteration. */
|
|
5637
|
-
|
|
5755
|
+
uint32_t c = li.indent;
|
|
5638
5756
|
const int dash_blank =
|
|
5639
5757
|
li.first == '-' &&
|
|
5640
5758
|
(li.offset + li.indent + 1 >= e->len || e->p[li.offset + li.indent + 1] == ' ' ||
|
|
@@ -90,13 +90,13 @@ typedef struct yep_sink {
|
|
|
90
90
|
* placed, 0 = not handled (the engine emits the two events
|
|
91
91
|
* exactly as before), <0 = abort. */
|
|
92
92
|
int (*on_block_pair)(void* ctx, const yep_view* key, const struct yep_block_value* v,
|
|
93
|
-
uint32_t line,
|
|
93
|
+
uint32_t line, uint32_t key_col, uint32_t val_col);
|
|
94
94
|
/* Optional block-open fast path (TODO.restructure/57): a `key:`
|
|
95
95
|
* line whose value lives on FOLLOWING lines, when the engine is
|
|
96
96
|
* about to open a FRESH mapping. 1 = the sink built the map node
|
|
97
97
|
* (placed, stack pushed) and the key node — the engine opens its
|
|
98
98
|
* frame silently and skips both events; 0 = events as before. */
|
|
99
|
-
int (*on_block_open)(void* ctx, const yep_view* key, uint32_t line,
|
|
99
|
+
int (*on_block_open)(void* ctx, const yep_view* key, uint32_t line, uint32_t key_col);
|
|
100
100
|
/* Optional dash-item fast path (TODO.restructure/78): a classified
|
|
101
101
|
* `- value` plain item after the engine opened (or continued) the
|
|
102
102
|
* block sequence. 1 = the sink built and placed the item node,
|
|
@@ -248,7 +248,8 @@ static yep_tag_id compat11(void* ctx, const char* p, uint32_t n) {
|
|
|
248
248
|
if (n - i > 2 && p[i] == '0' && (p[i + 1] == 'b' || p[i + 1] == 'B')) {
|
|
249
249
|
return is_digits_us(p + i + 2, n - i - 2) ? 1 : 0;
|
|
250
250
|
}
|
|
251
|
-
if (n - i > 2 && p[i] == '0' &&
|
|
251
|
+
if (n - i > 2 && p[i] == '0' &&
|
|
252
|
+
p[i + 1] == 'x') { /* lowercase only — psych keeps "0X1A" a String */
|
|
252
253
|
uint32_t k = i + 2;
|
|
253
254
|
if (p[k] == '_') {
|
|
254
255
|
k++;
|
|
@@ -78,7 +78,9 @@ static yep_tag_id core12(void* ctx, const char* p, uint32_t n) {
|
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
|
-
if (n - i > 2 && p[i] == '0' &&
|
|
81
|
+
if (n - i > 2 && p[i] == '0' &&
|
|
82
|
+
p[i + 1] == 'x') { /* lowercase only: the core schema's int regexp; "0X1A" rides a string
|
|
83
|
+
(psych agrees) */
|
|
82
84
|
for (uint32_t k = i + 2; k < n; k++) {
|
|
83
85
|
char c = p[k];
|
|
84
86
|
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
|
|
@@ -250,6 +250,9 @@ int yep_json_number_scan(const char* p, size_t len, size_t* i, int* is_float, in
|
|
|
250
250
|
double* dv) {
|
|
251
251
|
size_t k = *i;
|
|
252
252
|
int neg = 0;
|
|
253
|
+
if (k >= len) {
|
|
254
|
+
return 0; /* the caller's index is at the end: p[len] is OOB */
|
|
255
|
+
}
|
|
253
256
|
if (p[k] == '-') {
|
|
254
257
|
neg = 1;
|
|
255
258
|
k++;
|
|
@@ -438,6 +441,9 @@ int yep_json_number(const char* p, size_t len, size_t* i) {
|
|
|
438
441
|
* the full scan (the 2M tape-diff oracle pins the equivalence). */
|
|
439
442
|
int yep_json_number_shape(const char* p, size_t len, size_t* i, int* is_float) {
|
|
440
443
|
size_t k = *i;
|
|
444
|
+
if (k >= len) {
|
|
445
|
+
return 0; /* the caller's index is at the end: p[len] is OOB */
|
|
446
|
+
}
|
|
441
447
|
if (p[k] == '-') {
|
|
442
448
|
k++;
|
|
443
449
|
}
|