@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/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_library.c
CHANGED
|
@@ -251,6 +251,21 @@ ScrBytes *scr_library_bytes_in(const uint8_t *p, size_t len, const char *trap_ms
|
|
|
251
251
|
return b;
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
+
double scr_library_i64_in(int64_t v, const char *trap_msg) {
|
|
255
|
+
/* The inbound declared-integer edge (ask 4): only |v| <= 2^53-1 rides
|
|
256
|
+
* f64 exactly; past it, (double)v silently rounds — a coercion the
|
|
257
|
+
* author never wrote, so the wrapper funnels the host-contract
|
|
258
|
+
* violation instead (same story as an impossible bytes length; the
|
|
259
|
+
* message is the compiler-assembled structured trap-teaching form). */
|
|
260
|
+
if (v > 9007199254740991LL || v < -9007199254740991LL) scr_trap(trap_msg);
|
|
261
|
+
return (double)v;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
double scr_library_u64_in(uint64_t v, const char *trap_msg) {
|
|
265
|
+
if (v > 9007199254740991ULL) scr_trap(trap_msg);
|
|
266
|
+
return (double)v;
|
|
267
|
+
}
|
|
268
|
+
|
|
254
269
|
void scr_library_str_out(ScrStr *s, const uint8_t **out, size_t *out_len) {
|
|
255
270
|
scr_library_arena_keep(s, true);
|
|
256
271
|
*out = (const uint8_t *)s->data; /* NUL-terminated after len (ScrStr layout) */
|
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_regex.c
CHANGED
|
@@ -484,13 +484,20 @@ ScrArr *scr_regex_match_all_into(ScrStr *s, ScrRegex *re, ScrArr *indices) {
|
|
|
484
484
|
* replacements are frontend-fenced): $$, $&, $` and $', $1..$99 (two digits
|
|
485
485
|
* win when in range — the refined ES2019 rule quickjs implements), with
|
|
486
486
|
* out-of-range references left literal and unmatched groups substituting
|
|
487
|
-
* empty. $<name>
|
|
488
|
-
*
|
|
489
|
-
*
|
|
490
|
-
*
|
|
487
|
+
* empty. $<name> resolves against the pattern's named capture groups
|
|
488
|
+
* (lre_get_groupnames — one NUL-terminated name per capture, "" for
|
|
489
|
+
* unnamed): the first PARTICIPATING capture with that name substitutes
|
|
490
|
+
* (ES2025 duplicates live in distinct alternatives, so at most one
|
|
491
|
+
* participates); a nonexistent or nonparticipating name substitutes
|
|
492
|
+
* empty (the spec's Get→undefined→"" path, Node-exact). When the pattern
|
|
493
|
+
* has NO named groups, namedCaptures is undefined and '$<' stays literal
|
|
494
|
+
* — also Node's unterminated-'$<name' answer either way. The template is
|
|
495
|
+
* scanned byte-wise: every '$' directive is ASCII, and UTF-8 continuation
|
|
496
|
+
* bytes can never alias it. */
|
|
491
497
|
static void scr_put_substitution(ScrJsonBuf *b, const uint16_t *u, int len,
|
|
492
498
|
int start, int end, uint8_t **capture,
|
|
493
|
-
int capture_count, const
|
|
499
|
+
int capture_count, const char *groupnames,
|
|
500
|
+
const ScrStr *rep) {
|
|
494
501
|
const uint8_t *ubase = (const uint8_t *)u;
|
|
495
502
|
size_t i = 0;
|
|
496
503
|
while (i < rep->len) {
|
|
@@ -534,6 +541,31 @@ static void scr_put_substitution(ScrJsonBuf *b, const uint16_t *u, int len,
|
|
|
534
541
|
scr_jb_putc(b, '$');
|
|
535
542
|
i++;
|
|
536
543
|
}
|
|
544
|
+
} else if (c1 == '<' && groupnames != NULL) {
|
|
545
|
+
/* $<name>: scan for '>'; absent, the '$' is literal (the rest
|
|
546
|
+
* re-scans verbatim — GetSubstitution's not-found answer). */
|
|
547
|
+
size_t gt = i + 2;
|
|
548
|
+
while (gt < rep->len && rep->data[gt] != '>') gt++;
|
|
549
|
+
if (gt >= rep->len) {
|
|
550
|
+
scr_jb_putc(b, '$');
|
|
551
|
+
i++;
|
|
552
|
+
continue;
|
|
553
|
+
}
|
|
554
|
+
const char *name = rep->data + i + 2;
|
|
555
|
+
size_t name_len = gt - (i + 2);
|
|
556
|
+
const char *p = groupnames; /* capture_count-1 entries: name NUL scope */
|
|
557
|
+
for (int k = 1; k < capture_count; k++) {
|
|
558
|
+
size_t glen = strlen(p);
|
|
559
|
+
if (glen == name_len && memcmp(p, name, name_len) == 0) {
|
|
560
|
+
const uint8_t *cs = capture[2 * k], *ce = capture[2 * k + 1];
|
|
561
|
+
if (cs && ce) {
|
|
562
|
+
scr_jb_put_utf16(b, u, (int)((cs - ubase) >> 1), (int)((ce - ubase) >> 1));
|
|
563
|
+
break; /* at most one duplicate participates */
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
p += glen + LRE_GROUP_NAME_TRAILER_LEN;
|
|
567
|
+
}
|
|
568
|
+
i = gt + 1;
|
|
537
569
|
} else {
|
|
538
570
|
scr_jb_putc(b, '$');
|
|
539
571
|
i++;
|
|
@@ -550,6 +582,7 @@ static ScrStr *scr_replace_impl(ScrStr *s, ScrRegex *re, ScrStr *rep) {
|
|
|
550
582
|
bool global = (re_flags & LRE_FLAG_GLOBAL) != 0;
|
|
551
583
|
bool unicode = (re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0;
|
|
552
584
|
int capture_count = lre_get_capture_count(bc);
|
|
585
|
+
const char *groupnames = lre_get_groupnames(bc);
|
|
553
586
|
int len;
|
|
554
587
|
uint16_t *u = scr_to_utf16(s, &len);
|
|
555
588
|
uint8_t **capture = scr_capture_alloc(bc);
|
|
@@ -562,7 +595,7 @@ static ScrStr *scr_replace_impl(ScrStr *s, ScrRegex *re, ScrStr *rep) {
|
|
|
562
595
|
int start = (int)((capture[0] - ubase) >> 1);
|
|
563
596
|
int end = (int)((capture[1] - ubase) >> 1);
|
|
564
597
|
scr_jb_put_utf16(&b, u, next, start);
|
|
565
|
-
scr_put_substitution(&b, u, len, start, end, capture, capture_count, rep);
|
|
598
|
+
scr_put_substitution(&b, u, len, start, end, capture, capture_count, groupnames, rep);
|
|
566
599
|
next = end;
|
|
567
600
|
if (!global) break;
|
|
568
601
|
pos = end == start ? scr_advance(u, len, end, unicode) : end;
|