@scriptc/runtime 0.0.9 → 0.0.10
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/package.json +1 -1
- package/src/scr_assert.c +43 -4
- package/src/scr_bytes.c +7 -6
- package/src/scr_bytes_io.c +410 -0
- package/src/scr_dc.c +6 -0
- package/src/scr_dgram.c +176 -1
- package/src/scr_dyn_invoke.c +96 -2
- package/src/scr_inspect.c +27 -3
- package/src/scr_island.c +389 -3
- package/src/scr_json.c +488 -7
- package/src/scr_lib.c +21 -1
- package/src/scr_net.c +112 -0
- package/src/scr_runtime.h +236 -4
- package/src/scr_tls.c +172 -0
package/src/scr_lib.c
CHANGED
|
@@ -1347,7 +1347,27 @@ static double scr_net_autosel_timeout_ms = 250;
|
|
|
1347
1347
|
|
|
1348
1348
|
double scr_net_get_autosel_timeout(void) { return scr_net_autosel_timeout_ms; }
|
|
1349
1349
|
|
|
1350
|
-
|
|
1350
|
+
/* Node's setDefaultAutoSelectFamilyAttemptTimeout: validateInt32(value,
|
|
1351
|
+
* 'value', 1), then the sub-10ms floor (Node clamps small budgets to
|
|
1352
|
+
* 10ms). Throws ERR_OUT_OF_RANGE catchably. */
|
|
1353
|
+
void scr_net_set_autosel_timeout(double ms) {
|
|
1354
|
+
char recv[48], msg[160];
|
|
1355
|
+
if (!(isfinite(ms) && trunc(ms) == ms)) {
|
|
1356
|
+
scr_num_received(ms, recv);
|
|
1357
|
+
int len = snprintf(msg, sizeof msg,
|
|
1358
|
+
"The value of \"value\" is out of range. It must be an integer. Received %s", recv);
|
|
1359
|
+
scr_throw_error_msg_code(SCR_ERR_RANGE, msg, (size_t)len, "ERR_OUT_OF_RANGE");
|
|
1360
|
+
return;
|
|
1361
|
+
}
|
|
1362
|
+
if (ms < 1 || ms > 2147483647.0) {
|
|
1363
|
+
scr_num_received(ms, recv);
|
|
1364
|
+
int len = snprintf(msg, sizeof msg,
|
|
1365
|
+
"The value of \"value\" is out of range. It must be >= 1 && <= 2147483647. Received %s", recv);
|
|
1366
|
+
scr_throw_error_msg_code(SCR_ERR_RANGE, msg, (size_t)len, "ERR_OUT_OF_RANGE");
|
|
1367
|
+
return;
|
|
1368
|
+
}
|
|
1369
|
+
scr_net_autosel_timeout_ms = ms < 10 ? 10 : ms;
|
|
1370
|
+
}
|
|
1351
1371
|
|
|
1352
1372
|
/* ── fs error formatting ─────────────────────────────────────────────
|
|
1353
1373
|
* Node's fs errors read "<ERRNO>: <text>, <syscall> '<path>'"
|
package/src/scr_net.c
CHANGED
|
@@ -92,6 +92,7 @@
|
|
|
92
92
|
#include "scr_runtime.h"
|
|
93
93
|
|
|
94
94
|
#include <errno.h>
|
|
95
|
+
#include <math.h>
|
|
95
96
|
#include <fcntl.h>
|
|
96
97
|
#include <stdio.h>
|
|
97
98
|
#include <stdlib.h>
|
|
@@ -1601,6 +1602,117 @@ ScrNetSocket *scr_net_connect(double port, ScrStr *host /*borrowed, nullable*/,
|
|
|
1601
1602
|
return s;
|
|
1602
1603
|
}
|
|
1603
1604
|
|
|
1605
|
+
/* ── the connect option-bag validation ladders (checked-dynamic lane) ──
|
|
1606
|
+
* Node-order validation over DOM option values with Node's exact typed
|
|
1607
|
+
* errors; the honest tail (connect for the validated forms, the
|
|
1608
|
+
* compiler-rendered fence for bags with unmodeled keys) runs only after
|
|
1609
|
+
* every validation passes. */
|
|
1610
|
+
|
|
1611
|
+
static bool scr_net_attempt_timeout_chk(const ScrDyn *t, const char *name) {
|
|
1612
|
+
if (t->kind != SCR_DYN_NUM) {
|
|
1613
|
+
scr_dyn_prop_type_fail(name, "of type number", t);
|
|
1614
|
+
return false;
|
|
1615
|
+
}
|
|
1616
|
+
char recv[48], msg[192];
|
|
1617
|
+
if (!(isfinite(t->v.num) && trunc(t->v.num) == t->v.num)) {
|
|
1618
|
+
scr_num_received(t->v.num, recv);
|
|
1619
|
+
int len = snprintf(msg, sizeof msg,
|
|
1620
|
+
"The value of \"%s\" is out of range. It must be an integer. Received %s",
|
|
1621
|
+
name, recv);
|
|
1622
|
+
scr_throw_error_msg_code(SCR_ERR_RANGE, msg, (size_t)len, "ERR_OUT_OF_RANGE");
|
|
1623
|
+
return false;
|
|
1624
|
+
}
|
|
1625
|
+
if (t->v.num < 1 || t->v.num > 2147483647.0) {
|
|
1626
|
+
scr_num_received(t->v.num, recv);
|
|
1627
|
+
int len = snprintf(msg, sizeof msg,
|
|
1628
|
+
"The value of \"%s\" is out of range. It must be >= 1 && <= 2147483647. Received %s",
|
|
1629
|
+
name, recv);
|
|
1630
|
+
scr_throw_error_msg_code(SCR_ERR_RANGE, msg, (size_t)len, "ERR_OUT_OF_RANGE");
|
|
1631
|
+
return false;
|
|
1632
|
+
}
|
|
1633
|
+
return true;
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
/* connect({ ..., autoSelectFamilyAttemptTimeout }): the budget validates
|
|
1637
|
+
* (validateInt32 from 1, Node's exact texts) and is then inert — this
|
|
1638
|
+
* slice's single dial has nothing to time, the same simplification the
|
|
1639
|
+
* autoSelectFamily flag already takes. NULL with the throw pending. */
|
|
1640
|
+
ScrNetSocket *scr_net_connect_attempt(double port, ScrStr *host, const ScrDyn *t) {
|
|
1641
|
+
if (!scr_net_attempt_timeout_chk(t, "options.autoSelectFamilyAttemptTimeout")) return NULL;
|
|
1642
|
+
return scr_net_connect(port, host, NULL);
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
static bool scr_net_dyn_truthy(const ScrDyn *v) {
|
|
1646
|
+
switch (v->kind) {
|
|
1647
|
+
case SCR_DYN_UNDEF:
|
|
1648
|
+
case SCR_DYN_NULL: return false;
|
|
1649
|
+
case SCR_DYN_BOOL: return v->v.b;
|
|
1650
|
+
case SCR_DYN_NUM: return v->v.num == v->v.num && v->v.num != 0;
|
|
1651
|
+
case SCR_DYN_STR: return v->v.str->len > 0;
|
|
1652
|
+
default: return true;
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
/* net.connect/createConnection over a RUNTIME option bag (computed keys
|
|
1657
|
+
* — the invalid-input probes): Node's Socket-constructor order — the
|
|
1658
|
+
* objectMode trio throws ERR_INVALID_ARG_VALUE first, then the port
|
|
1659
|
+
* (validatePort), the host's string contract, autoSelectFamily's boolean
|
|
1660
|
+
* contract, and the attempt budget. A bag that survives everything meets
|
|
1661
|
+
* the compiler-rendered fence: an unmodeled key must refuse loudly, never
|
|
1662
|
+
* silently drop. Always leaves an exception pending. */
|
|
1663
|
+
void scr_net_connect_opts_chk(const ScrDyn *opts, const ScrStr *fence) {
|
|
1664
|
+
if (opts == NULL || opts->kind != SCR_DYN_OBJ) {
|
|
1665
|
+
scr_dyn_arg_type_fail("options", "of type object",
|
|
1666
|
+
opts ? opts : scr_dyn_undefined());
|
|
1667
|
+
return;
|
|
1668
|
+
}
|
|
1669
|
+
static const char *const om[] = { "objectMode", "readableObjectMode", "writableObjectMode" };
|
|
1670
|
+
for (size_t i = 0; i < 3; i++) {
|
|
1671
|
+
const ScrDyn *v = scr_dyn_obj_get(opts, om[i], strlen(om[i]));
|
|
1672
|
+
if (v != NULL && scr_net_dyn_truthy(v)) {
|
|
1673
|
+
char name[48];
|
|
1674
|
+
snprintf(name, sizeof name, "options.%s", om[i]);
|
|
1675
|
+
scr_dyn_arg_value_fail(name, "is not supported", v);
|
|
1676
|
+
return;
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
const ScrDyn *port = scr_dyn_obj_get(opts, "port", 4);
|
|
1680
|
+
if (port != NULL && port->kind != SCR_DYN_UNDEF) {
|
|
1681
|
+
bool ok = port->kind == SCR_DYN_NUM && trunc(port->v.num) == port->v.num &&
|
|
1682
|
+
port->v.num >= 0 && port->v.num < 65536;
|
|
1683
|
+
if (!ok && port->kind == SCR_DYN_STR) {
|
|
1684
|
+
ScrStr *ps = scr_str_retain(port->v.str);
|
|
1685
|
+
double n = scr_string_to_number(ps);
|
|
1686
|
+
scr_str_release(ps);
|
|
1687
|
+
ok = n == n && trunc(n) == n && n >= 0 && n < 65536 && port->v.str->len > 0;
|
|
1688
|
+
}
|
|
1689
|
+
if (!ok) {
|
|
1690
|
+
char detail[64], msg[160];
|
|
1691
|
+
const char *d = scr_dyn_specific_type(port, detail, sizeof detail);
|
|
1692
|
+
int len = snprintf(msg, sizeof msg,
|
|
1693
|
+
"options.port should be >= 0 and < 65536. Received %s", d);
|
|
1694
|
+
scr_throw_error_msg_code(SCR_ERR_RANGE, msg, (size_t)len, "ERR_SOCKET_BAD_PORT");
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
const ScrDyn *host = scr_dyn_obj_get(opts, "host", 4);
|
|
1699
|
+
if (host != NULL && host->kind != SCR_DYN_UNDEF && host->kind != SCR_DYN_STR) {
|
|
1700
|
+
scr_dyn_prop_type_fail("options.host", "of type string", host);
|
|
1701
|
+
return;
|
|
1702
|
+
}
|
|
1703
|
+
const ScrDyn *asf = scr_dyn_obj_get(opts, "autoSelectFamily", 16);
|
|
1704
|
+
if (asf != NULL && asf->kind != SCR_DYN_UNDEF && asf->kind != SCR_DYN_BOOL) {
|
|
1705
|
+
scr_dyn_prop_type_fail("options.autoSelectFamily", "of type boolean", asf);
|
|
1706
|
+
return;
|
|
1707
|
+
}
|
|
1708
|
+
const ScrDyn *att = scr_dyn_obj_get(opts, "autoSelectFamilyAttemptTimeout", 30);
|
|
1709
|
+
if (att != NULL && att->kind != SCR_DYN_UNDEF &&
|
|
1710
|
+
!scr_net_attempt_timeout_chk(att, "options.autoSelectFamilyAttemptTimeout")) {
|
|
1711
|
+
return;
|
|
1712
|
+
}
|
|
1713
|
+
scr_throw_lowering_fence(fence);
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1604
1716
|
/* ── the caller-lookup dial (net.connect with a lookup option) ─────────
|
|
1605
1717
|
*
|
|
1606
1718
|
* portless's createLoopbackConnection: connect({ host, port,
|
package/src/scr_runtime.h
CHANGED
|
@@ -2617,6 +2617,28 @@ typedef enum {
|
|
|
2617
2617
|
* (the dyn→closure stance): a cycle THROUGH a dyn-boxed promise is
|
|
2618
2618
|
* merely never collected. */
|
|
2619
2619
|
SCR_DYN_PROMISE,
|
|
2620
|
+
/* An ISLAND (engine-held) value — the jsval→DOM crossing. Never
|
|
2621
|
+
* produced by the parser — it enters the DOM through the gated
|
|
2622
|
+
* constructor scr_dyn_from_jsval (scr_island.c): an 'any'-typed value
|
|
2623
|
+
* flowing into an 'unknown'/'object'/JS-residue slot. Boxes by
|
|
2624
|
+
* REFERENCE (a retained ScrJsval cell). The constructor SCALAR-
|
|
2625
|
+
* NORMALIZES: engine numbers/strings/booleans/null/undefined convert
|
|
2626
|
+
* to the native DOM kinds at wrap time, so JSVAL nodes only ever hold
|
|
2627
|
+
* engine objects, arrays, and functions (plus the symbol/bigint edge —
|
|
2628
|
+
* kinds the DOM cannot represent at all). Identity is the CELL's
|
|
2629
|
+
* engine value: strict equality routes to the engine's === (two wraps
|
|
2630
|
+
* of one engine value compare equal), and scr_jsval_from_dyn unwraps
|
|
2631
|
+
* the SAME cell back (+1) — the boundary is identity-preserving for
|
|
2632
|
+
* engine-born values. typeof/truthiness/String() route to the engine
|
|
2633
|
+
* per use (scr_dyn_jsval_ops); every DOM walk without an armed route
|
|
2634
|
+
* (JSON, structuredClone, deepStrictEqual, inspect, keyed access,
|
|
2635
|
+
* calls, iteration) throws the LOUD "not supported yet" ladder — never
|
|
2636
|
+
* a silent wrong answer. The dyn→cell edge is NOT visible to the cycle
|
|
2637
|
+
* collector (the dyn→closure stance): a cycle DOM → cell → engine
|
|
2638
|
+
* object → host closure → DOM is merely never collected (the
|
|
2639
|
+
* documented cross-boundary-cycle divergence). Enum position: LAST —
|
|
2640
|
+
* the LLVM backend hardcodes the preceding kind numbers. */
|
|
2641
|
+
SCR_DYN_JSVAL,
|
|
2620
2642
|
} ScrDynKind;
|
|
2621
2643
|
|
|
2622
2644
|
/* The handle-type tags the DOM can carry. The set is deliberately the
|
|
@@ -2636,6 +2658,10 @@ typedef enum {
|
|
|
2636
2658
|
typedef struct ScrDyn ScrDyn;
|
|
2637
2659
|
typedef struct ScrBytes ScrBytes; /* full definition below (C11 repeat) */
|
|
2638
2660
|
typedef struct ScrClosure ScrClosure; /* full definition below (C11 repeat) */
|
|
2661
|
+
typedef struct ScrJsval ScrJsval; /* opaque island cell (C11 repeat; the
|
|
2662
|
+
* always-linked DOM core never touches
|
|
2663
|
+
* its engine value — only the gated ops
|
|
2664
|
+
* installed by scr_dyn_from_jsval do) */
|
|
2639
2665
|
|
|
2640
2666
|
/* The compiler-emitted call glue carried by a SCR_DYN_FUNC box: checks the
|
|
2641
2667
|
* dyn arguments against the boxed closure's declared parameter types (a
|
|
@@ -2661,6 +2687,16 @@ struct ScrDyn {
|
|
|
2661
2687
|
* coercion and toString() decode utf8, where a plain Uint8Array joins
|
|
2662
2688
|
* its elements ("1,2,3"). Everything else ignores it. */
|
|
2663
2689
|
bool buffer;
|
|
2690
|
+
/* SCR_DYN_OBJ flavor: true for Object.create(null)'s dictionary — an
|
|
2691
|
+
* object with NO prototype. Method dispatch needs nothing (the DOM's
|
|
2692
|
+
* OBJ dispatch is already own-member-only, which IS Node's null-proto
|
|
2693
|
+
* answer); util.inspect prefixes "[Object: null prototype]", and
|
|
2694
|
+
* deepStrictEqual separates it from plain objects (Node compares
|
|
2695
|
+
* prototypes — the bytes `buffer` gate's stance). Keyed reads/writes,
|
|
2696
|
+
* Object.keys/entries/assign, JSON, and typeof are flag-blind, and
|
|
2697
|
+
* fresh copies (structuredClone) DROP the flag — Node's serialization
|
|
2698
|
+
* answers a plain object too. */
|
|
2699
|
+
bool null_proto;
|
|
2664
2700
|
union {
|
|
2665
2701
|
bool b;
|
|
2666
2702
|
double num;
|
|
@@ -2688,6 +2724,11 @@ struct ScrDyn {
|
|
|
2688
2724
|
* emitted converters guarantee it (direct box for promise<dyn>,
|
|
2689
2725
|
* adapter promise otherwise). */
|
|
2690
2726
|
ScrPromise *promise;
|
|
2727
|
+
/* SCR_DYN_JSVAL: the retained island cell (engine objects/arrays/
|
|
2728
|
+
* functions only — the constructor scalar-normalizes; see the kind's
|
|
2729
|
+
* comment). Released through the installed ops so this always-linked
|
|
2730
|
+
* core never references the gated island unit. */
|
|
2731
|
+
struct { ScrJsval *cell; } jsval;
|
|
2691
2732
|
} v;
|
|
2692
2733
|
};
|
|
2693
2734
|
|
|
@@ -2716,8 +2757,24 @@ ScrDyn *scr_dyn_obj_keys(const ScrDyn *v);
|
|
|
2716
2757
|
* TypeError; every other kind answers false. */
|
|
2717
2758
|
bool scr_dyn_has_own(const ScrDyn *v, const ScrStr *key);
|
|
2718
2759
|
/* Object.assign over DOM values (+1 target back; ToObject TypeError on a
|
|
2719
|
-
* nullish target).
|
|
2760
|
+
* nullish target). Sources copy their own enumerable keys exactly as
|
|
2761
|
+
* Object.keys lists them: OBJ members, ARR/STR/BYTES index keys; nullish
|
|
2762
|
+
* and scalar/function/handle sources copy nothing. */
|
|
2720
2763
|
ScrDyn *scr_dyn_assign(ScrDyn *target, const ScrDyn *src);
|
|
2764
|
+
/* Variadic Object.assign (the spread-source form): the compiler packs
|
|
2765
|
+
* every source into one fresh DOM array — pack_push retains a plain
|
|
2766
|
+
* source in (BORROWED), pack_push_spread flattens a spread source through
|
|
2767
|
+
* the spread-call walk (V8's exact TypeError texts, `what` spelling the
|
|
2768
|
+
* spread expression; MAY THROW pending) — then assign_all copies each
|
|
2769
|
+
* pack element's own members onto the target left to right and answers
|
|
2770
|
+
* the target retained (+1; ToObject TypeError on a nullish target). */
|
|
2771
|
+
void scr_dyn_pack_push(ScrDyn *pack, ScrDyn *v);
|
|
2772
|
+
void scr_dyn_pack_push_spread(ScrDyn *pack, const ScrDyn *src, const ScrStr *what);
|
|
2773
|
+
/* The iterated-path twin — a spread that is NOT the single last argument
|
|
2774
|
+
* takes V8's iterator-protocol failure texts, which describe the VALUE
|
|
2775
|
+
* ("object null", "number 5", ...) instead of spelling the expression. */
|
|
2776
|
+
void scr_dyn_pack_push_spread_iter(ScrDyn *pack, const ScrDyn *src);
|
|
2777
|
+
ScrDyn *scr_dyn_assign_all(ScrDyn *target, const ScrDyn *sources);
|
|
2721
2778
|
ScrDyn *scr_dyn_obj_values(const ScrDyn *v);
|
|
2722
2779
|
ScrDyn *scr_dyn_obj_entries(const ScrDyn *v);
|
|
2723
2780
|
|
|
@@ -2735,6 +2792,9 @@ ScrDyn *scr_dyn_new_num(double n);
|
|
|
2735
2792
|
ScrDyn *scr_dyn_new_str(ScrStr *s);
|
|
2736
2793
|
ScrDyn *scr_dyn_new_arr(void);
|
|
2737
2794
|
ScrDyn *scr_dyn_new_obj(void);
|
|
2795
|
+
/* Object.create(null): the fresh null-prototype dictionary (see the
|
|
2796
|
+
* null_proto flavor flag above). */
|
|
2797
|
+
ScrDyn *scr_dyn_new_obj_null_proto(void);
|
|
2738
2798
|
/* Wraps a fresh COPY of the u8 payload (the static→dyn boundary copies —
|
|
2739
2799
|
* DataView-backed sources copy their aliased window). Borrows b. */
|
|
2740
2800
|
ScrDyn *scr_dyn_new_bytes_copy(const ScrBytes *b);
|
|
@@ -2753,6 +2813,12 @@ void scr_dyn_arr_push(ScrDyn *arr, ScrDyn *item);
|
|
|
2753
2813
|
* nullish sources spell the spread expression (`what`), everything else is
|
|
2754
2814
|
* the generic "Spread syntax requires ..." text. Borrows src. */
|
|
2755
2815
|
void scr_dyn_arr_push_spread(ScrDyn *arr, const ScrDyn *src, const char *what);
|
|
2816
|
+
/* Destructuring pack over a DOM source: iterable kinds (arrays, strings by
|
|
2817
|
+
* code point, bytes) collect into a fresh array (+1); every other kind
|
|
2818
|
+
* throws V8's destructuring TypeError — `msg` verbatim when non-empty (the
|
|
2819
|
+
* compile-time source spelling), else the runtime kind wording. Borrows
|
|
2820
|
+
* both; NULL with the exception pending on the throw. */
|
|
2821
|
+
ScrDyn *scr_dyn_iter_pack(const ScrDyn *src, const ScrStr *msg);
|
|
2756
2822
|
void scr_dyn_obj_set(ScrDyn *obj, const char *key, size_t key_len, ScrDyn *value);
|
|
2757
2823
|
/* The checked-dynamic keyed WRITE (`h.k = v` on a dyn receiver): OBJ sets
|
|
2758
2824
|
* the member (JS: later writes win, insertion order); undefined/null and
|
|
@@ -2766,6 +2832,10 @@ ScrStr *scr_dyn_typeof(const ScrDyn *d);
|
|
|
2766
2832
|
* enc — utf8 default; strings/numbers/booleans/arrays/objects answer
|
|
2767
2833
|
* JS-exactly; undefined/null throw the catchable TypeError). Borrows; +1. */
|
|
2768
2834
|
ScrStr *scr_dyn_to_string(const ScrDyn *d, const ScrStr *enc);
|
|
2835
|
+
/* The method-call spelling `d.toString(enc?)`: identical, except a
|
|
2836
|
+
* null-prototype dictionary throws "<what> is not a function" — its
|
|
2837
|
+
* prototype chain has no toString (Node's answer). */
|
|
2838
|
+
ScrStr *scr_dyn_to_string_method(const ScrDyn *d, const ScrStr *enc, const ScrStr *what);
|
|
2769
2839
|
/* JS String() over the DOM kind (units render "null"/"undefined" where
|
|
2770
2840
|
* scr_dyn_to_string throws) — the web globals' WebIDL ToString. +1. */
|
|
2771
2841
|
ScrStr *scr_dyn_string_coerce(const ScrDyn *d);
|
|
@@ -2943,6 +3013,87 @@ ScrDyn *scr_dyn_new_promise_adapting(ScrPromise *src,
|
|
|
2943
3013
|
/* BORROWED peek at the boxed promise; NULL when d is not a promise box. */
|
|
2944
3014
|
ScrPromise *scr_dyn_promise_of(const ScrDyn *d);
|
|
2945
3015
|
|
|
3016
|
+
/* ── island values in the DOM (SCR_DYN_JSVAL) ─────────────────────────
|
|
3017
|
+
* Engine routing ops for JSVAL nodes, installed by the gated constructor
|
|
3018
|
+
* (scr_dyn_from_jsval, scr_island.c — the scr_dyn_alloc_promise hook
|
|
3019
|
+
* story: JSVAL nodes exist only after the constructor ran, so the ops
|
|
3020
|
+
* are always installed when a dispatch arm meets the kind, and a
|
|
3021
|
+
* dynamic-free link never references engine symbols). Contracts mirror
|
|
3022
|
+
* the scr_jsval_* entries they route to. */
|
|
3023
|
+
typedef struct ScrDynJsvalOps {
|
|
3024
|
+
void (*release)(ScrJsval *cell);
|
|
3025
|
+
ScrStr *(*type_of)(ScrJsval *cell); /* engine typeof; +1, never throws */
|
|
3026
|
+
bool (*truthy)(ScrJsval *cell); /* engine ToBoolean; never throws */
|
|
3027
|
+
/* String(v) in the engine (the full ToString protocol — user toString
|
|
3028
|
+
* runs, its throw bridges): +1, or NULL with the exception pending. */
|
|
3029
|
+
ScrStr *(*to_str)(ScrJsval *cell);
|
|
3030
|
+
bool (*strict_eq)(ScrJsval *a, ScrJsval *b); /* engine ===; never throws */
|
|
3031
|
+
bool (*is_array)(ScrJsval *cell); /* Array.isArray, engine-side */
|
|
3032
|
+
bool (*is_error)(ScrJsval *cell); /* native Error instance, engine-side */
|
|
3033
|
+
/* ── the routed operation set (lane dyn-routing-ops) ────────────────
|
|
3034
|
+
* Each routes to the engine at the moment of use and converts at the
|
|
3035
|
+
* boundary: dyn ARGUMENTS cross through scr_jsval_from_dyn (wrapped
|
|
3036
|
+
* cells unwrap by reference, DOM data deep-copies, DOM FUNC boxes
|
|
3037
|
+
* cross through the generic host-function shim), engine RESULTS come
|
|
3038
|
+
* back through scr_dyn_from_jsval (scalar-normalizing). Fallible ops
|
|
3039
|
+
* bridge the ENGINE's exception catchably and answer NULL/false/-1. */
|
|
3040
|
+
ScrDyn *(*key_get)(ScrJsval *cell, const ScrStr *k); /* o[k]; +1 or NULL pending */
|
|
3041
|
+
bool (*key_set)(ScrJsval *cell, const ScrStr *k, const ScrDyn *v); /* false = pending */
|
|
3042
|
+
ScrDyn *(*call)(ScrJsval *cell, ScrDyn *const *args, size_t argc); /* f(...); +1 or NULL pending */
|
|
3043
|
+
/* o.m(...) — the ENGINE's own prototypes run (JS-exact flatMap/map/
|
|
3044
|
+
* forEach/...). A missing or non-callable member throws Node's
|
|
3045
|
+
* "<what> is not a function" (the call site's spelling — V8's text,
|
|
3046
|
+
* front-run before the engine's terser claim). */
|
|
3047
|
+
ScrDyn *(*invoke)(ScrJsval *cell, const char *method, ScrDyn *const *args, size_t argc, const char *what);
|
|
3048
|
+
bool (*is_nullish)(ScrJsval *cell); /* engine undefined/null; never throws
|
|
3049
|
+
* (always false today — the wrap
|
|
3050
|
+
* constructor scalar-normalizes) */
|
|
3051
|
+
/* Object.keys/values/entries (mode 0/1/2) as a NATIVE DOM array (+1):
|
|
3052
|
+
* keys are DOM strings, values wrap per element, entries are native
|
|
3053
|
+
* DOM pairs. NULL with the engine's exception pending on refusal. */
|
|
3054
|
+
ScrDyn *(*obj_walk)(ScrJsval *cell, int mode);
|
|
3055
|
+
int (*has_own)(ScrJsval *cell, const ScrStr *k); /* 0/1; -1 = pending */
|
|
3056
|
+
/* Object.assign(target, src) with the ENGINE target: src converts per
|
|
3057
|
+
* member semantics (a wrapped src spreads by reference; DOM data
|
|
3058
|
+
* enters as the usual deep copy). false = pending. */
|
|
3059
|
+
bool (*assign)(ScrJsval *cell, const ScrDyn *src);
|
|
3060
|
+
/* JSON.stringify text of the engine value (+1) — the engine's own
|
|
3061
|
+
* stringify (toJSON protocols, cycle TypeErrors). NULL + pending when
|
|
3062
|
+
* not JSON-representable. */
|
|
3063
|
+
ScrStr *(*to_json)(ScrJsval *cell);
|
|
3064
|
+
} ScrDynJsvalOps;
|
|
3065
|
+
|
|
3066
|
+
/* The allocator view the gated constructor uses (installs the ops);
|
|
3067
|
+
* ownership of `cell` MOVES in (the caller retains first). */
|
|
3068
|
+
ScrDyn *scr_dyn_alloc_jsval(ScrJsval *cell, const ScrDynJsvalOps *ops);
|
|
3069
|
+
/* The installed ops (traps on a missing install — impossible unless a
|
|
3070
|
+
* JSVAL node was forged without the constructor). */
|
|
3071
|
+
const ScrDynJsvalOps *scr_dyn_jsval_ops(void);
|
|
3072
|
+
/* dynTest arms that need the ENGINE's answer on a JSVAL node. Each
|
|
3073
|
+
* answers false for every other kind (callers test unconditionally —
|
|
3074
|
+
* the emitted narrowing tests stay branch-free). Never throw. */
|
|
3075
|
+
bool scr_dyn_isl_typeof_is(const ScrDyn *d, const char *name);
|
|
3076
|
+
bool scr_dyn_isl_is_array(const ScrDyn *d);
|
|
3077
|
+
bool scr_dyn_isl_is_error(const ScrDyn *d);
|
|
3078
|
+
/* The JSVAL honesty ladder: when d is a JSVAL node, THROWS the catchable
|
|
3079
|
+
* "<what> on an island value held in 'unknown' is not supported yet"
|
|
3080
|
+
* Error and returns false; every other kind returns false untouched.
|
|
3081
|
+
* Callers gate un-armed operations with it — never a silent wrong
|
|
3082
|
+
* answer (the retired fence-box bug). */
|
|
3083
|
+
bool scr_dyn_isl_fence(const ScrDyn *d, const char *what);
|
|
3084
|
+
/* The emitted keyed READ's JSVAL arm (sc_dyn_key_get): routes o[k] to the
|
|
3085
|
+
* engine through the installed ops and wraps the result back (+1, scalars
|
|
3086
|
+
* normalized) — the retired `.length -> fence` row. d MUST be a JSVAL
|
|
3087
|
+
* node; NULL with the engine's exception bridged catchably. */
|
|
3088
|
+
ScrDyn *scr_dyn_isl_key_get(const ScrDyn *d, const ScrStr *k);
|
|
3089
|
+
/* The `??`/optional-chain nullish test over a DOM value: UNDEF/NULL
|
|
3090
|
+
* native, JSVAL through the engine's own test (defensively — the wrap
|
|
3091
|
+
* constructor scalar-normalizes engine null/undefined away), every other
|
|
3092
|
+
* kind false. Never throws. */
|
|
3093
|
+
bool scr_dyn_is_nullish(const ScrDyn *d);
|
|
3094
|
+
/* scr_dyn_isl_tostr_buf (the display walkers' JSVAL arm) is declared
|
|
3095
|
+
* with the ScrJsonBuf surface below. */
|
|
3096
|
+
|
|
2946
3097
|
/* ── the ambient receiver (JS `this` inside listener/callback bodies) ──
|
|
2947
3098
|
* Node calls a handle's listeners with `this` bound to the emitting
|
|
2948
3099
|
* handle (server.listen(0, function() { this.address().port })), and a
|
|
@@ -2991,6 +3142,24 @@ const char *scr_dyn_specific_type(const ScrDyn *v, char *buf, size_t cap);
|
|
|
2991
3142
|
* error.argTypeThrow libCall). Borrows all three; always throws. */
|
|
2992
3143
|
void scr_throw_arg_type(const ScrStr *argname, const ScrStr *expected, const ScrDyn *got);
|
|
2993
3144
|
void scr_dyn_arg_type_fail(const char *argname, const char *expected, const ScrDyn *got);
|
|
3145
|
+
/* The property flavor ("The \"options.x\" property must be ...") — the
|
|
3146
|
+
* option-bag validators' gate (error.propTypeThrow). Always throws. */
|
|
3147
|
+
void scr_throw_prop_type(const ScrStr *name, const ScrStr *expected, const ScrDyn *got);
|
|
3148
|
+
void scr_dyn_prop_type_fail(const char *name, const char *expected, const ScrDyn *got);
|
|
3149
|
+
/* Node's ERR_INVALID_ARG_VALUE ("The argument 'encoding' is invalid
|
|
3150
|
+
* encoding. Received 'no'") — reason NULL renders "is invalid".
|
|
3151
|
+
* TypeError; always throws catchably. */
|
|
3152
|
+
void scr_dyn_arg_value_fail(const char *name, const char *reason, const ScrDyn *got);
|
|
3153
|
+
/* The ERR_INVALID_ARG_VALUE/%j "Received" renderer (inspect-lite:
|
|
3154
|
+
* strings quote, scalars print plain, deep shapes sketch). */
|
|
3155
|
+
const char *scr_dyn_inspect_lite(const ScrDyn *v, char *buf, size_t cap);
|
|
3156
|
+
/* A ladder's post-validation refuse: throws the compiler-rendered SC2020
|
|
3157
|
+
* statement-fence text verbatim (Node's validation errors run first). */
|
|
3158
|
+
void scr_throw_lowering_fence(const ScrStr *msg);
|
|
3159
|
+
/* ERR_OUT_OF_RANGE's "Received" number rendering (Node's
|
|
3160
|
+
* addNumericalSeparator underscores past 2^32) — scr_bytes.c's renderer,
|
|
3161
|
+
* shared by the fs/net/tls option-ladder validators. */
|
|
3162
|
+
size_t scr_num_received(double v, char out[48]);
|
|
2994
3163
|
/* Listener-closure builders for the handle dispatchers' .on(...) paths:
|
|
2995
3164
|
* a runtime-built ScrClosure whose capture is the boxed dyn listener and
|
|
2996
3165
|
* whose invoke boxes the event tuple back into the DOM and calls through
|
|
@@ -3065,6 +3234,12 @@ void scr_jb_put_f64(ScrJsonBuf *b, double v);
|
|
|
3065
3234
|
* as \u00XX, everything else (UTF-8 included) verbatim — exactly the JS
|
|
3066
3235
|
* JSON.stringify escape set for well-formed strings. */
|
|
3067
3236
|
void scr_jb_put_json_str(ScrJsonBuf *b, const ScrStr *s);
|
|
3237
|
+
/* String(v) of a JSVAL node appended into b (the emitted sc_ds display
|
|
3238
|
+
* walkers' arm; scr_dyn_display/to_string route here too): the engine's
|
|
3239
|
+
* ToString. A bridged failure (throwing user toString, a symbol) leaves
|
|
3240
|
+
* the exception PENDING and appends nothing — the loud path, never a
|
|
3241
|
+
* fabricated rendering. */
|
|
3242
|
+
void scr_dyn_isl_tostr_buf(ScrJsonBuf *b, const ScrDyn *d);
|
|
3068
3243
|
/* JSON-serialize a DOM value into the buffer — the sc_jw_* walker for the
|
|
3069
3244
|
* dyn leaves the compiler cannot type: object members holding undefined
|
|
3070
3245
|
* DROP, array slots holding undefined print null (exactly Node). */
|
|
@@ -3738,11 +3913,27 @@ ScrJsval *scr_jsval_from_f64(double v);
|
|
|
3738
3913
|
ScrJsval *scr_jsval_from_bool(bool v);
|
|
3739
3914
|
ScrJsval *scr_jsval_from_str(const ScrStr *s);
|
|
3740
3915
|
ScrJsval *scr_jsval_from_json(const ScrStr *json);
|
|
3741
|
-
/* A CHECKED-DYNAMIC (DOM) value entering the island — deep copy
|
|
3742
|
-
* kinds
|
|
3743
|
-
*
|
|
3916
|
+
/* A CHECKED-DYNAMIC (DOM) value entering the island — deep copy for data
|
|
3917
|
+
* kinds (a boxed handle/promise throws the catchable TypeError). A JSVAL
|
|
3918
|
+
* node unwraps to its OWN cell (+1) — an engine value that crossed into
|
|
3919
|
+
* the DOM and back is the SAME engine value, by reference (nested JSVAL
|
|
3920
|
+
* members embed their engine values directly). A boxed FUNCTION crosses
|
|
3921
|
+
* as one generic host-function shim over its uniform ScrDynThunk: the
|
|
3922
|
+
* shim wraps engine arguments as DOM values (scalar-normalizing), calls
|
|
3923
|
+
* the thunk, and converts the DOM result back — each crossing mints a
|
|
3924
|
+
* fresh engine function (identity is not preserved for re-crossings;
|
|
3925
|
+
* SEMANTICS.md). NULL with a pending exception on failure. Borrows d. */
|
|
3744
3926
|
ScrJsval *scr_jsval_from_dyn(const ScrDyn *d);
|
|
3745
3927
|
|
|
3928
|
+
/* The jsval→DOM crossing (the IR's dynFromJsval): wraps an island value
|
|
3929
|
+
* as a SCR_DYN_JSVAL node, SCALAR-NORMALIZING first — engine numbers/
|
|
3930
|
+
* strings/booleans/null/undefined convert to the native DOM kinds (the
|
|
3931
|
+
* strict exits cannot fail on engine-reported scalars), so JSVAL nodes
|
|
3932
|
+
* only ever hold engine objects/arrays/functions (and the symbol/bigint
|
|
3933
|
+
* edge). Installs the DOM's engine-routing ops on first use. Borrows
|
|
3934
|
+
* the cell (retains it into the node); +1 out; never throws. */
|
|
3935
|
+
ScrDyn *scr_dyn_from_jsval(ScrJsval *cell);
|
|
3936
|
+
|
|
3746
3937
|
/* Engine operations. Arithmetic yields a fresh cell (NULL = bridged);
|
|
3747
3938
|
* comparisons yield 0/1 (-1 = bridged); truthy/not never fail. */
|
|
3748
3939
|
ScrJsval *scr_jsval_binop(int op, ScrJsval *a, ScrJsval *b);
|
|
@@ -4236,6 +4427,23 @@ ScrBytes *scr_buffer_new_string_fail(const ScrDyn *got);
|
|
|
4236
4427
|
* numbers coerce (negatives answer now/1000), the rest throw Node's
|
|
4237
4428
|
* ERR_INVALID_ARG_TYPE. Borrowed. */
|
|
4238
4429
|
double scr_fs_to_unix_timestamp(const ScrDyn *t);
|
|
4430
|
+
/* The fs argument-validation ladders (the fs.*Chk libCalls): Node-order
|
|
4431
|
+
* validation over DOM values with Node's exact typed errors; a pass
|
|
4432
|
+
* meets the real operation where one exists (mkdtempSync, macOS
|
|
4433
|
+
* lchmodSync) or the compiler-rendered fence. All borrowed; the Chk
|
|
4434
|
+
* forms without results always leave an exception pending. */
|
|
4435
|
+
ScrDyn *scr_fs_exists_async(const ScrDyn *path, const ScrDyn *cb);
|
|
4436
|
+
void scr_fs_mkdtemp_chk(const ScrDyn *prefix, const ScrDyn *cb, const ScrStr *fence);
|
|
4437
|
+
ScrStr *scr_fs_mkdtemp_sync_chk(const ScrDyn *prefix, const ScrDyn *opts, const ScrStr *fence);
|
|
4438
|
+
void scr_fs_read_file_chk(const ScrDyn *path, const ScrDyn *opts, const ScrDyn *cb, const ScrStr *fence);
|
|
4439
|
+
void scr_fs_opendir_chk(const ScrDyn *path, const ScrDyn *opts, const ScrStr *fence);
|
|
4440
|
+
void scr_fs_watch_file_chk(const ScrDyn *path, const ScrDyn *listener, const ScrStr *fence);
|
|
4441
|
+
void scr_fs_lchmod_chk(const ScrDyn *path, const ScrDyn *mode, const ScrDyn *cb, const ScrStr *fence);
|
|
4442
|
+
ScrDyn *scr_fs_lchmod_sync_chk(const ScrDyn *path, const ScrDyn *mode);
|
|
4443
|
+
ScrPromise *scr_fsp_lchmod_chk(const ScrDyn *path, const ScrDyn *mode);
|
|
4444
|
+
void scr_fs_read_chk(const ScrDyn *fd, const ScrDyn *buffer, const ScrDyn *offset,
|
|
4445
|
+
const ScrDyn *length, const ScrDyn *position, const ScrStr *fence);
|
|
4446
|
+
void scr_fs_stream_opts_chk(const ScrDyn *path, const ScrDyn *opts, const ScrStr *fence);
|
|
4239
4447
|
/* The checked-dynamic max-listeners ladders (scr_events_emitter.c). */
|
|
4240
4448
|
ScrEmitter *scr_emitter_set_max_chk(ScrEmitter *em, const ScrDyn *n);
|
|
4241
4449
|
void scr_emitter_set_default_max_chk(const ScrDyn *n, const ScrStr *name);
|
|
@@ -4503,6 +4711,16 @@ void scr_net_server_on_connection(ScrNetServer *s, ScrClosure *cb /*moves*/, Scr
|
|
|
4503
4711
|
* server never fires it, like Node). */
|
|
4504
4712
|
void scr_net_server_on_secure_connection(ScrNetServer *s, ScrClosure *cb /*moves*/, ScrNetConnFn fn, bool once);
|
|
4505
4713
|
ScrNetSocket *scr_net_connect(double port, ScrStr *host /*borrowed, nullable*/, ScrClosure *cb /*moves, nullable*/); /* +1 */
|
|
4714
|
+
/* connect with a validated autoSelectFamilyAttemptTimeout option: the
|
|
4715
|
+
* budget runs Node's validateInt32-from-1 ladder (ERR_OUT_OF_RANGE /
|
|
4716
|
+
* ERR_INVALID_ARG_TYPE) and is then inert — the single dial has nothing
|
|
4717
|
+
* to time. +1, or NULL with the throw pending. */
|
|
4718
|
+
ScrNetSocket *scr_net_connect_attempt(double port, ScrStr *host /*borrowed*/, const ScrDyn *t /*borrowed*/);
|
|
4719
|
+
/* net.connect/createConnection over a RUNTIME option bag (computed
|
|
4720
|
+
* keys): Node-order validation (objectMode trio, port, host,
|
|
4721
|
+
* autoSelectFamily, attempt budget), then the compiler-rendered fence —
|
|
4722
|
+
* always leaves an exception pending. Borrowed. */
|
|
4723
|
+
void scr_net_connect_opts_chk(const ScrDyn *opts, const ScrStr *fence);
|
|
4506
4724
|
/* connect with a caller lookup (net.connect({ ..., lookup })): invokes
|
|
4507
4725
|
* lookup(hostname, options, answer-closure) synchronously; answer_fn is
|
|
4508
4726
|
* the emitted per-shape thunk that decodes the answer down to
|
|
@@ -4717,6 +4935,13 @@ void scr_tls_h2_client_wrap(ScrNetSocket *sock, ScrStr *host /*borrowed*/, bool
|
|
|
4717
4935
|
* the default pair, exactly Node. */
|
|
4718
4936
|
typedef struct ScrSecureCtx ScrSecureCtx;
|
|
4719
4937
|
ScrSecureCtx *scr_tls_create_secure_context(const char *cert, size_t cert_len, const char *key, size_t key_len); /* +1 */
|
|
4938
|
+
/* createSecureContext over a RUNTIME options record: Node's typed option
|
|
4939
|
+
* validations first, then the pem walk (+1, or NULL with the exception
|
|
4940
|
+
* pending). Borrowed. */
|
|
4941
|
+
ScrSecureCtx *scr_tls_create_secure_context_dyn(const ScrDyn *opts);
|
|
4942
|
+
/* tls.getCACertificates(type): validateString + the documented name set,
|
|
4943
|
+
* then the compiler-rendered fence — always leaves an exception pending. */
|
|
4944
|
+
void scr_tls_ca_certs_chk(const ScrDyn *type, const ScrStr *fence);
|
|
4720
4945
|
ScrSecureCtx *scr_secure_ctx_retain(ScrSecureCtx *c);
|
|
4721
4946
|
void scr_secure_ctx_release(ScrSecureCtx *c);
|
|
4722
4947
|
void *scr_secure_ctx_retain_v(void *p);
|
|
@@ -5140,6 +5365,13 @@ void scr_dgram_bind(ScrDgramSocket *s, double port, ScrStr *host /*borrowed*/, S
|
|
|
5140
5365
|
void scr_dgram_connect(ScrDgramSocket *s, double port, ScrStr *host /*borrowed*/, ScrClosure *cb /*moves, nullable*/);
|
|
5141
5366
|
void scr_dgram_send_str(ScrDgramSocket *s, ScrStr *data /*borrowed*/, double port, ScrStr *host /*borrowed*/);
|
|
5142
5367
|
void scr_dgram_send_bytes(ScrDgramSocket *s, ScrBytes *data /*borrowed*/, double port, ScrStr *host /*borrowed*/);
|
|
5368
|
+
/* The send argument-validation ladder over DOM arguments (Node's
|
|
5369
|
+
* signature shuffle, slice bounds, list/type contracts, port/address
|
|
5370
|
+
* validation, and the connected-state errors); a fully-validated
|
|
5371
|
+
* unconnected single-payload send RUNS, the rest meet the fence. */
|
|
5372
|
+
void scr_dgram_send_chk(ScrDgramSocket *s, const ScrDyn *buffer, const ScrDyn *a1,
|
|
5373
|
+
const ScrDyn *a2, const ScrDyn *a3, const ScrDyn *a4,
|
|
5374
|
+
const ScrStr *fence);
|
|
5143
5375
|
/* address() parts: ip THROWS "Not running" before bind/connect (+1
|
|
5144
5376
|
* otherwise); family/port are only called after ip succeeded. */
|
|
5145
5377
|
ScrStr *scr_dgram_addr_ip(ScrDgramSocket *s); /* +1, may throw */
|