@scriptc/runtime 0.0.22 → 0.0.24

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.
package/src/scr_json.c CHANGED
@@ -94,6 +94,10 @@ static void scr_jb_write(ScrJsonBuf *b, const char *s, size_t n) {
94
94
  b->len += n;
95
95
  }
96
96
 
97
+ void scr_jb_put_str(ScrJsonBuf *b, const ScrStr *s) {
98
+ scr_jb_write(b, s->data, s->len);
99
+ }
100
+
97
101
  void scr_jb_puts(ScrJsonBuf *b, const char *s) { scr_jb_write(b, s, strlen(s)); }
98
102
 
99
103
  void scr_jb_put_f64(ScrJsonBuf *b, double v) {
@@ -986,10 +990,18 @@ void scr_throw_arg_type(const ScrStr *argname, const ScrStr *expected, const Scr
986
990
  void scr_dyn_arg_type_fail(const char *argname, const char *expected, const ScrDyn *got) {
987
991
  char detail[64];
988
992
  const char *d = scr_dyn_specific_type(got, detail, sizeof detail);
989
- char msg[224];
990
- int len = snprintf(msg, sizeof msg,
991
- "The \"%s\" argument must be %s. Received %s", argname, expected, d);
992
- scr_throw_error_msg_code(SCR_ERR_TYPE, msg, (size_t)len, "ERR_INVALID_ARG_TYPE");
993
+ ScrJsonBuf b;
994
+ scr_jb_init(&b);
995
+ scr_jb_puts(&b, "The \"");
996
+ scr_jb_puts(&b, argname);
997
+ scr_jb_puts(&b, "\" argument must be ");
998
+ scr_jb_puts(&b, expected);
999
+ scr_jb_puts(&b, ". Received ");
1000
+ scr_jb_puts(&b, d);
1001
+ ScrStr *msg = scr_jb_finish(&b);
1002
+ scr_throw_error_msg_code(SCR_ERR_TYPE, msg->data, msg->len,
1003
+ "ERR_INVALID_ARG_TYPE");
1004
+ scr_str_release(msg);
993
1005
  }
994
1006
 
995
1007
  /* The property flavor of the same ladder — Node renders option-bag
@@ -999,10 +1011,18 @@ void scr_dyn_arg_type_fail(const char *argname, const char *expected, const ScrD
999
1011
  void scr_dyn_prop_type_fail(const char *name, const char *expected, const ScrDyn *got) {
1000
1012
  char detail[64];
1001
1013
  const char *d = scr_dyn_specific_type(got, detail, sizeof detail);
1002
- char msg[224];
1003
- int len = snprintf(msg, sizeof msg,
1004
- "The \"%s\" property must be %s. Received %s", name, expected, d);
1005
- scr_throw_error_msg_code(SCR_ERR_TYPE, msg, (size_t)len, "ERR_INVALID_ARG_TYPE");
1014
+ ScrJsonBuf b;
1015
+ scr_jb_init(&b);
1016
+ scr_jb_puts(&b, "The \"");
1017
+ scr_jb_puts(&b, name);
1018
+ scr_jb_puts(&b, "\" property must be ");
1019
+ scr_jb_puts(&b, expected);
1020
+ scr_jb_puts(&b, ". Received ");
1021
+ scr_jb_puts(&b, d);
1022
+ ScrStr *msg = scr_jb_finish(&b);
1023
+ scr_throw_error_msg_code(SCR_ERR_TYPE, msg->data, msg->len,
1024
+ "ERR_INVALID_ARG_TYPE");
1025
+ scr_str_release(msg);
1006
1026
  }
1007
1027
 
1008
1028
  /* The compiler-resolved property-typed throw (error.propTypeThrow —
@@ -1051,11 +1071,19 @@ const char *scr_dyn_inspect_lite(const ScrDyn *v, char *buf, size_t cap) {
1051
1071
  void scr_dyn_arg_value_fail(const char *name, const char *reason, const ScrDyn *got) {
1052
1072
  char insp[64];
1053
1073
  const char *d = scr_dyn_inspect_lite(got, insp, sizeof insp);
1054
- char msg[256];
1055
- int len = snprintf(msg, sizeof msg, "The %s '%s' %s. Received %s",
1056
- strchr(name, '.') != NULL ? "property" : "argument", name,
1057
- reason != NULL ? reason : "is invalid", d);
1058
- scr_throw_error_msg_code(SCR_ERR_TYPE, msg, (size_t)len, "ERR_INVALID_ARG_VALUE");
1074
+ ScrJsonBuf b;
1075
+ scr_jb_init(&b);
1076
+ scr_jb_puts(&b, "The ");
1077
+ scr_jb_puts(&b, strchr(name, '.') != NULL ? "property '" : "argument '");
1078
+ scr_jb_puts(&b, name);
1079
+ scr_jb_puts(&b, "' ");
1080
+ scr_jb_puts(&b, reason != NULL ? reason : "is invalid");
1081
+ scr_jb_puts(&b, ". Received ");
1082
+ scr_jb_puts(&b, d);
1083
+ ScrStr *msg = scr_jb_finish(&b);
1084
+ scr_throw_error_msg_code(SCR_ERR_TYPE, msg->data, msg->len,
1085
+ "ERR_INVALID_ARG_VALUE");
1086
+ scr_str_release(msg);
1059
1087
  }
1060
1088
 
1061
1089
  /* The deferred JS lowering fence, thrown from a ladder's post-validation
@@ -1362,7 +1390,8 @@ ScrStr *scr_dyn_typeof(const ScrDyn *d) {
1362
1390
  /* ── JSON.stringify over a dyn value (util.format's %j) ───────────────
1363
1391
  * The RUNTIME walk the type-directed serializers deliberately avoid for
1364
1392
  * static values — a dyn value has no static type, so the checked-dynamic tree's own kinds
1365
- * drive it, JS-exactly: insertion-ordered objects with undefined/function
1393
+ * drive it, JS-exactly: objects in OrdinaryOwnPropertyKeys order (array
1394
+ * indices ascending, then other strings in insertion order) with undefined/function
1366
1395
  * members OMITTED, arrays rendering those as null, Buffer's toJSON shape
1367
1396
  * ({"type":"Buffer","data":[...]}), shortest-roundtrip numbers, escaped
1368
1397
  * strings. HANDLE values fence loudly (Node walks own enumerable props
@@ -1390,23 +1419,26 @@ static bool scr_dyn_json_write(ScrJsonBuf *b, const ScrDyn *d) {
1390
1419
  case SCR_DYN_OBJ: {
1391
1420
  scr_jb_putc(b, '{');
1392
1421
  bool first = true;
1393
- for (size_t i = 0; i < d->v.obj.len; i++) {
1422
+ ScrDyn *entries = scr_dyn_obj_entries(d);
1423
+ for (size_t i = 0; i < entries->v.arr.len; i++) {
1424
+ const ScrDyn *pair = entries->v.arr.items[i];
1425
+ const ScrDyn *key = pair->v.arr.items[0];
1426
+ const ScrDyn *value = pair->v.arr.items[1];
1394
1427
  ScrJsonBuf probe;
1395
1428
  scr_jb_init(&probe);
1396
- if (!scr_dyn_json_write(&probe, d->v.obj.entries[i].value)) {
1429
+ if (!scr_dyn_json_write(&probe, value)) {
1397
1430
  scr_jb_dispose(&probe);
1398
1431
  continue; /* undefined/function members drop, like Node */
1399
1432
  }
1400
1433
  if (!first) scr_jb_putc(b, ',');
1401
1434
  first = false;
1402
- ScrStr *k = scr_str_new(d->v.obj.entries[i].key, d->v.obj.entries[i].key_len);
1403
- scr_jb_put_json_str(b, k);
1404
- scr_str_release(k);
1435
+ scr_jb_put_json_str(b, key->v.str);
1405
1436
  scr_jb_putc(b, ':');
1406
1437
  ScrStr *body = scr_jb_finish(&probe);
1407
1438
  scr_jb_write(b, body->data, body->len);
1408
1439
  scr_str_release(body);
1409
1440
  }
1441
+ scr_dyn_release(entries);
1410
1442
  scr_jb_putc(b, '}');
1411
1443
  return true;
1412
1444
  }
@@ -1637,8 +1669,17 @@ ScrStr *scr_dyn_to_string(const ScrDyn *d, const ScrStr *enc) {
1637
1669
  case SCR_DYN_OBJ:
1638
1670
  return scr_str_new("[object Object]", 15);
1639
1671
  case SCR_DYN_HANDLE:
1640
- /* IncomingMessage/ServerResponse/Socket inherit
1641
- * Object.prototype.toString Node's String() answer exactly. */
1672
+ if (d->v.handle.tag >= SCR_DYNH_ABORT_SIGNAL &&
1673
+ d->v.handle.tag <= SCR_DYNH_ABORT_CONTROLLER) {
1674
+ ScrJsonBuf b;
1675
+ scr_jb_init(&b);
1676
+ scr_jb_puts(&b, "[object ");
1677
+ scr_jb_puts(&b, scr_dyn_handle_cls(d));
1678
+ scr_jb_putc(&b, ']');
1679
+ return scr_jb_finish(&b);
1680
+ }
1681
+ /* IncomingMessage/ServerResponse/Socket and the other Node handles
1682
+ * inherit Object.prototype.toString without a @@toStringTag. */
1642
1683
  return scr_str_new("[object Object]", 15);
1643
1684
  case SCR_DYN_PROMISE:
1644
1685
  /* Object.prototype.toString with the Promise @@toStringTag. */
@@ -1789,6 +1830,81 @@ ScrStr *scr_dyn_string_coerce_js(const ScrDyn *d) {
1789
1830
  return scr_dyn_string_coerce(d);
1790
1831
  }
1791
1832
 
1833
+ /* JS ToNumber over a checked-dynamic value, including OrdinaryToPrimitive's
1834
+ * NUMBER hint for object snapshots. This is the numeric twin of
1835
+ * scr_dyn_string_coerce_js above: valueOf precedes toString, inherited
1836
+ * Object.prototype.valueOf returns the receiver (so conversion continues),
1837
+ * and the inherited toString fallback supplies "[object Object]". Borrows d;
1838
+ * false means an object hook threw or no primitive value could be produced. */
1839
+ bool scr_dyn_number_coerce_js(const ScrDyn *d, double *out) {
1840
+ if (d->kind == SCR_DYN_TYPED_REF) {
1841
+ ScrDyn *materialized = scr_dyn_typed_ref_materialize(d);
1842
+ bool ok = scr_dyn_number_coerce_js(materialized, out);
1843
+ scr_dyn_release(materialized);
1844
+ return ok;
1845
+ }
1846
+ switch (d->kind) {
1847
+ case SCR_DYN_NULL:
1848
+ *out = 0.0;
1849
+ return true;
1850
+ case SCR_DYN_BOOL:
1851
+ *out = d->v.b ? 1.0 : 0.0;
1852
+ return true;
1853
+ case SCR_DYN_NUM:
1854
+ *out = d->v.num;
1855
+ return true;
1856
+ case SCR_DYN_STR:
1857
+ *out = scr_string_to_number(d->v.str);
1858
+ return true;
1859
+ case SCR_DYN_UNDEF:
1860
+ *out = NAN;
1861
+ return true;
1862
+ case SCR_DYN_OBJ: {
1863
+ static const char *const hint[2] = { "valueOf", "toString" };
1864
+ for (int i = 0; i < 2; i++) {
1865
+ ScrDyn *m = scr_dyn_obj_get(d, hint[i], strlen(hint[i])); /* borrowed */
1866
+ if (!m) {
1867
+ if (!d->null_proto && i == 0) {
1868
+ /* Inherited Object.prototype.valueOf returns the object, so the
1869
+ * number-hint protocol advances to toString. */
1870
+ continue;
1871
+ }
1872
+ if (!d->null_proto && i == 1) {
1873
+ *out = NAN; /* Number("[object Object]") */
1874
+ return true;
1875
+ }
1876
+ continue;
1877
+ }
1878
+ if (m->kind != SCR_DYN_FUNC) continue;
1879
+ scr_dyn_this_push_dyn(d);
1880
+ ScrDyn *r = scr_dyn_call(m, NULL, 0, hint[i]);
1881
+ scr_dyn_this_pop();
1882
+ if (!r) return false;
1883
+ if (scr_dyn_to_primitive_result_is_object(r)) {
1884
+ scr_dyn_release(r);
1885
+ continue;
1886
+ }
1887
+ bool ok = scr_dyn_number_coerce_js(r, out);
1888
+ scr_dyn_release(r);
1889
+ return ok;
1890
+ }
1891
+ static const char msg[] = "Cannot convert object to primitive value";
1892
+ scr_throw_error_msg(SCR_ERR_TYPE, msg, sizeof msg - 1);
1893
+ return false;
1894
+ }
1895
+ default: {
1896
+ /* Arrays, byte views, functions, promises, and native handles inherit a
1897
+ * valueOf that returns the receiver, then use their existing JS-exact
1898
+ * string rendering for the numeric conversion. */
1899
+ ScrStr *text = scr_dyn_string_coerce(d);
1900
+ if (!text) return false;
1901
+ *out = scr_string_to_number(text);
1902
+ scr_str_release(text);
1903
+ return true;
1904
+ }
1905
+ }
1906
+ }
1907
+
1792
1908
  /* The checked-dynamic keyed WRITE (`h.k = v` on a dyn receiver): OBJ sets
1793
1909
  * the member (later writes win, insertion order — JS); undefined/null
1794
1910
  * throws Node's "Cannot set properties of ..."; every other kind throws