yeptris 0.6.18.2-arm-linux-eabihf → 0.6.20.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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/ext/build_windows_native.rb +31 -12
  3. data/lib/yeptris/3.4/native.so +0 -0
  4. data/lib/yeptris/materializer.rb +12 -11
  5. data/lib/yeptris/psych/handler.rb +5 -0
  6. data/lib/yeptris/psych/parser.rb +8 -3
  7. data/lib/yeptris/psych/tree_builder.rb +119 -0
  8. data/lib/yeptris/psych.rb +4 -0
  9. data/lib/yeptris.rb +15 -11
  10. data/libyeptris.so +0 -0
  11. data/vendor/libyeptris/CMakeLists.txt +1 -1
  12. data/vendor/libyeptris/src/CMakeLists.txt +1 -0
  13. data/vendor/libyeptris/src/include/yeptris/events.h +8 -1
  14. data/vendor/libyeptris/src/yeptris/cbor/decode.c +1 -0
  15. data/vendor/libyeptris/src/yeptris/common/simd_text.h +47 -13
  16. data/vendor/libyeptris/src/yeptris/common/simd_text_avx2.c +86 -8
  17. data/vendor/libyeptris/src/yeptris/common/simd_text_neon.c +82 -8
  18. data/vendor/libyeptris/src/yeptris/common/simd_text_scalar.c +10 -6
  19. data/vendor/libyeptris/src/yeptris/doc.h +8 -4
  20. data/vendor/libyeptris/src/yeptris/dom/ytape.c +640 -0
  21. data/vendor/libyeptris/src/yeptris/dom/ytape.h +77 -0
  22. data/vendor/libyeptris/src/yeptris/emit/writer.c +7 -2
  23. data/vendor/libyeptris/src/yeptris/events/capture.c +5 -1
  24. data/vendor/libyeptris/src/yeptris/parse/engine.c +150 -3
  25. data/vendor/libyeptris/src/yeptris/parse/events.h +6 -0
  26. data/vendor/libyeptris/src/yeptris/parse.c +144 -42
  27. data/vendor/libyeptris/src/yeptris/scan/json.c +43 -5
  28. data/vendor/libyeptris/src/yeptris/scan/json.h +9 -2
  29. data/vendor/libyeptris/src/yeptris/tape.c +539 -163
  30. data/vendor/libyeptris/src/yeptris/tape_in.h +12 -0
  31. metadata +5 -2
  32. data/lib/yeptris/native-3.4.so +0 -0
@@ -0,0 +1,77 @@
1
+ /* ytape.h — the packed YAML record tape (#378, TODO.max-perf/12).
2
+ *
3
+ * The eager DOM builders' callback stream packed into 8-byte words:
4
+ * the common block ops carry spans only (the resolver call and the
5
+ * 48-byte node build defer to replay), the general event path packs
6
+ * into a props word plus span words. Replay calls the SAME builder
7
+ * functions with reconstructed views — resolution and placement
8
+ * semantics are the eager path's by construction (the differential
9
+ * gate pins tree identity across the corpora).
10
+ *
11
+ * Spans are input-relative when they fall inside [input, input+len]
12
+ * and fit 24 bits; anything else (pool content, oversized spans) is a
13
+ * generic (ptr, len) pair — the engine's finish pool owns that
14
+ * memory, its blocks are stable until the document frees it, and the
15
+ * lazy route keeps the pool on the document until replay copies (the
16
+ * builders copy exactly what must outlive the engine — dom_str_in).
17
+ *
18
+ * The recorder mirrors the eager builders' return-code discipline
19
+ * (depth caps answer 0 so the engine's event path owns the error;
20
+ * OOM answers <0) so error precedence survives the detour. */
21
+ #ifndef YEP_YTAPE_H
22
+ #define YEP_YTAPE_H
23
+
24
+ #include <stddef.h>
25
+
26
+ #include "parse/events.h"
27
+
28
+ #ifdef __cplusplus
29
+ extern "C" {
30
+ #endif
31
+
32
+ typedef struct yep_pool yep_pool;
33
+
34
+ typedef struct yep_ytape {
35
+ uint64_t* w;
36
+ uint32_t count;
37
+ uint32_t cap;
38
+ const char* input; /* the POST-BOM data pointer (span base) */
39
+ size_t input_len;
40
+ int depth; /* the DOM's depth mirror (cap parity) */
41
+ int max_depth; /* the engine's flow-walk limit, replayed */
42
+ int flow_strict; /* mirrors dom->flow_strict (0 everywhere today) */
43
+ int docs; /* DOCUMENT_START count (the empty-stream check) */
44
+ int oom;
45
+ uint32_t flow_mark; /* record mark for the staged flow build */
46
+ } yep_ytape;
47
+
48
+ /* Record kinds — byte 7 of a word. */
49
+ enum {
50
+ YTP_SPAN_IN = 0, /* [off:32][len:24][0x00] */
51
+ YTP_EV_COMPACT = 1, /* stream/document frames: [type:8][...][kind] */
52
+ YTP_EVENT = 2, /* props + value + [tag] + [anchor] */
53
+ YTP_SCALAR = 3, /* props + value + [tag] + [anchor]; is_item bit
54
+ * routes the replay to the dash-item builder */
55
+ YTP_ITEM = 4, /* borrowed dash item: [off:32][len:24][kind] */
56
+ YTP_PAIR = 5, /* props + key + value + [anchor] + [anchor hi] */
57
+ YTP_OPEN = 6, /* `key:`'s fresh map: [off:32][len:24][kind] */
58
+ YTP_FLOW = 7, /* props + [open:32|len:32] + [tag] + [anchor] */
59
+ YTP_SPAN_POOL = 0xFF, /* [len:32][kind] + [ptr:64] */
60
+ };
61
+
62
+ /* Recorder lifecycle. Returns 0, or -1 when the word carve fails
63
+ * (caller answers YEPTRIS_ERROR_MEMORY — bounded-parse law). */
64
+ int ytap_init(yep_ytape* t, const char* input, size_t len, int max_depth);
65
+ void ytap_sink(yep_ytape* t, yep_sink* sink);
66
+ void ytap_free(yep_ytape* t);
67
+
68
+ /* Replay: builds the node tree through the eager builders. Returns 0,
69
+ * or -1 (a builder refused — allocation/depth; the lazy route treats
70
+ * it as the JSON tape route does). Sets d->input_base/len. */
71
+ int dom_from_ytape(yep_dom* d, const yep_ytape* t);
72
+
73
+ #ifdef __cplusplus
74
+ }
75
+ #endif
76
+
77
+ #endif /* YEP_YTAPE_H */
@@ -91,7 +91,12 @@ static void wr_put(yep_writer* w, const char* p, uint32_t n) {
91
91
  w->len += n;
92
92
  return;
93
93
  }
94
- if (w->grow && w->len + n > w->cap) {
94
+ /* the +1 reserves the terminator slot: the serializers write the
95
+ * NUL at p[len] after the run, and a write landing exactly on cap
96
+ * (len + n == cap) put that NUL one byte past the buffer — the
97
+ * first byte of the next heap block's header (the #182 flake:
98
+ * corrupt deterministic, detected later, timing-varying) */
99
+ if (w->grow && w->len + n + 1 > w->cap) {
95
100
  wr_grow(w, n);
96
101
  }
97
102
  if (w->oom) {
@@ -114,7 +119,7 @@ static void wr_byte(yep_writer* w, char c) {
114
119
  w->len++;
115
120
  return;
116
121
  }
117
- if (w->grow && w->len + 1 > w->cap) {
122
+ if (w->grow && w->len + 2 > w->cap) { /* +1 write, +1 terminator */
118
123
  wr_grow(w, 1);
119
124
  }
120
125
  if (w->oom) {
@@ -7,7 +7,7 @@
7
7
  #include "../../include/yeptris/events.h"
8
8
 
9
9
  /* The record IS the public ABI shape (events.h pins it). */
10
- YEPTRIS_CT_ASSERT(sizeof(YeptrisEventRecord) == 36);
10
+ YEPTRIS_CT_ASSERT(sizeof(YeptrisEventRecord) == 44);
11
11
 
12
12
  void yep_rec_init(yep_rec_store* s) {
13
13
  s->recs = NULL;
@@ -114,6 +114,8 @@ int yep_rec_on_event(void* ctx, const yep_event* ev) {
114
114
  }
115
115
  r->line = ev->line;
116
116
  r->col = ev->col;
117
+ r->end_line = ev->end_line;
118
+ r->end_col = ev->end_col;
117
119
  r->value_off = arena_put(s, (const char*)ev->value.p, (uint32_t)ev->value.len);
118
120
  r->value_len = (uint32_t)ev->value.len;
119
121
  r->anchor_off = arena_put(s, (const char*)ev->anchor.p, (uint32_t)ev->anchor.len);
@@ -135,6 +137,8 @@ void yep_rec_materialize(const yep_rec_store* s, size_t i, void* out) {
135
137
  e->implicit = (r->flags & YEPTRIS_EF_IMPLICIT) != 0;
136
138
  e->line = r->line;
137
139
  e->col = r->col;
140
+ e->end_line = r->end_line;
141
+ e->end_col = r->end_col;
138
142
  if (r->value_len > 0) {
139
143
  e->value = s->arena + r->value_off;
140
144
  e->value_len = r->value_len;
@@ -104,8 +104,11 @@ struct yep_engine {
104
104
  yep_view handle, prefix;
105
105
  } tagmap[8];
106
106
  int tagmap_n;
107
- int saw_yaml; /* %YAML seen for the pending document */
108
- void* step; /* yep_stepstate: resumable stepping (07) */
107
+ int saw_yaml; /* %YAML seen for the pending document */
108
+ size_t doc_begin; /* #179: first directive line of the pending doc
109
+ * (SIZE_MAX = none) — libyaml's DOCUMENT_START
110
+ * start_mark includes directives */
111
+ void* step; /* yep_stepstate: resumable stepping (07) */
109
112
 
110
113
  /* Flow single-pair deferral: a sequence entry's events are buffered
111
114
  * until we know whether ':' follows ("[a: b]" needs MAP_START before
@@ -134,6 +137,34 @@ static uint32_t e_col(const yep_engine* e, size_t at) {
134
137
  return at >= e->line_start ? (uint32_t)(at - e->line_start) : 0;
135
138
  }
136
139
 
140
+ /* #179: the (1-based line, 1-based col) of a byte offset. Unlike
141
+ * e_col this handles offsets on PRIOR lines — event ends whose scan
142
+ * already advanced past them (block scalars, collection closes).
143
+ * The backward walk covers only the span's own lines, so the total
144
+ * across a document stays linear in its size. */
145
+ static void e_pos_mark(const yep_engine* e, size_t at, uint32_t* line, uint32_t* col) {
146
+ if (at >= e->line_start) {
147
+ *line = e->line;
148
+ *col = (uint32_t)(at - e->line_start) + 1;
149
+ return;
150
+ }
151
+ uint32_t l = e->line;
152
+ size_t ls = e->line_start;
153
+ while (at < ls && ls > 0) {
154
+ /* p[ls-1] is the newline ENDED the previous line: start the
155
+ * walk below it, or ls never decreases (the infinite-loop bug
156
+ * the Stepping.Directive hang found) */
157
+ size_t q = ls - 1;
158
+ while (q > 0 && e->p[q - 1] != '\n') {
159
+ q--;
160
+ }
161
+ ls = q; /* line_start(l-1) */
162
+ l--;
163
+ }
164
+ *line = l;
165
+ *col = (uint32_t)(at - ls) + 1;
166
+ }
167
+
137
168
  static int e_fail(yep_engine* e, yep_err_code code, size_t at) {
138
169
  yep_error_set(&e->err, code, e->line, e_col(e, at) + 1, at, NULL);
139
170
  return -1;
@@ -374,6 +405,18 @@ static int e_open_seq(yep_engine* e, uint16_t col, uint32_t line, uint32_t coln,
374
405
  ev.tag = tag;
375
406
  ev.line = line;
376
407
  ev.col = coln;
408
+ ev.end_line = line; /* block opens are zero-span (libyaml) — except
409
+ * the sequence at its parent mapping's column
410
+ * ("k:\n- a"), which ends after the dash */
411
+ ev.end_col = coln;
412
+ for (int i = e->depth - 1; i >= 0; i--) {
413
+ if (e->frames[i].kind == YEP_FRAME_MAP) {
414
+ if (col == e->frames[i].col) {
415
+ ev.end_col = coln + 1;
416
+ }
417
+ break;
418
+ }
419
+ }
377
420
  return emit_now(e, &ev) == 0 ? 0 : -2;
378
421
  }
379
422
 
@@ -403,6 +446,8 @@ static int e_open_map(yep_engine* e, uint16_t col, uint32_t line, uint32_t coln,
403
446
  ev.tag = tag;
404
447
  ev.line = line;
405
448
  ev.col = coln;
449
+ ev.end_line = line; /* block opens are zero-span (libyaml) */
450
+ ev.end_col = coln;
406
451
  return emit_now(e, &ev) == 0 ? 0 : -2;
407
452
  }
408
453
 
@@ -436,6 +481,16 @@ static int e_close_to(yep_engine* e, int to_depth) {
436
481
  yep_event ev;
437
482
  e_event_init(&ev,
438
483
  e->frames[e->depth].kind == YEP_FRAME_SEQ ? YEP_EV_SEQ_END : YEP_EV_MAP_END);
484
+ { /* libyaml: a block END's mark is the next token's position
485
+ * (zero-span) — the first non-space at the cursor, or EOF */
486
+ size_t at = e->pos;
487
+ while (at < e->len && e->p[at] == ' ') {
488
+ at++;
489
+ }
490
+ e_pos_mark(e, at, &ev.line, &ev.col);
491
+ ev.end_line = ev.line;
492
+ ev.end_col = ev.col;
493
+ }
439
494
  if (emit_now(e, &ev) != 0) {
440
495
  return -2;
441
496
  }
@@ -631,6 +686,7 @@ static int e_quoted_floor(yep_engine* e, yep_event* ev, uint16_t min_indent, int
631
686
  e->line_start = ls;
632
687
  }
633
688
  e->pos = after;
689
+ e_pos_mark(e, after, &ev->end_line, &ev->end_col);
634
690
  e_skip_inline_space(e);
635
691
  return 0;
636
692
  }
@@ -810,6 +866,7 @@ static int e_block_scalar(yep_engine* e, yep_event* ev, int parent_col) {
810
866
  ev->value.p = out; /* may be NULL for an empty block; len 0 */
811
867
  ev->borrowed = 0;
812
868
  ev->style = folded ? YEP_STYLE_FOLDED : YEP_STYLE_LITERAL;
869
+ e_pos_mark(e, e->pos, &ev->end_line, &ev->end_col);
813
870
  return 0;
814
871
  }
815
872
 
@@ -887,6 +944,11 @@ static int e_plain_multiline(yep_engine* e, yep_span s0, uint32_t block_floor, y
887
944
  break; /* the comment ends the scalar; later lines are new */
888
945
  }
889
946
  }
947
+ { /* #179: the source end = the last piece's content end */
948
+ const yep_view* last = &e->fold[e->fold_n - 1].content;
949
+ size_t lend = (size_t)(last->p - e->p) + last->len;
950
+ e_pos_mark(e, lend, &ev->end_line, &ev->end_col);
951
+ }
890
952
  if (e->fold_n == 1) {
891
953
  return 0; /* single line: the borrowed view stands */
892
954
  }
@@ -1082,6 +1144,7 @@ static int e_alias(yep_engine* e, yep_event* ev) {
1082
1144
  the DOM borrows it like any plain scalar — no
1083
1145
  arena copy per alias */
1084
1146
  ev->anchor_id = target;
1147
+ e_pos_mark(e, e->pos, &ev->end_line, &ev->end_col);
1085
1148
  e_skip_inline_space(e);
1086
1149
  return 0;
1087
1150
  }
@@ -1224,6 +1287,7 @@ static int e_flow_node(yep_engine* e, yep_event* ev, int keyish) {
1224
1287
  if ((c == ',' || c == ']' || c == '}' || c == ':') &&
1225
1288
  (!yep_view_is_empty(anchor) || !yep_view_is_empty(tag))) {
1226
1289
  ev->implicit = 1; /* properties with no node: a tagged null */
1290
+ e_pos_mark(e, e->pos, &ev->end_line, &ev->end_col);
1227
1291
  return 1;
1228
1292
  }
1229
1293
  if (c == '"' || c == '\'') {
@@ -1313,6 +1377,10 @@ static int e_flow_node(yep_engine* e, yep_event* ev, int keyish) {
1313
1377
  ev->style = YEP_STYLE_PLAIN;
1314
1378
  ev->implicit = 1;
1315
1379
  ev->multiline = (e->fold_n > 1) || crossed_break;
1380
+ { /* #179: the source end = the last fold piece's content end */
1381
+ const yep_view* lastp = &e->fold[e->fold_n - 1].content;
1382
+ e_pos_mark(e, (size_t)(lastp->p - e->p) + lastp->len, &ev->end_line, &ev->end_col);
1383
+ }
1316
1384
  return 1;
1317
1385
  }
1318
1386
 
@@ -1464,6 +1532,8 @@ static int e_flow_json(yep_engine* e, yep_view anchor, yep_view tag, uint32_t an
1464
1532
  ev.tag = tag;
1465
1533
  ev.line = cur_line;
1466
1534
  ev.col = (uint32_t)(open_pos + 1 - cur_ls) + 1;
1535
+ ev.end_line = cur_line; /* flow opens end after the indicator */
1536
+ ev.end_col = (uint32_t)(open_pos + 2 - cur_ls) + 1;
1467
1537
  if (emit_now(e, &ev) != 0) {
1468
1538
  return -2;
1469
1539
  }
@@ -1488,6 +1558,8 @@ static int e_flow_json(yep_engine* e, yep_view anchor, yep_view tag, uint32_t an
1488
1558
  jx_advance_line(e, &cur_scan, i, &cur_line, &cur_ls);
1489
1559
  ev.line = cur_line;
1490
1560
  ev.col = (uint32_t)(i - cur_ls) + 1;
1561
+ ev.end_line = cur_line;
1562
+ ev.end_col = (uint32_t)(i + 1 - cur_ls) + 1;
1491
1563
  if (emit_now(e, &ev) != 0) {
1492
1564
  return -2;
1493
1565
  }
@@ -1509,6 +1581,8 @@ static int e_flow_json(yep_engine* e, yep_view anchor, yep_view tag, uint32_t an
1509
1581
  jx_advance_line(e, &cur_scan, i, &cur_line, &cur_ls);
1510
1582
  ev.line = cur_line;
1511
1583
  ev.col = (uint32_t)(i + 1 - cur_ls) + 1;
1584
+ ev.end_line = cur_line; /* flow opens end after the indicator */
1585
+ ev.end_col = (uint32_t)(i + 2 - cur_ls) + 1;
1512
1586
  if (emit_now(e, &ev) != 0) {
1513
1587
  return -2;
1514
1588
  }
@@ -1582,6 +1656,11 @@ static int e_flow_json(yep_engine* e, yep_view anchor, yep_view tag, uint32_t an
1582
1656
  return e_fail(e, YEP_ERR_KEY_TOO_LONG, vstart);
1583
1657
  }
1584
1658
  }
1659
+ if (raw_end == vstart) {
1660
+ raw_end = i; /* numbers/literals advance i, not raw_end */
1661
+ }
1662
+ ev.end_line = cur_line;
1663
+ ev.end_col = (uint32_t)(raw_end - cur_ls) + 1;
1585
1664
  if (emit_now(e, &ev) != 0) {
1586
1665
  return -2;
1587
1666
  }
@@ -1652,6 +1731,8 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
1652
1731
  ev.tag = tag;
1653
1732
  ev.line = e->line;
1654
1733
  ev.col = e_col(e, e->pos);
1734
+ ev.end_line = e->line; /* flow opens end after the indicator */
1735
+ ev.end_col = e_col(e, e->pos) + 1;
1655
1736
  if (emit_now(e, &ev) != 0) {
1656
1737
  return -2;
1657
1738
  }
@@ -1755,6 +1836,8 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
1755
1836
  ev.tag = pt;
1756
1837
  ev.line = e->line;
1757
1838
  ev.col = e_col(e, e->pos);
1839
+ ev.end_line = e->line; /* flow opens end after the indicator */
1840
+ ev.end_col = e_col(e, e->pos) + 1;
1758
1841
  if (emit_now(e, &ev) != 0) {
1759
1842
  return -2;
1760
1843
  }
@@ -1861,6 +1944,9 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
1861
1944
  mk.flow = 1;
1862
1945
  mk.line = ev.line;
1863
1946
  mk.col = ev.col;
1947
+ mk.end_line = ev.line; /* virtual opener: zero-span
1948
+ * at the implied position */
1949
+ mk.end_col = ev.col;
1864
1950
  if (emit_now(e, &mk) != 0) {
1865
1951
  return -2;
1866
1952
  }
@@ -2045,6 +2131,11 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
2045
2131
  }
2046
2132
  e->pos++;
2047
2133
  e_event_init(&ev, st[n - 1].kind ? YEP_EV_MAP_END : YEP_EV_SEQ_END);
2134
+ /* the close indicator's span: e->pos sits just past it */
2135
+ ev.line = e->line;
2136
+ ev.col = e_col(e, e->pos - 1) + 1;
2137
+ ev.end_line = e->line;
2138
+ ev.end_col = e_col(e, e->pos) + 1;
2048
2139
  if (emit_now(e, &ev) != 0) {
2049
2140
  return -2;
2050
2141
  }
@@ -2135,6 +2226,9 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
2135
2226
  yep_event mk;
2136
2227
  e_event_init(&mk, YEP_EV_MAP_START);
2137
2228
  mk.flow = 1;
2229
+ e_pos_mark(e, e->pos, &mk.line, &mk.col);
2230
+ mk.end_line = mk.line; /* virtual opener: zero-span */
2231
+ mk.end_col = mk.col;
2138
2232
  if (emit_now(e, &mk) != 0) {
2139
2233
  return -2;
2140
2234
  }
@@ -2282,6 +2376,9 @@ static void e_key_event(const yep_engine* e, const yep_line_shape* sh, uint16_t
2282
2376
  kv->borrowed = 1;
2283
2377
  kv->line = line;
2284
2378
  kv->col = key_col + 1;
2379
+ /* keys are single-line by the simple-key law; the cursor may have
2380
+ * advanced past the line, so the mark comes from e_pos_mark */
2381
+ e_pos_mark(e, sh->key_end, &kv->end_line, &kv->end_col);
2285
2382
  }
2286
2383
 
2287
2384
  static int e_classified(yep_engine* e, uint16_t floor_col) {
@@ -2786,6 +2883,7 @@ static int e_node(yep_engine* e, yep_ctx ctx, uint16_t floor_col) {
2786
2883
  kv.borrowed = 1;
2787
2884
  kv.line = e->line;
2788
2885
  kv.col = key_col + 1;
2886
+ e_pos_mark(e, s.end, &kv.end_line, &kv.end_col);
2789
2887
  if (emit_now(e, &kv) != 0) {
2790
2888
  return -2;
2791
2889
  }
@@ -2958,6 +3056,20 @@ empty_value: {
2958
3056
  e->pend_anchor_id = 0;
2959
3057
  e->pend_tag.p = NULL;
2960
3058
  e->pend_tag.len = 0;
3059
+ { /* libyaml: the implicit null sits just past the key's colon
3060
+ * ("k: " -> col 2, not the line end), zero-span */
3061
+ size_t at = e->pos;
3062
+ while (at > 0 && (e->p[at - 1] == ' ' || e->p[at - 1] == '\t' || e->p[at - 1] == '\n' ||
3063
+ e->p[at - 1] == '\r')) {
3064
+ at--; /* the cursor may sit lines past the deferred key */
3065
+ }
3066
+ if (at == 0 || e->p[at - 1] != ':') {
3067
+ at = e->pos; /* not a plain "key:" defer: the cursor stands */
3068
+ }
3069
+ e_pos_mark(e, at, &ev.line, &ev.col);
3070
+ ev.end_line = ev.line;
3071
+ ev.end_col = ev.col;
3072
+ }
2961
3073
  return emit_now(e, &ev) == 0 ? 0 : -2;
2962
3074
  }
2963
3075
  }
@@ -3300,6 +3412,7 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
3300
3412
  yep_nametab_clear(&e->anchors);
3301
3413
  e->tagmap_n = 0;
3302
3414
  e->saw_yaml = 0;
3415
+ e->doc_begin = (size_t)-1;
3303
3416
  e->doc_content = 0;
3304
3417
  e->q_key_pending = 0;
3305
3418
  e->q_value_pending = 0;
@@ -3312,6 +3425,10 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
3312
3425
  yep_event ev;
3313
3426
  if (emit_start) {
3314
3427
  e_event_init(&ev, YEP_EV_STREAM_START);
3428
+ ev.line = 1;
3429
+ ev.col = 1;
3430
+ ev.end_line = 1;
3431
+ ev.end_col = 1;
3315
3432
  if (emit_now(e, &ev) != 0) {
3316
3433
  return -2;
3317
3434
  }
@@ -3406,6 +3523,11 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
3406
3523
  e->tagmap_n++;
3407
3524
  }
3408
3525
  }
3526
+ if (e->doc_begin == (size_t)-1) {
3527
+ e->doc_begin = li.offset; /* libyaml: DOCUMENT_START's
3528
+ * start_mark includes the
3529
+ * leading directive lines */
3530
+ }
3409
3531
  e_line_done(e, li.end);
3410
3532
  continue;
3411
3533
  }
@@ -3428,6 +3550,10 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
3428
3550
  }
3429
3551
  e->doc_content = 0;
3430
3552
  e_event_init(&ev, YEP_EV_DOCUMENT_END);
3553
+ e_pos_mark(e, li.offset + li.indent, &ev.line, &ev.col);
3554
+ ev.end_line = ev.line; /* zero-span at the new marker —
3555
+ * libyaml's implicit close mark */
3556
+ ev.end_col = ev.col;
3431
3557
  if (emit_now(e, &ev) != 0) {
3432
3558
  return -2;
3433
3559
  }
@@ -3437,6 +3563,10 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
3437
3563
  }
3438
3564
  e_event_init(&ev, YEP_EV_DOCUMENT_START);
3439
3565
  ev.style = 1; /* explicit marker */
3566
+ e_pos_mark(e, e->doc_begin != (size_t)-1 ? e->doc_begin : li.offset + li.indent,
3567
+ &ev.line, &ev.col);
3568
+ e_pos_mark(e, li.offset + li.indent + 3, &ev.end_line, &ev.end_col);
3569
+ e->doc_begin = (size_t)-1;
3440
3570
  if (emit_now(e, &ev) != 0) {
3441
3571
  return -2;
3442
3572
  }
@@ -3485,7 +3615,9 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
3485
3615
  }
3486
3616
  }
3487
3617
  e_event_init(&ev, YEP_EV_DOCUMENT_END);
3488
- ev.style = 1; /* explicit "..." marker */
3618
+ ev.style = 1; /* explicit "..." marker */
3619
+ e_pos_mark(e, li.offset + li.indent, &ev.line, &ev.col);
3620
+ e_pos_mark(e, li.offset + li.indent + 3, &ev.end_line, &ev.end_col);
3489
3621
  e->tagmap_n = 0; /* directives are per-document */
3490
3622
  yep_nametab_clear(&e->anchors);
3491
3623
  if (emit_now(e, &ev) != 0) {
@@ -3494,6 +3626,7 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
3494
3626
  doc_open = 0;
3495
3627
  e->doc_content = 0;
3496
3628
  e->saw_yaml = 0;
3629
+ e->doc_begin = (size_t)-1;
3497
3630
  }
3498
3631
  e_line_done(e, li.end);
3499
3632
  continue;
@@ -3501,6 +3634,14 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
3501
3634
 
3502
3635
  if (!doc_open) {
3503
3636
  e_event_init(&ev, YEP_EV_DOCUMENT_START);
3637
+ if (e->doc_begin != (size_t)-1) {
3638
+ e_pos_mark(e, e->doc_begin, &ev.line, &ev.col);
3639
+ } else {
3640
+ e_pos_mark(e, li.offset + li.indent, &ev.line, &ev.col);
3641
+ }
3642
+ ev.end_line = ev.line;
3643
+ ev.end_col = ev.col;
3644
+ e->doc_begin = (size_t)-1;
3504
3645
  if (emit_now(e, &ev) != 0) {
3505
3646
  return -2;
3506
3647
  }
@@ -3670,6 +3811,9 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
3670
3811
  }
3671
3812
  }
3672
3813
  e_event_init(&ev, YEP_EV_DOCUMENT_END);
3814
+ e_pos_mark(e, e->len, &ev.line, &ev.col);
3815
+ ev.end_line = ev.line;
3816
+ ev.end_col = ev.col;
3673
3817
  if (emit_now(e, &ev) != 0) {
3674
3818
  return -2;
3675
3819
  }
@@ -3678,6 +3822,9 @@ static int engine_run_impl(yep_engine* e, const char* buf, size_t len, const yep
3678
3822
  }
3679
3823
  if (emit_end) {
3680
3824
  e_event_init(&ev, YEP_EV_STREAM_END);
3825
+ e_pos_mark(e, e->len, &ev.line, &ev.col);
3826
+ ev.end_line = ev.line;
3827
+ ev.end_col = ev.col;
3681
3828
  if (emit_now(e, &ev) != 0) {
3682
3829
  return -2;
3683
3830
  }
@@ -55,6 +55,12 @@ typedef struct yep_event {
55
55
  * that key on it skip the name hash entirely. */
56
56
  uint32_t line; /* 1-based position of the node start */
57
57
  uint32_t col;
58
+ uint32_t end_line; /* #179: 1-based position of the node's end —
59
+ * libyaml's end_mark semantics: a START event
60
+ * ends after its opening token, a scalar/alias
61
+ * spans anchor/tag through content, an END
62
+ * event spans its closing indicator */
63
+ uint32_t end_col;
58
64
  } yep_event;
59
65
 
60
66
  struct yep_block_value; /* value facts for on_block_pair (below) */