yeptris 0.6.46.0-aarch64-linux → 0.6.47.0-aarch64-linux
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/emit/writer.c +258 -238
- data/vendor/libyeptris/src/yeptris/scan/scan.c +38 -0
- data/vendor/libyeptris/src/yeptris/scan/scan.h +3 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 653e8a27e48a658a1232063a9031730f764203d2ff7b15a24158882d4536c1db
|
|
4
|
+
data.tar.gz: 90bc2c8ee8e376f1ec2373365fa6f18c27c188e0c60244cd10c05c8206d13536
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d6c0ed641dfe83cd513d5c17b8f65a0cb83dc6152f61f46e4ffd4c43f60d15340d8bbbb47a58e43ce9c06bb3f03e9d01c28e12f27e49a52a865fae02927778a9
|
|
7
|
+
data.tar.gz: e4f90f9bfb449b0bd8493e4cb01190e236fef512d854d23004654f269498f7e01b057d2106cf9441cc6f053c1966da4c3d0120a70dabdf43169d80ccf8c0c658
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
|
|
12
12
|
#define YEPTRIS_VERSION_MAJOR 0
|
|
13
13
|
#define YEPTRIS_VERSION_MINOR 6
|
|
14
|
-
#define YEPTRIS_VERSION_PATCH
|
|
15
|
-
#define YEPTRIS_VERSION_STRING "0.6.
|
|
14
|
+
#define YEPTRIS_VERSION_PATCH 47
|
|
15
|
+
#define YEPTRIS_VERSION_STRING "0.6.47"
|
|
16
16
|
|
|
17
17
|
#ifdef __cplusplus
|
|
18
18
|
extern "C" {
|
data/lib/yeptris.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Yeptris
|
|
4
4
|
# The gem's version lives in the parent namespace's file — the last
|
|
5
5
|
# internal require (yeptris/version) retired with it.
|
|
6
|
-
VERSION = "0.6.
|
|
6
|
+
VERSION = "0.6.47.0".freeze
|
|
7
7
|
|
|
8
8
|
# Informational notices are OPT-IN (yeptris-ruby#217): consumers
|
|
9
9
|
# embed yeptris inside CLIs that assert clean stderr, and a
|
data/libyeptris.so
CHANGED
|
Binary file
|
|
@@ -1390,17 +1390,19 @@ static void emit_node(yep_emitter* em, uint32_t id, int parent_col, int as_key)
|
|
|
1390
1390
|
* reconstruction). The format facts mirror marshal.c's emission
|
|
1391
1391
|
* contract (empirically pinned against Ruby 3.4): w_long small form
|
|
1392
1392
|
* x==0 -> 0x00, |x| <= 122 -> sign*(|x|+5), size form tag +-k with
|
|
1393
|
-
* LE payload (2^8k - m for negatives); strings carry 'I' ivar
|
|
1393
|
+
* LE payload (2^(8k) - m for negatives); strings carry 'I' ivar
|
|
1394
1394
|
* wrappers; arrays/hashes/strings/floats register for '@' links.
|
|
1395
|
-
*
|
|
1396
|
-
*
|
|
1395
|
+
*
|
|
1396
|
+
* '@' links MEMMOVE the registered object's emitted span — the first
|
|
1397
|
+
* walk's bytes are the cache; a lookup miss is a cycle (JSON cannot
|
|
1398
|
+
* express it, the binding falls back). No re-parse, no registration
|
|
1399
|
+
* on links: the object table stays exactly Ruby's stream order.
|
|
1400
|
+
*
|
|
1397
1401
|
* The JSON-irrelevant constructs ('o' objects, 'S' structs, 'u'
|
|
1398
1402
|
* user marshal, 'l' bignums beyond i64, non-finite floats) return
|
|
1399
1403
|
* UNSUPPORTED — the binding falls back to its per-node walk.
|
|
1400
1404
|
* ============================================================ */
|
|
1401
1405
|
|
|
1402
|
-
#include <inttypes.h>
|
|
1403
|
-
|
|
1404
1406
|
typedef struct {
|
|
1405
1407
|
const char* p;
|
|
1406
1408
|
size_t len;
|
|
@@ -1408,31 +1410,29 @@ typedef struct {
|
|
|
1408
1410
|
} mj_stream;
|
|
1409
1411
|
|
|
1410
1412
|
typedef struct {
|
|
1411
|
-
|
|
1412
|
-
uint32_t
|
|
1413
|
-
}
|
|
1413
|
+
const char* p;
|
|
1414
|
+
uint32_t len;
|
|
1415
|
+
} mj_sym;
|
|
1416
|
+
|
|
1417
|
+
typedef struct {
|
|
1418
|
+
size_t pos; /* the stream position of the type byte */
|
|
1419
|
+
size_t out_off; /* where the emitted span starts in w's buffer */
|
|
1420
|
+
size_t out_len; /* the span's length */
|
|
1421
|
+
} mj_obj;
|
|
1414
1422
|
|
|
1415
1423
|
typedef struct {
|
|
1416
1424
|
yep_writer* w;
|
|
1417
1425
|
mj_stream s;
|
|
1418
|
-
|
|
1419
|
-
int depth;
|
|
1420
|
-
int compact;
|
|
1421
|
-
/* the symbol table: ';' links resolve to these names */
|
|
1422
|
-
struct {
|
|
1423
|
-
const char* p;
|
|
1424
|
-
uint32_t len;
|
|
1425
|
-
}* syms;
|
|
1426
|
+
mj_sym* syms;
|
|
1426
1427
|
size_t syms_n, syms_cap;
|
|
1427
|
-
|
|
1428
|
-
struct {
|
|
1429
|
-
size_t pos;
|
|
1430
|
-
uint32_t chain_pos;
|
|
1431
|
-
}* objs;
|
|
1428
|
+
mj_obj* objs;
|
|
1432
1429
|
size_t objs_n, objs_cap;
|
|
1433
|
-
size_t* chain; /* the active positions (cycle guard) */
|
|
1434
|
-
size_t chain_n, chain_cap;
|
|
1435
1430
|
int failed; /* 0 ok, YEPTRIS_ERROR_UNSUPPORTED */
|
|
1431
|
+
int compact;
|
|
1432
|
+
int no_reg; /* the next mj_value entry skips registration — an
|
|
1433
|
+
* 'I'-wrapped construct registers ONCE (at the 'I');
|
|
1434
|
+
* its immediate inner must not add a second entry or
|
|
1435
|
+
* every later '@' link shifts */
|
|
1436
1436
|
} mj_ctx;
|
|
1437
1437
|
|
|
1438
1438
|
static int mj_fail(mj_ctx* c) {
|
|
@@ -1450,8 +1450,7 @@ static int mj_byte(mj_ctx* c, unsigned char* out) {
|
|
|
1450
1450
|
/* the w_long inverse — mirrors m_w_long's encode exactly:
|
|
1451
1451
|
* 0x00 -> 0; 1..4 -> positive size form k=b; 5..127 -> small +(
|
|
1452
1452
|
* b-5); 129..250 -> small -(251-b); 251..255 -> negative size form
|
|
1453
|
-
* k=256-b (payload = LE(2^(8k) - m)); 128
|
|
1454
|
-
* writer takes the small form first). */
|
|
1453
|
+
* k=256-b (payload = LE(2^(8k) - m)); 128 unreachable. */
|
|
1455
1454
|
static int mj_long(mj_ctx* c, int64_t* out) {
|
|
1456
1455
|
unsigned char b;
|
|
1457
1456
|
if (mj_byte(c, &b) != 0)
|
|
@@ -1493,19 +1492,9 @@ static int mj_long(mj_ctx* c, int64_t* out) {
|
|
|
1493
1492
|
}
|
|
1494
1493
|
}
|
|
1495
1494
|
|
|
1496
|
-
static
|
|
1497
|
-
if (idx < 0 || (size_t)idx >= c->syms_n) {
|
|
1498
|
-
mj_fail(c);
|
|
1499
|
-
return NULL;
|
|
1500
|
-
}
|
|
1501
|
-
*len_out = c->syms[idx].len;
|
|
1502
|
-
return c->syms[idx].p;
|
|
1503
|
-
}
|
|
1504
|
-
|
|
1505
|
-
static int mj_ivar_skip(mj_ctx* c);
|
|
1506
|
-
static int mj_link_key(mj_ctx* c, int64_t idx);
|
|
1507
|
-
|
|
1495
|
+
static int mj_ivar_pairs(mj_ctx* c);
|
|
1508
1496
|
static int mj_value(mj_ctx* c);
|
|
1497
|
+
static int mj_discard_value(mj_ctx* c);
|
|
1509
1498
|
|
|
1510
1499
|
static int mj_string_body(mj_ctx* c, int64_t len) {
|
|
1511
1500
|
if (len < 0 || (uint64_t)len > (uint64_t)(c->s.len - c->s.at))
|
|
@@ -1528,36 +1517,79 @@ static int mj_symbol(mj_ctx* c, int emit) {
|
|
|
1528
1517
|
c->s.at += (size_t)len;
|
|
1529
1518
|
if (c->syms_n == c->syms_cap) {
|
|
1530
1519
|
c->syms_cap = c->syms_cap ? c->syms_cap * 2 : 16;
|
|
1531
|
-
c->syms = (
|
|
1520
|
+
c->syms = (mj_sym*)realloc(c->syms, c->syms_cap * sizeof(*c->syms));
|
|
1532
1521
|
if (!c->syms)
|
|
1533
1522
|
return mj_fail(c);
|
|
1534
1523
|
}
|
|
1535
1524
|
c->syms[c->syms_n].p = name;
|
|
1536
1525
|
c->syms[c->syms_n].len = nlen;
|
|
1537
1526
|
c->syms_n++;
|
|
1538
|
-
if (emit)
|
|
1527
|
+
if (emit)
|
|
1539
1528
|
emit_dq_json(c->w, name, nlen);
|
|
1540
|
-
}
|
|
1541
1529
|
return 0;
|
|
1542
1530
|
}
|
|
1543
1531
|
|
|
1544
|
-
/*
|
|
1545
|
-
*
|
|
1546
|
-
|
|
1532
|
+
/* the count + (symbol, value) pairs that follow an 'I' wrapper's
|
|
1533
|
+
* wrapped value. Parsed and DISCARDED — encoding/freeze ivars have
|
|
1534
|
+
* no JSON spelling; the symbol still enters the ';' table. */
|
|
1535
|
+
static int mj_ivar_pairs(mj_ctx* c) {
|
|
1536
|
+
int64_t count;
|
|
1537
|
+
if (mj_long(c, &count) != 0)
|
|
1538
|
+
return -1;
|
|
1539
|
+
for (int64_t i = 0; i < count; i++) {
|
|
1540
|
+
unsigned char nt;
|
|
1541
|
+
if (mj_byte(c, &nt) != 0)
|
|
1542
|
+
return -1;
|
|
1543
|
+
if (nt == ':') {
|
|
1544
|
+
if (mj_symbol(c, 0) != 0)
|
|
1545
|
+
return -1; /* the name: tabled, not emitted */
|
|
1546
|
+
} else if (nt == ';') {
|
|
1547
|
+
int64_t sidx;
|
|
1548
|
+
if (mj_long(c, &sidx) != 0)
|
|
1549
|
+
return -1;
|
|
1550
|
+
if (sidx < 0 || (size_t)sidx >= c->syms_n)
|
|
1551
|
+
return mj_fail(c);
|
|
1552
|
+
} else {
|
|
1553
|
+
return mj_fail(c); /* ivar names are symbols only */
|
|
1554
|
+
}
|
|
1555
|
+
if (mj_discard_value(c) != 0)
|
|
1556
|
+
return -1; /* the ivar value */
|
|
1557
|
+
}
|
|
1558
|
+
return 0;
|
|
1559
|
+
}
|
|
1547
1560
|
|
|
1561
|
+
/* stream-position-only walk: consumes one value, emits nothing */
|
|
1548
1562
|
static int mj_discard_value(mj_ctx* c) {
|
|
1549
1563
|
unsigned char t;
|
|
1550
|
-
|
|
1564
|
+
int rc = mj_byte(c, &t);
|
|
1565
|
+
if (rc != 0)
|
|
1551
1566
|
return -1;
|
|
1552
1567
|
switch (t) {
|
|
1553
1568
|
case '0':
|
|
1554
1569
|
case 'T':
|
|
1555
1570
|
case 'F':
|
|
1556
1571
|
return 0;
|
|
1557
|
-
case 'i':
|
|
1572
|
+
case 'i':
|
|
1573
|
+
case ';':
|
|
1574
|
+
case '@': {
|
|
1558
1575
|
int64_t v;
|
|
1559
1576
|
return mj_long(c, &v);
|
|
1560
1577
|
}
|
|
1578
|
+
case 'l': {
|
|
1579
|
+
unsigned char sign;
|
|
1580
|
+
int64_t nlimbs;
|
|
1581
|
+
if (mj_byte(c, &sign) != 0)
|
|
1582
|
+
return -1;
|
|
1583
|
+
if (sign != 0x2b && sign != 0x2d)
|
|
1584
|
+
return mj_fail(c);
|
|
1585
|
+
if (mj_long(c, &nlimbs) != 0)
|
|
1586
|
+
return -1;
|
|
1587
|
+
if (nlimbs < 0 || (uint64_t)(nlimbs * 2) > (uint64_t)(c->s.len - c->s.at))
|
|
1588
|
+
return mj_fail(c);
|
|
1589
|
+
c->s.at += (size_t)(nlimbs * 2);
|
|
1590
|
+
return 0;
|
|
1591
|
+
}
|
|
1592
|
+
case 'f':
|
|
1561
1593
|
case '"': {
|
|
1562
1594
|
int64_t len;
|
|
1563
1595
|
if (mj_long(c, &len) != 0)
|
|
@@ -1567,73 +1599,105 @@ static int mj_discard_value(mj_ctx* c) {
|
|
|
1567
1599
|
c->s.at += (size_t)len;
|
|
1568
1600
|
return 0;
|
|
1569
1601
|
}
|
|
1602
|
+
case 'I':
|
|
1603
|
+
if (mj_discard_value(c) != 0)
|
|
1604
|
+
return -1;
|
|
1605
|
+
return mj_ivar_pairs(c);
|
|
1570
1606
|
case ':':
|
|
1571
1607
|
return mj_symbol(c, 0);
|
|
1572
|
-
case '
|
|
1573
|
-
int64_t
|
|
1574
|
-
if (mj_long(c, &
|
|
1608
|
+
case '[': {
|
|
1609
|
+
int64_t count;
|
|
1610
|
+
if (mj_long(c, &count) != 0)
|
|
1575
1611
|
return -1;
|
|
1576
|
-
|
|
1612
|
+
for (int64_t i = 0; i < count; i++) {
|
|
1613
|
+
if (mj_discard_value(c) != 0)
|
|
1614
|
+
return -1;
|
|
1615
|
+
}
|
|
1616
|
+
return 0;
|
|
1617
|
+
}
|
|
1618
|
+
case '{': {
|
|
1619
|
+
int64_t count;
|
|
1620
|
+
if (mj_long(c, &count) != 0)
|
|
1621
|
+
return -1;
|
|
1622
|
+
for (int64_t i = 0; i < count; i++) {
|
|
1623
|
+
if (mj_discard_value(c) != 0)
|
|
1624
|
+
return -1; /* key */
|
|
1625
|
+
if (mj_discard_value(c) != 0)
|
|
1626
|
+
return -1; /* value */
|
|
1627
|
+
}
|
|
1628
|
+
return 0;
|
|
1577
1629
|
}
|
|
1578
|
-
case 'I':
|
|
1579
|
-
return mj_ivar_skip(c);
|
|
1580
1630
|
default:
|
|
1581
|
-
return mj_fail(c);
|
|
1582
|
-
pairs only in practice */
|
|
1631
|
+
return mj_fail(c);
|
|
1583
1632
|
}
|
|
1584
1633
|
}
|
|
1585
1634
|
|
|
1586
|
-
/* the
|
|
1587
|
-
*
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
if (
|
|
1635
|
+
/* the memo'd span of a registered object, copied to the cursor. The
|
|
1636
|
+
* span lives earlier in the same buffer (append-only), so the copy
|
|
1637
|
+
* is memmove-safe. */
|
|
1638
|
+
static int mj_emit_memo(mj_ctx* c, const mj_obj* o) {
|
|
1639
|
+
if (getenv("MJ_DEBUG")) {
|
|
1640
|
+
char prev[13];
|
|
1641
|
+
uint32_t k = o->out_len < 12 ? (uint32_t)o->out_len : 12;
|
|
1642
|
+
memcpy(prev, c->w->p + o->out_off, k);
|
|
1643
|
+
prev[k] = '\0';
|
|
1644
|
+
fprintf(stderr, "memo off=%zu len=%zu: %s\n", o->out_off, o->out_len, prev);
|
|
1645
|
+
}
|
|
1646
|
+
if (o->out_len == 0)
|
|
1647
|
+
return mj_fail(c); /* not memoized yet: a cycle */
|
|
1648
|
+
wr_reserve(c->w, o->out_len);
|
|
1649
|
+
if (c->w->oom)
|
|
1591
1650
|
return -1;
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1651
|
+
memmove(c->w->p + c->w->len, c->w->p + o->out_off, o->out_len);
|
|
1652
|
+
wr_col_update(c->w, c->w->p + c->w->len, (uint32_t)o->out_len);
|
|
1653
|
+
c->w->len += o->out_len;
|
|
1654
|
+
/* the raw advance bypasses wr_put: hand back the reservation it
|
|
1655
|
+
* would have consumed, or the next write rides past cap */
|
|
1656
|
+
c->w->reserve -= o->out_len;
|
|
1657
|
+
c->w->last = c->w->p[c->w->len - 1];
|
|
1598
1658
|
return 0;
|
|
1599
1659
|
}
|
|
1600
1660
|
|
|
1601
|
-
/* a standalone 'I' wrapper: the wrapped value, then the pairs */
|
|
1602
|
-
static int mj_ivar_skip(mj_ctx* c) {
|
|
1603
|
-
if (mj_discard_value(c) != 0)
|
|
1604
|
-
return -1; /* the wrapped value */
|
|
1605
|
-
return mj_ivar_pairs(c);
|
|
1606
|
-
}
|
|
1607
|
-
|
|
1608
1661
|
static int mj_value(mj_ctx* c) {
|
|
1609
1662
|
unsigned char t;
|
|
1610
1663
|
size_t tpos = c->s.at;
|
|
1664
|
+
int reg_idx = -1;
|
|
1665
|
+
size_t span_start = 0;
|
|
1666
|
+
int register_this = !c->no_reg;
|
|
1667
|
+
c->no_reg = 0;
|
|
1611
1668
|
if (mj_byte(c, &t) != 0)
|
|
1612
1669
|
return -1;
|
|
1613
|
-
/* arrays, hashes, strings
|
|
1614
|
-
*
|
|
1615
|
-
*
|
|
1616
|
-
|
|
1670
|
+
/* arrays, hashes, strings, floats, bignums and anything
|
|
1671
|
+
* 'I'-wrapped register — ONCE per construct, at the outer byte
|
|
1672
|
+
* (the wrapper's no_reg suppresses the inner) (0-based stream
|
|
1673
|
+
* order). Bignums hold a slot but Ruby never emits a link to one
|
|
1674
|
+
* (the second occurrence re-emits in full); the entry only keeps
|
|
1675
|
+
* the slot count aligned for later links. Integers, symbols and
|
|
1676
|
+
* the other immediates never register. */
|
|
1677
|
+
if (register_this && (t == '[' || t == '{' || t == '"' || t == 'f' || t == 'I' || t == 'l')) {
|
|
1617
1678
|
if (c->objs_n == c->objs_cap) {
|
|
1618
1679
|
c->objs_cap = c->objs_cap ? c->objs_cap * 2 : 16;
|
|
1619
|
-
c->objs = (
|
|
1680
|
+
c->objs = (mj_obj*)realloc(c->objs, c->objs_cap * sizeof(*c->objs));
|
|
1620
1681
|
if (!c->objs)
|
|
1621
1682
|
return mj_fail(c);
|
|
1622
1683
|
}
|
|
1623
1684
|
c->objs[c->objs_n].pos = tpos;
|
|
1624
|
-
c->objs[c->objs_n].
|
|
1685
|
+
c->objs[c->objs_n].out_off = c->w->len;
|
|
1686
|
+
c->objs[c->objs_n].out_len = 0;
|
|
1687
|
+
reg_idx = (int)c->objs_n;
|
|
1625
1688
|
c->objs_n++;
|
|
1689
|
+
span_start = c->w->len;
|
|
1626
1690
|
}
|
|
1627
1691
|
switch (t) {
|
|
1628
1692
|
case '0':
|
|
1629
1693
|
wr_put(c->w, "null", 4);
|
|
1630
|
-
|
|
1694
|
+
break;
|
|
1631
1695
|
case 'T':
|
|
1632
1696
|
wr_put(c->w, "true", 4);
|
|
1633
|
-
|
|
1697
|
+
break;
|
|
1634
1698
|
case 'F':
|
|
1635
1699
|
wr_put(c->w, "false", 5);
|
|
1636
|
-
|
|
1700
|
+
break;
|
|
1637
1701
|
case 'i': {
|
|
1638
1702
|
int64_t v;
|
|
1639
1703
|
if (mj_long(c, &v) != 0)
|
|
@@ -1641,60 +1705,34 @@ static int mj_value(mj_ctx* c) {
|
|
|
1641
1705
|
char buf[24];
|
|
1642
1706
|
int n = snprintf(buf, sizeof buf, "%lld", (long long)v);
|
|
1643
1707
|
wr_put(c->w, buf, (uint32_t)n);
|
|
1644
|
-
|
|
1645
|
-
}
|
|
1646
|
-
case '"': {
|
|
1647
|
-
int64_t len;
|
|
1648
|
-
if (mj_long(c, &len) != 0)
|
|
1649
|
-
return -1;
|
|
1650
|
-
int rc = mj_string_body(c, len);
|
|
1651
|
-
if (rc != 0)
|
|
1652
|
-
return -1;
|
|
1653
|
-
/* the 'I' wrapper follows when the string carries ivars: the
|
|
1654
|
-
* value is already parsed — pairs only */
|
|
1655
|
-
if (c->s.at < c->s.len && c->s.p[c->s.at] == 'I') {
|
|
1656
|
-
c->s.at++;
|
|
1657
|
-
if (mj_ivar_pairs(c) != 0)
|
|
1658
|
-
return -1;
|
|
1659
|
-
}
|
|
1660
|
-
return 0;
|
|
1661
|
-
}
|
|
1662
|
-
case 'I': {
|
|
1663
|
-
/* the wrapped value IS the payload: re-dispatch into it, then
|
|
1664
|
-
* the ivar pairs ride */
|
|
1665
|
-
if (mj_value(c) != 0)
|
|
1666
|
-
return -1;
|
|
1667
|
-
return mj_ivar_pairs(c);
|
|
1708
|
+
break;
|
|
1668
1709
|
}
|
|
1669
1710
|
case 'l': {
|
|
1670
|
-
/* the bignum: sign byte + w_long(
|
|
1671
|
-
*
|
|
1711
|
+
/* the bignum: sign byte '+'/'-' + w_long(byte count) + LE
|
|
1712
|
+
* bytes; the i64-representable range emits, wider falls back */
|
|
1672
1713
|
unsigned char sign;
|
|
1673
1714
|
if (mj_byte(c, &sign) != 0)
|
|
1674
1715
|
return -1;
|
|
1675
1716
|
if (sign != 0x2b && sign != 0x2d)
|
|
1676
|
-
return mj_fail(c); /* + / - */
|
|
1677
|
-
int64_t words;
|
|
1678
|
-
if (mj_long(c, &words) != 0)
|
|
1679
|
-
return -1;
|
|
1680
|
-
if (words < 0 || words > 4)
|
|
1681
1717
|
return mj_fail(c);
|
|
1718
|
+
int64_t nlimbs;
|
|
1719
|
+
if (mj_long(c, &nlimbs) != 0)
|
|
1720
|
+
return -1;
|
|
1721
|
+
if (nlimbs < 1 || nlimbs > 4)
|
|
1722
|
+
return mj_fail(c); /* beyond 64 bits: fall back */
|
|
1682
1723
|
int64_t v = 0;
|
|
1683
|
-
for (int64_t i = 0; i <
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
v |= (int64_t)d << (16 * i + 8 * b);
|
|
1689
|
-
}
|
|
1724
|
+
for (int64_t i = 0; i < nlimbs; i++) {
|
|
1725
|
+
unsigned char lo, hi;
|
|
1726
|
+
if (mj_byte(c, &lo) != 0 || mj_byte(c, &hi) != 0)
|
|
1727
|
+
return -1;
|
|
1728
|
+
v |= (int64_t)(lo | ((uint64_t)hi << 8)) << (16 * i);
|
|
1690
1729
|
}
|
|
1691
|
-
if (sign == 0x2d)
|
|
1730
|
+
if (sign == 0x2d)
|
|
1692
1731
|
v = -v;
|
|
1693
|
-
}
|
|
1694
1732
|
char buf[24];
|
|
1695
1733
|
int n = snprintf(buf, sizeof buf, "%lld", (long long)v);
|
|
1696
1734
|
wr_put(c->w, buf, (uint32_t)n);
|
|
1697
|
-
|
|
1735
|
+
break;
|
|
1698
1736
|
}
|
|
1699
1737
|
case 'f': {
|
|
1700
1738
|
int64_t len;
|
|
@@ -1707,14 +1745,63 @@ static int mj_value(mj_ctx* c) {
|
|
|
1707
1745
|
memcpy(tmp, c->s.p + c->s.at, tl);
|
|
1708
1746
|
tmp[tl] = '\0';
|
|
1709
1747
|
c->s.at += (size_t)len;
|
|
1710
|
-
if (strcmp(tmp, "inf") == 0 || strcmp(tmp, "-inf") == 0 || strcmp(tmp, "nan") == 0)
|
|
1748
|
+
if (strcmp(tmp, "inf") == 0 || strcmp(tmp, "-inf") == 0 || strcmp(tmp, "nan") == 0)
|
|
1711
1749
|
return mj_fail(c); /* JSON has no inf/nan spelling */
|
|
1712
|
-
}
|
|
1713
1750
|
double d = strtod(tmp, NULL);
|
|
1714
1751
|
char buf[40];
|
|
1715
1752
|
int wl = yep_d2s_json(d, buf);
|
|
1716
1753
|
wr_put(c->w, buf, (uint32_t)wl);
|
|
1717
|
-
|
|
1754
|
+
break;
|
|
1755
|
+
}
|
|
1756
|
+
case '"': {
|
|
1757
|
+
int64_t len;
|
|
1758
|
+
if (mj_long(c, &len) != 0)
|
|
1759
|
+
return -1;
|
|
1760
|
+
int rc = mj_string_body(c, len);
|
|
1761
|
+
if (rc != 0)
|
|
1762
|
+
return -1;
|
|
1763
|
+
break;
|
|
1764
|
+
}
|
|
1765
|
+
case 'I': {
|
|
1766
|
+
/* the wrapped value IS the payload: re-dispatch into it, then
|
|
1767
|
+
* the ivar pairs ride. The inner dispatch must not register —
|
|
1768
|
+
* the construct registered at the 'I' (the double entry
|
|
1769
|
+
* shifted every later '@' link) */
|
|
1770
|
+
c->no_reg = 1;
|
|
1771
|
+
if (mj_value(c) != 0) {
|
|
1772
|
+
c->no_reg = 0;
|
|
1773
|
+
return -1;
|
|
1774
|
+
}
|
|
1775
|
+
c->no_reg = 0;
|
|
1776
|
+
if (mj_ivar_pairs(c) != 0)
|
|
1777
|
+
return -1;
|
|
1778
|
+
break;
|
|
1779
|
+
}
|
|
1780
|
+
case ':': {
|
|
1781
|
+
/* a bare symbol VALUE: emitted as its name string */
|
|
1782
|
+
if (mj_symbol(c, 1) != 0)
|
|
1783
|
+
return -1;
|
|
1784
|
+
break;
|
|
1785
|
+
}
|
|
1786
|
+
case ';': {
|
|
1787
|
+
int64_t idx;
|
|
1788
|
+
if (mj_long(c, &idx) != 0)
|
|
1789
|
+
return -1;
|
|
1790
|
+
if (idx < 0 || (size_t)idx >= c->syms_n)
|
|
1791
|
+
return mj_fail(c);
|
|
1792
|
+
emit_dq_json(c->w, c->syms[idx].p, c->syms[idx].len);
|
|
1793
|
+
break;
|
|
1794
|
+
}
|
|
1795
|
+
case '@': {
|
|
1796
|
+
/* an object link: the registered span memmoves to the cursor */
|
|
1797
|
+
int64_t idx;
|
|
1798
|
+
if (mj_long(c, &idx) != 0)
|
|
1799
|
+
return -1;
|
|
1800
|
+
if (idx < 0 || (size_t)idx >= c->objs_n)
|
|
1801
|
+
return mj_fail(c);
|
|
1802
|
+
if (mj_emit_memo(c, &c->objs[idx]) != 0)
|
|
1803
|
+
return -1;
|
|
1804
|
+
break;
|
|
1718
1805
|
}
|
|
1719
1806
|
case '[':
|
|
1720
1807
|
case '{': {
|
|
@@ -1723,45 +1810,53 @@ static int mj_value(mj_ctx* c) {
|
|
|
1723
1810
|
return -1;
|
|
1724
1811
|
if (count < 0)
|
|
1725
1812
|
return mj_fail(c);
|
|
1726
|
-
if (c->depth >= 512)
|
|
1727
|
-
return mj_fail(c);
|
|
1728
|
-
c->depth++;
|
|
1729
1813
|
wr_byte(c->w, t == '[' ? '[' : '{');
|
|
1814
|
+
const char* sep = c->compact ? "," : ", ";
|
|
1815
|
+
uint32_t sep_len = c->compact ? 1u : 2u;
|
|
1730
1816
|
for (int64_t i = 0; i < count; i++) {
|
|
1731
|
-
if (i > 0)
|
|
1732
|
-
wr_put(c->w,
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1817
|
+
if (i > 0)
|
|
1818
|
+
wr_put(c->w, sep, sep_len);
|
|
1819
|
+
if (t == '[') {
|
|
1820
|
+
if (mj_value(c) != 0)
|
|
1821
|
+
return -1;
|
|
1822
|
+
} else {
|
|
1823
|
+
/* the key: a string (with its 'I' wrapper) or a
|
|
1824
|
+
* symbol — JSON keys are strings */
|
|
1736
1825
|
unsigned char kt;
|
|
1826
|
+
size_t ktpos = c->s.at;
|
|
1737
1827
|
if (mj_byte(c, &kt) != 0)
|
|
1738
1828
|
return -1;
|
|
1739
1829
|
if (kt == 'I') {
|
|
1740
|
-
/* an ivar-wrapped key: the inner value emits, then
|
|
1741
|
-
* the pairs (the 'I' is consumed) */
|
|
1742
1830
|
if (mj_value(c) != 0)
|
|
1743
1831
|
return -1;
|
|
1744
1832
|
if (mj_ivar_pairs(c) != 0)
|
|
1745
1833
|
return -1;
|
|
1746
|
-
} else if (kt == '@') {
|
|
1747
|
-
/* a linked key: re-emit the target (#322's corpus
|
|
1748
|
-
* links the users' repeated key strings) */
|
|
1749
|
-
int64_t idx;
|
|
1750
|
-
if (mj_long(c, &idx) != 0)
|
|
1751
|
-
return -1;
|
|
1752
|
-
if (mj_link_key(c, idx) != 0)
|
|
1753
|
-
return -1;
|
|
1754
1834
|
} else if (kt == '"') {
|
|
1835
|
+
/* the key registers like any string object: its
|
|
1836
|
+
* span is memo'd for later '@' key links */
|
|
1837
|
+
int kreg = (int)c->objs_n;
|
|
1838
|
+
size_t kspan = c->w->len;
|
|
1839
|
+
if (kreg >= 0) {
|
|
1840
|
+
if (c->objs_n == c->objs_cap) {
|
|
1841
|
+
c->objs_cap = c->objs_cap ? c->objs_cap * 2 : 16;
|
|
1842
|
+
c->objs = (mj_obj*)realloc(c->objs, c->objs_cap * sizeof(*c->objs));
|
|
1843
|
+
if (!c->objs)
|
|
1844
|
+
return mj_fail(c);
|
|
1845
|
+
}
|
|
1846
|
+
c->objs[c->objs_n].pos = ktpos;
|
|
1847
|
+
c->objs[c->objs_n].out_off = c->w->len;
|
|
1848
|
+
c->objs[c->objs_n].out_len = 0;
|
|
1849
|
+
c->objs_n++;
|
|
1850
|
+
}
|
|
1755
1851
|
int64_t len;
|
|
1756
1852
|
if (mj_long(c, &len) != 0)
|
|
1757
1853
|
return -1;
|
|
1758
1854
|
int rc = mj_string_body(c, len);
|
|
1759
1855
|
if (rc != 0)
|
|
1760
1856
|
return -1;
|
|
1761
|
-
if (
|
|
1762
|
-
c->
|
|
1763
|
-
|
|
1764
|
-
return -1;
|
|
1857
|
+
if (kreg >= 0) {
|
|
1858
|
+
c->objs[kreg].out_off = kspan;
|
|
1859
|
+
c->objs[kreg].out_len = c->w->len - kspan;
|
|
1765
1860
|
}
|
|
1766
1861
|
} else if (kt == ':') {
|
|
1767
1862
|
if (mj_symbol(c, 1) != 0)
|
|
@@ -1770,108 +1865,36 @@ static int mj_value(mj_ctx* c) {
|
|
|
1770
1865
|
int64_t idx;
|
|
1771
1866
|
if (mj_long(c, &idx) != 0)
|
|
1772
1867
|
return -1;
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1868
|
+
if (idx < 0 || (size_t)idx >= c->syms_n)
|
|
1869
|
+
return mj_fail(c);
|
|
1870
|
+
emit_dq_json(c->w, c->syms[idx].p, c->syms[idx].len);
|
|
1871
|
+
} else if (kt == '@') {
|
|
1872
|
+
int64_t idx;
|
|
1873
|
+
if (mj_long(c, &idx) != 0)
|
|
1874
|
+
return -1;
|
|
1875
|
+
if (idx < 0 || (size_t)idx >= c->objs_n)
|
|
1876
|
+
return mj_fail(c);
|
|
1877
|
+
if (mj_emit_memo(c, &c->objs[idx]) != 0)
|
|
1776
1878
|
return -1;
|
|
1777
|
-
emit_dq_json(c->w, nm, nlen);
|
|
1778
1879
|
} else {
|
|
1779
1880
|
return mj_fail(c);
|
|
1780
1881
|
}
|
|
1781
|
-
wr_put(c->w, c->compact ? ":" : ": ", c->compact ?
|
|
1782
|
-
if (mj_value(c) != 0)
|
|
1783
|
-
return -1;
|
|
1784
|
-
} else {
|
|
1882
|
+
wr_put(c->w, c->compact ? ":" : ": ", c->compact ? 1u : 2u);
|
|
1785
1883
|
if (mj_value(c) != 0)
|
|
1786
1884
|
return -1;
|
|
1787
1885
|
}
|
|
1788
1886
|
}
|
|
1789
|
-
c->depth--;
|
|
1790
1887
|
wr_byte(c->w, t == '[' ? ']' : '}');
|
|
1791
|
-
|
|
1792
|
-
}
|
|
1793
|
-
case ';': {
|
|
1794
|
-
int64_t idx;
|
|
1795
|
-
if (mj_long(c, &idx) != 0)
|
|
1796
|
-
return -1;
|
|
1797
|
-
uint32_t nlen;
|
|
1798
|
-
const char* nm = mj_sym_name(c, idx, &nlen);
|
|
1799
|
-
if (!nm)
|
|
1800
|
-
return -1;
|
|
1801
|
-
emit_dq_json(c->w, nm, nlen);
|
|
1802
|
-
return 0;
|
|
1803
|
-
}
|
|
1804
|
-
case ':': {
|
|
1805
|
-
/* a bare symbol VALUE: emitted as its name string */
|
|
1806
|
-
if (mj_symbol(c, 1) != 0)
|
|
1807
|
-
return -1;
|
|
1808
|
-
return 0;
|
|
1809
|
-
}
|
|
1810
|
-
case '@': {
|
|
1811
|
-
/* an object link: re-walk from the registered position */
|
|
1812
|
-
int64_t idx;
|
|
1813
|
-
if (mj_long(c, &idx) != 0)
|
|
1814
|
-
return -1;
|
|
1815
|
-
if (idx < 0 || (size_t)idx >= c->objs_n)
|
|
1816
|
-
return mj_fail(c);
|
|
1817
|
-
size_t save = c->s.at;
|
|
1818
|
-
c->s.at = c->objs[idx].pos;
|
|
1819
|
-
/* cycle guard: the link target is in the active chain */
|
|
1820
|
-
for (size_t k = 0; k < c->chain_n; k++) {
|
|
1821
|
-
if (c->chain[k] == c->objs[idx].pos) {
|
|
1822
|
-
c->s.at = save;
|
|
1823
|
-
return mj_fail(c);
|
|
1824
|
-
}
|
|
1825
|
-
}
|
|
1826
|
-
if (c->chain_n == c->chain_cap) {
|
|
1827
|
-
c->chain_cap = c->chain_cap ? c->chain_cap * 2 : 16;
|
|
1828
|
-
c->chain = (size_t*)realloc(c->chain, c->chain_cap * sizeof(*c->chain));
|
|
1829
|
-
if (!c->chain) {
|
|
1830
|
-
c->s.at = save;
|
|
1831
|
-
return mj_fail(c);
|
|
1832
|
-
}
|
|
1833
|
-
}
|
|
1834
|
-
c->chain[c->chain_n++] = c->objs[idx].pos;
|
|
1835
|
-
int rc = mj_value(c);
|
|
1836
|
-
c->chain_n--;
|
|
1837
|
-
c->s.at = save;
|
|
1838
|
-
if (rc != 0)
|
|
1839
|
-
return -1;
|
|
1840
|
-
return 0;
|
|
1888
|
+
break;
|
|
1841
1889
|
}
|
|
1842
1890
|
default:
|
|
1843
1891
|
return mj_fail(c);
|
|
1844
1892
|
}
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
* the key string (Ruby links repeated key objects — the users' "id"
|
|
1849
|
-
* keys, yeptris-ruby#322's corpus). The link consumes no stream
|
|
1850
|
-
* bytes; the key walk resumes at the caller's cursor. */
|
|
1851
|
-
static int mj_link_key(mj_ctx* c, int64_t idx) {
|
|
1852
|
-
if (idx < 0 || (size_t)idx >= c->objs_n)
|
|
1853
|
-
return mj_fail(c);
|
|
1854
|
-
size_t save = c->s.at;
|
|
1855
|
-
for (size_t k = 0; k < c->chain_n; k++) {
|
|
1856
|
-
if (c->chain[k] == c->objs[idx].pos) {
|
|
1857
|
-
c->s.at = save;
|
|
1858
|
-
return mj_fail(c);
|
|
1859
|
-
}
|
|
1860
|
-
}
|
|
1861
|
-
c->s.at = c->objs[idx].pos;
|
|
1862
|
-
if (c->chain_n == c->chain_cap) {
|
|
1863
|
-
c->chain_cap = c->chain_cap ? c->chain_cap * 2 : 16;
|
|
1864
|
-
c->chain = (size_t*)realloc(c->chain, c->chain_cap * sizeof(*c->chain));
|
|
1865
|
-
if (!c->chain) {
|
|
1866
|
-
c->s.at = save;
|
|
1867
|
-
return mj_fail(c);
|
|
1868
|
-
}
|
|
1893
|
+
if (reg_idx >= 0) {
|
|
1894
|
+
c->objs[reg_idx].out_off = span_start;
|
|
1895
|
+
c->objs[reg_idx].out_len = c->w->len - span_start;
|
|
1869
1896
|
}
|
|
1870
|
-
|
|
1871
|
-
int rc = mj_value(c);
|
|
1872
|
-
c->chain_n--;
|
|
1873
|
-
c->s.at = save;
|
|
1874
|
-
return rc;
|
|
1897
|
+
return 0;
|
|
1875
1898
|
}
|
|
1876
1899
|
|
|
1877
1900
|
YEPTRIS_API YeptrisStatus yeptris_json_from_marshal(const char* m, size_t m_len, int compact,
|
|
@@ -1880,12 +1903,10 @@ YEPTRIS_API YeptrisStatus yeptris_json_from_marshal(const char* m, size_t m_len,
|
|
|
1880
1903
|
return YEPTRIS_ERROR_ARG;
|
|
1881
1904
|
*out = NULL;
|
|
1882
1905
|
*out_len = 0;
|
|
1883
|
-
if (m == NULL || m_len < 2 || (unsigned char)m[0] != 0x04 || (unsigned char)m[1] != 0x08)
|
|
1906
|
+
if (m == NULL || m_len < 2 || (unsigned char)m[0] != 0x04 || (unsigned char)m[1] != 0x08)
|
|
1884
1907
|
return YEPTRIS_ERROR_UNSUPPORTED;
|
|
1885
|
-
}
|
|
1886
1908
|
yep_emitter em;
|
|
1887
1909
|
memset(&em, 0, sizeof(em));
|
|
1888
|
-
em.doc = NULL;
|
|
1889
1910
|
yep_writer* w = &em.w;
|
|
1890
1911
|
w->sc_dec = NULL;
|
|
1891
1912
|
w->sc_i = 0;
|
|
@@ -1927,7 +1948,6 @@ YEPTRIS_API YeptrisStatus yeptris_json_from_marshal(const char* m, size_t m_len,
|
|
|
1927
1948
|
buf = w->p;
|
|
1928
1949
|
free(c.syms);
|
|
1929
1950
|
free(c.objs);
|
|
1930
|
-
free(c.chain);
|
|
1931
1951
|
if (failed || w->oom) {
|
|
1932
1952
|
free(buf);
|
|
1933
1953
|
return failed ? (YeptrisStatus)failed : YEPTRIS_ERROR_MEMORY;
|
|
@@ -20,6 +20,22 @@ size_t yep_scan_break_len(const char* p, size_t len, size_t pos) {
|
|
|
20
20
|
if (p[pos] == '\r') {
|
|
21
21
|
return (pos + 1 < len && p[pos + 1] == '\n') ? 2 : 1;
|
|
22
22
|
}
|
|
23
|
+
/* NEL/LS/PS are breaks like LF/CR (libyaml's IS_BREAK): the byte
|
|
24
|
+
* scanners ride them as content otherwise, and a plain value
|
|
25
|
+
* folds across the break INTO a following document marker (the
|
|
26
|
+
* nightly's r74: "&k:\":(<PS>---" read as one scalar, libyaml
|
|
27
|
+
* two events) */
|
|
28
|
+
return yep_scan_mb_break_len(p, len, pos);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
size_t yep_scan_mb_break_len(const char* p, size_t len, size_t pos) {
|
|
32
|
+
if (pos + 1 < len && (unsigned char)p[pos] == 0xC2 && (unsigned char)p[pos + 1] == 0x85) {
|
|
33
|
+
return 2; /* NEL */
|
|
34
|
+
}
|
|
35
|
+
if (pos + 2 < len && (unsigned char)p[pos] == 0xE2 && (unsigned char)p[pos + 1] == 0x80 &&
|
|
36
|
+
((unsigned char)p[pos + 2] & 0xFE) == 0xA8) {
|
|
37
|
+
return 3; /* LS / PS */
|
|
38
|
+
}
|
|
23
39
|
return 0;
|
|
24
40
|
}
|
|
25
41
|
|
|
@@ -38,6 +54,13 @@ void yep_scan_advance_line(const char* p, size_t* from, size_t to, uint32_t* lin
|
|
|
38
54
|
* (the nightly's run 38549939326) */
|
|
39
55
|
(*line)++;
|
|
40
56
|
*line_start = i + 1;
|
|
57
|
+
} else {
|
|
58
|
+
size_t mb = yep_scan_mb_break_len(p, to, i);
|
|
59
|
+
if (mb > 0) {
|
|
60
|
+
(*line)++;
|
|
61
|
+
i += mb - 1;
|
|
62
|
+
*line_start = i + 1;
|
|
63
|
+
}
|
|
41
64
|
}
|
|
42
65
|
}
|
|
43
66
|
*from = to;
|
|
@@ -463,6 +486,21 @@ yep_span yep_scan_plain(const char* p, size_t len, size_t pos, int flow) {
|
|
|
463
486
|
hit = k->stopset_find(stop, p + i, len - i);
|
|
464
487
|
}
|
|
465
488
|
size_t at = (hit < 0) ? len : i + (size_t)hit;
|
|
489
|
+
/* a multibyte break inside the piece ends it like an EOL: the
|
|
490
|
+
* byte stopset cannot see NEL/LS/PS, and the continuation
|
|
491
|
+
* would ride across the break into the next line's tokens */
|
|
492
|
+
if (at > i) {
|
|
493
|
+
const char* lead = (const char*)memchr(p + i, 0xC2, at - i);
|
|
494
|
+
const char* lead2 = (const char*)memchr(p + i, 0xE2, at - i);
|
|
495
|
+
const char* first =
|
|
496
|
+
(lead && lead2) ? (lead < lead2 ? lead : lead2) : (lead ? lead : lead2);
|
|
497
|
+
if (first != NULL && yep_scan_mb_break_len(p, len, (size_t)(first - p)) > 0) {
|
|
498
|
+
at = (size_t)(first - p);
|
|
499
|
+
i = at;
|
|
500
|
+
s.term = YEP_TERM_EOL;
|
|
501
|
+
break;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
466
504
|
unsigned char c = (at < len) ? (unsigned char)p[at] : 0;
|
|
467
505
|
|
|
468
506
|
if (at == len) {
|
|
@@ -147,6 +147,9 @@ int yep_scan_is_key_start(unsigned char c);
|
|
|
147
147
|
/* Consumed length of the line break at pos (0 if none): \n -> 1,
|
|
148
148
|
* \r\n -> 2, lone \r -> 1. */
|
|
149
149
|
size_t yep_scan_break_len(const char* p, size_t len, size_t pos);
|
|
150
|
+
/* NEL/LS/PS length at pos (2/3), 0 otherwise — the multibyte half of
|
|
151
|
+
* yep_scan_break_len's law, callable when only the UTF-8 breaks matter */
|
|
152
|
+
size_t yep_scan_mb_break_len(const char* p, size_t len, size_t pos);
|
|
150
153
|
|
|
151
154
|
/* Line/col bookkeeping across a scanned gap: advances *line and
|
|
152
155
|
* *line_start over the bytes in [*from, to) (only the unscanned region
|