@scriptc/runtime 0.0.9 → 0.0.11
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_async.c +24 -4
- package/src/scr_bytes.c +47 -9
- 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_events_emitter.c +58 -5
- 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_library.c +15 -0
- package/src/scr_net.c +112 -0
- package/src/scr_regex.c +39 -6
- package/src/scr_runtime.h +296 -17
- package/src/scr_stream.c +214 -7
- package/src/scr_tls.c +172 -0
package/package.json
CHANGED
package/src/scr_assert.c
CHANGED
|
@@ -439,6 +439,11 @@ static bool scr_assert_dyn_same_value(const ScrDyn *a, const ScrDyn *b) {
|
|
|
439
439
|
case SCR_DYN_PROMISE:
|
|
440
440
|
/* Identity is the PROMISE (the strict_eq stance). */
|
|
441
441
|
return a->v.promise == b->v.promise;
|
|
442
|
+
case SCR_DYN_JSVAL:
|
|
443
|
+
/* Identity is the ENGINE VALUE (the strict_eq stance): the engine's
|
|
444
|
+
* === — exact for SameValue too, since wrap-time scalar
|
|
445
|
+
* normalization leaves only reference kinds behind. */
|
|
446
|
+
return a == b || scr_dyn_jsval_ops()->strict_eq(a->v.jsval.cell, b->v.jsval.cell);
|
|
442
447
|
default:
|
|
443
448
|
return a == b; /* ARR/OBJ/BYTES: node identity */
|
|
444
449
|
}
|
|
@@ -454,7 +459,16 @@ static bool scr_assert_dyn_same_value(const ScrDyn *a, const ScrDyn *b) {
|
|
|
454
459
|
* memo here where Node carries one (documented divergence). */
|
|
455
460
|
static bool scr_assert_dyn_deep_eq(const ScrDyn *a, const ScrDyn *b) {
|
|
456
461
|
if (a == b) return true;
|
|
457
|
-
if (a->kind != b->kind)
|
|
462
|
+
if (a->kind != b->kind) {
|
|
463
|
+
/* A MIXED comparison with an island side (wrapped engine object vs
|
|
464
|
+
* DOM data): Node walks both structurally — a plain `false` would
|
|
465
|
+
* mint a fabricated AssertionError for values Node may call equal.
|
|
466
|
+
* Loud fence (the long-tail lane's structural walk). */
|
|
467
|
+
if (a->kind == SCR_DYN_JSVAL || b->kind == SCR_DYN_JSVAL) {
|
|
468
|
+
scr_dyn_isl_fence(a->kind == SCR_DYN_JSVAL ? a : b, "deepStrictEqual");
|
|
469
|
+
}
|
|
470
|
+
return false;
|
|
471
|
+
}
|
|
458
472
|
switch (a->kind) {
|
|
459
473
|
case SCR_DYN_UNDEF:
|
|
460
474
|
case SCR_DYN_NULL:
|
|
@@ -493,6 +507,7 @@ static bool scr_assert_dyn_deep_eq(const ScrDyn *a, const ScrDyn *b) {
|
|
|
493
507
|
return true;
|
|
494
508
|
}
|
|
495
509
|
case SCR_DYN_OBJ: {
|
|
510
|
+
if (a->null_proto != b->null_proto) return false; /* the prototype gate */
|
|
496
511
|
if (a->v.obj.len != b->v.obj.len) return false;
|
|
497
512
|
for (size_t i = 0; i < a->v.obj.len; i++) {
|
|
498
513
|
const ScrDynEntry *ent = &a->v.obj.entries[i];
|
|
@@ -501,6 +516,14 @@ static bool scr_assert_dyn_deep_eq(const ScrDyn *a, const ScrDyn *b) {
|
|
|
501
516
|
}
|
|
502
517
|
return true;
|
|
503
518
|
}
|
|
519
|
+
case SCR_DYN_JSVAL:
|
|
520
|
+
/* Node walks the engine objects structurally — a walk this runtime
|
|
521
|
+
* cannot run. Engine-identical answers true honestly; anything else
|
|
522
|
+
* throws the loud ladder (scr_assert_eq_dyn propagates the pending
|
|
523
|
+
* exception INSTEAD of minting an AssertionError). */
|
|
524
|
+
if (scr_dyn_jsval_ops()->strict_eq(a->v.jsval.cell, b->v.jsval.cell)) return true;
|
|
525
|
+
scr_dyn_isl_fence(a, "deepStrictEqual");
|
|
526
|
+
return false;
|
|
504
527
|
}
|
|
505
528
|
return false; /* unreachable */
|
|
506
529
|
}
|
|
@@ -653,15 +676,26 @@ static void scr_assert_cf_value(ScrAssertBuf *b, const ScrDyn *d, size_t indent,
|
|
|
653
676
|
ab_char(b, ']');
|
|
654
677
|
return;
|
|
655
678
|
}
|
|
679
|
+
case SCR_DYN_JSVAL: {
|
|
680
|
+
/* The depth-elided placeholder (the handle stance): Node renders
|
|
681
|
+
* the engine object's property dump — internals this walker does
|
|
682
|
+
* not model; the text only appears inside FAILURE reports, which
|
|
683
|
+
* already diverge in format. */
|
|
684
|
+
ab_cstr(b, "[island value]");
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
656
687
|
case SCR_DYN_OBJ: {
|
|
688
|
+
/* The null-proto dictionary renders with Node's prefix in the
|
|
689
|
+
* failure diff too (assertion_error.js inspects both sides). */
|
|
657
690
|
if (d->v.obj.len == 0) {
|
|
658
|
-
ab_cstr(b, "{}");
|
|
691
|
+
ab_cstr(b, d->null_proto ? "[Object: null prototype] {}" : "{}");
|
|
659
692
|
return;
|
|
660
693
|
}
|
|
661
694
|
if (depth == 0) {
|
|
662
|
-
ab_cstr(b, "[Object]");
|
|
695
|
+
ab_cstr(b, d->null_proto ? "[Object: null prototype]" : "[Object]");
|
|
663
696
|
return;
|
|
664
697
|
}
|
|
698
|
+
if (d->null_proto) ab_cstr(b, "[Object: null prototype] ");
|
|
665
699
|
/* Render every entry, then sort the RENDERED texts (Node's
|
|
666
700
|
* sorted:true sorts formatted entries, quotes included). */
|
|
667
701
|
ScrCfEntry *ents = malloc(d->v.obj.len * sizeof *ents);
|
|
@@ -893,7 +927,8 @@ static bool scr_assert_print_myers(ScrAssertBuf *b, const ScrDiffOp *diff, size_
|
|
|
893
927
|
/* Is this DOM kind `typeof == "object" && != null` to assertion_error.js? */
|
|
894
928
|
static bool scr_assert_dyn_is_object(const ScrDyn *d) {
|
|
895
929
|
return d->kind == SCR_DYN_ARR || d->kind == SCR_DYN_OBJ || d->kind == SCR_DYN_BYTES ||
|
|
896
|
-
d->kind == SCR_DYN_HANDLE || d->kind == SCR_DYN_PROMISE
|
|
930
|
+
d->kind == SCR_DYN_HANDLE || d->kind == SCR_DYN_PROMISE ||
|
|
931
|
+
scr_dyn_isl_typeof_is(d, "object"); /* engine-held: the engine's typeof */
|
|
897
932
|
}
|
|
898
933
|
|
|
899
934
|
/* The failing EQUAL operators over dyn operands — createErrDiff. */
|
|
@@ -1065,6 +1100,10 @@ static void scr_assert_dyn_neq_fail(ScrDyn *a, bool deep, ScrStr *msg, bool has_
|
|
|
1065
1100
|
void scr_assert_eq_dyn(ScrDyn *a, ScrDyn *b, bool negated, bool deep,
|
|
1066
1101
|
ScrStr *msg, bool has_msg) {
|
|
1067
1102
|
bool same = deep ? scr_assert_dyn_deep_eq(a, b) : scr_assert_dyn_same_value(a, b);
|
|
1103
|
+
/* The deep walk's JSVAL arm fences loudly (an island value it cannot
|
|
1104
|
+
* compare structurally): propagate THAT, never a fabricated
|
|
1105
|
+
* AssertionError over a comparison that did not run. */
|
|
1106
|
+
if (scr_exc_pending()) return;
|
|
1068
1107
|
if ((negated && !same) || (!negated && same)) return;
|
|
1069
1108
|
if (negated) {
|
|
1070
1109
|
scr_assert_dyn_neq_fail(a, deep, msg, has_msg);
|
package/src/scr_async.c
CHANGED
|
@@ -591,7 +591,8 @@ ScrArr *scr_active_resources(void) {
|
|
|
591
591
|
* left queued on the uncaught paths) never run — the teardown releases
|
|
592
592
|
* them, like Node dropping the queue at exit. */
|
|
593
593
|
typedef struct ScrNtick {
|
|
594
|
-
ScrClosure *cb;
|
|
594
|
+
ScrClosure *cb; /* owned; NULL for a raw C-hook entry */
|
|
595
|
+
void (*raw)(void); /* the hook when cb == NULL (stream tick markers) */
|
|
595
596
|
struct ScrNtick *next;
|
|
596
597
|
} ScrNtick;
|
|
597
598
|
|
|
@@ -612,11 +613,25 @@ void scr_next_tick(ScrClosure *cb /*moves*/) {
|
|
|
612
613
|
scr_nt_tail = t;
|
|
613
614
|
}
|
|
614
615
|
|
|
616
|
+
/* A RAW C-hook tick: the stream unit enqueues one marker per deferred
|
|
617
|
+
* stream emission so those emissions interleave with user nextTicks in
|
|
618
|
+
* true FIFO order — in Node they ARE nextTicks (resume_, emitReadable_,
|
|
619
|
+
* endReadableNT, ...). The hook dispatches exactly one stream tick;
|
|
620
|
+
* teardown just drops markers (the stream queue owns its entries). */
|
|
621
|
+
void scr_next_tick_raw(void (*fn)(void)) {
|
|
622
|
+
ScrNtick *t = calloc(1, sizeof *t);
|
|
623
|
+
if (!t) scr_oom();
|
|
624
|
+
t->raw = fn;
|
|
625
|
+
if (scr_nt_tail) scr_nt_tail->next = t;
|
|
626
|
+
else scr_nt_head = t;
|
|
627
|
+
scr_nt_tail = t;
|
|
628
|
+
}
|
|
629
|
+
|
|
615
630
|
void scr_nticks_teardown(void) {
|
|
616
631
|
while (scr_nt_head != NULL) {
|
|
617
632
|
ScrNtick *t = scr_nt_head;
|
|
618
633
|
scr_nt_head = t->next;
|
|
619
|
-
scr_closure_release(t->cb);
|
|
634
|
+
if (t->cb) scr_closure_release(t->cb);
|
|
620
635
|
free(t);
|
|
621
636
|
}
|
|
622
637
|
scr_nt_tail = NULL;
|
|
@@ -1677,9 +1692,14 @@ void scr_loop_run(void) {
|
|
|
1677
1692
|
scr_nt_head = t->next;
|
|
1678
1693
|
if (scr_nt_head == NULL) scr_nt_tail = NULL;
|
|
1679
1694
|
ScrClosure *cb = t->cb;
|
|
1695
|
+
void (*raw)(void) = t->raw;
|
|
1680
1696
|
free(t);
|
|
1681
|
-
|
|
1682
|
-
|
|
1697
|
+
if (cb) {
|
|
1698
|
+
((void (*)(ScrClosure *))cb->fn)(cb);
|
|
1699
|
+
scr_closure_release(cb);
|
|
1700
|
+
} else {
|
|
1701
|
+
raw(); /* one stream tick, FIFO with the user ticks around it */
|
|
1702
|
+
}
|
|
1683
1703
|
if (scr_exc_pending()) return;
|
|
1684
1704
|
}
|
|
1685
1705
|
}
|
package/src/scr_bytes.c
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/* Typed arrays / Buffer: ONE runtime representation (ScrBytes — see the
|
|
2
|
-
* header contract).
|
|
3
|
-
*
|
|
2
|
+
* header contract). An ScrBytes either OWNS its storage or is a VIEW into
|
|
3
|
+
* an owner's (backing set, chain depth exactly 1): DataView, subarray(),
|
|
4
|
+
* and Buffer's slice() all alias JS-exactly; only the plain typed arrays'
|
|
5
|
+
* slice() copies. Coercions are JS-exact
|
|
4
6
|
* (ToUint8/ToUint32 modular truncation, double→float rounding); the
|
|
5
7
|
* encoding conversions (utf8 with WHATWG replacement, hex, base64) match
|
|
6
8
|
* Node byte-for-byte — the differential corpus holds them to it. */
|
|
@@ -164,7 +166,7 @@ void scr_bytes_set(ScrBytes *b, double i, double v) {
|
|
|
164
166
|
}
|
|
165
167
|
}
|
|
166
168
|
|
|
167
|
-
/* ── slice / subarray (
|
|
169
|
+
/* ── slice (copy) / subarray (view) ────────────────────────────────────── */
|
|
168
170
|
|
|
169
171
|
/* Relative index: ToIntegerOrInfinity, negatives from the end, clamped. */
|
|
170
172
|
static size_t scr_bytes_rel_index(double i, size_t len) {
|
|
@@ -186,6 +188,41 @@ ScrBytes *scr_bytes_slice(const ScrBytes *b, double start, double end) {
|
|
|
186
188
|
return out;
|
|
187
189
|
}
|
|
188
190
|
|
|
191
|
+
/* TypedArray.prototype.fill on non-u8 receivers: per-ELEMENT fill with
|
|
192
|
+
* the element write's JS-exact coercion (ToUint32/ToInt32 wrap, f32
|
|
193
|
+
* rounding), slice-clamped relative indices; answers the receiver +1
|
|
194
|
+
* (chaining). Never throws — Buffer's throwing fill family is separate. */
|
|
195
|
+
ScrBytes *scr_bytes_fill_elem(ScrBytes *b, double v, double start, double end) {
|
|
196
|
+
size_t s = scr_bytes_rel_index(start, b->len);
|
|
197
|
+
size_t e = scr_bytes_rel_index(end, b->len);
|
|
198
|
+
for (size_t i = s; i < e; i++) scr_bytes_set(b, (double)i, v);
|
|
199
|
+
return scr_bytes_retain(b);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* subarray(start, end): a same-elem VIEW over the receiver's storage —
|
|
203
|
+
* TypedArray.prototype.subarray and Buffer's slice()/subarray() all alias
|
|
204
|
+
* in JS (mutations are visible both ways; buffer-swap through a slice is
|
|
205
|
+
* the canonical Node use). Chain depth stays exactly 1: a subarray of a
|
|
206
|
+
* view retains the OWNER, offsets composed here (the DataView rule).
|
|
207
|
+
* Relative indices clamp like slice; never throws. */
|
|
208
|
+
ScrBytes *scr_bytes_subarray(ScrBytes *b, double start, double end) {
|
|
209
|
+
size_t s = scr_bytes_rel_index(start, b->len);
|
|
210
|
+
size_t e = scr_bytes_rel_index(end, b->len);
|
|
211
|
+
size_t count = e > s ? e - s : 0;
|
|
212
|
+
ScrBytes *owner = b->backing ? b->backing : b;
|
|
213
|
+
ScrBytes *v = malloc(sizeof(ScrBytes));
|
|
214
|
+
if (!v) scr_bytes_oom();
|
|
215
|
+
v->rc = 1;
|
|
216
|
+
v->len = count;
|
|
217
|
+
v->elem = b->elem;
|
|
218
|
+
v->data = b->data + s * scr_bytes_elem_size(b->elem);
|
|
219
|
+
v->backing = scr_bytes_retain(owner);
|
|
220
|
+
#ifdef SCR_RC_AUDIT
|
|
221
|
+
scr_live_bytes++;
|
|
222
|
+
#endif
|
|
223
|
+
return v;
|
|
224
|
+
}
|
|
225
|
+
|
|
189
226
|
void scr_bytes_set_from(ScrBytes *dst, const ScrBytes *src, double offset) {
|
|
190
227
|
double t = (offset != offset) ? 0 : trunc(offset);
|
|
191
228
|
if (!(t >= 0) || (double)src->len + t > (double)dst->len) {
|
|
@@ -927,7 +964,7 @@ ScrBytes *scr_bytes_from_arr(ScrBytesElem elem, const ScrArr *arr) {
|
|
|
927
964
|
* the '>= 0 && <= max' render, ERR_OUT_OF_RANGE's Received rules — and
|
|
928
965
|
* copy's C++-side ladder; pinned by corpus 1663) ─────────────────────── */
|
|
929
966
|
|
|
930
|
-
|
|
967
|
+
size_t scr_num_received(double v, char out[48]); /* the numeric section below */
|
|
931
968
|
|
|
932
969
|
/* validateOffset(name, 0, max): non-integers are 'an integer' (Number.
|
|
933
970
|
* isInteger — ±Infinity render 'an integer' too), the rest '>= 0 && <=
|
|
@@ -938,7 +975,7 @@ static size_t scr_bytes_received(double v, char out[48]); /* the numeric section
|
|
|
938
975
|
bool scr_bytes_validate_off(const char *name, double value, double max) {
|
|
939
976
|
if (isfinite(value) && floor(value) == value && value >= 0 && (max < 0 || value <= max)) return true;
|
|
940
977
|
char recv[48];
|
|
941
|
-
|
|
978
|
+
scr_num_received(value, recv);
|
|
942
979
|
char msg[160];
|
|
943
980
|
int mlen;
|
|
944
981
|
if (floor(value) != value || !isfinite(value)) {
|
|
@@ -1250,8 +1287,9 @@ ScrBytes *scr_bytes_concat(const ScrArr *list) {
|
|
|
1250
1287
|
/* ERR_OUT_OF_RANGE's "Received" rendering: integers with |v| > 2^32 get
|
|
1251
1288
|
* Node's addNumericalSeparator underscores applied to the plain String()
|
|
1252
1289
|
* form — INCLUDING its quirks on exponent renderings ("1e_+21",
|
|
1253
|
-
* "1e+_300"); everything else is the shortest-roundtrip number.
|
|
1254
|
-
|
|
1290
|
+
* "1e+_300"); everything else is the shortest-roundtrip number. Shared
|
|
1291
|
+
* with the fs/net option-ladder validators (scr_num_received). */
|
|
1292
|
+
size_t scr_num_received(double v, char out[48]) {
|
|
1255
1293
|
char plain[32];
|
|
1256
1294
|
size_t n = scr_f64_to_str(v, plain);
|
|
1257
1295
|
if (!(isfinite(v) && trunc(v) == v && fabs(v) > 4294967296.0)) {
|
|
@@ -1281,7 +1319,7 @@ static size_t scr_bytes_received(double v, char out[48]) {
|
|
|
1281
1319
|
* "byteLength" renders min 1. All catchable RangeErrors. */
|
|
1282
1320
|
static void scr_bytes_bounds_error(double value, double length, const char *type) {
|
|
1283
1321
|
char recv[48];
|
|
1284
|
-
|
|
1322
|
+
scr_num_received(value, recv);
|
|
1285
1323
|
char msg[160];
|
|
1286
1324
|
int mlen;
|
|
1287
1325
|
if (floor(value) != value) {
|
|
@@ -1322,7 +1360,7 @@ static bool scr_bytes_check_int(const ScrBytes *b, double value, double offset,
|
|
|
1322
1360
|
double min = sign ? -exp2((double)(8 * width - 1)) : 0;
|
|
1323
1361
|
if (value > max || value < min) {
|
|
1324
1362
|
char recv[48];
|
|
1325
|
-
|
|
1363
|
+
scr_num_received(value, recv);
|
|
1326
1364
|
char msg[160];
|
|
1327
1365
|
int mlen;
|
|
1328
1366
|
if (width > 4) {
|