@scriptc/runtime 0.0.8 → 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 +65 -18
- package/src/scr_bytes_io.c +507 -1
- package/src/scr_dc.c +6 -0
- package/src/scr_dgram.c +176 -1
- package/src/scr_dyn_handle.c +8 -66
- package/src/scr_dyn_invoke.c +96 -2
- package/src/scr_error.c +15 -0
- package/src/scr_events_emitter.c +34 -0
- package/src/scr_exception.c +4 -1
- package/src/scr_inspect.c +27 -3
- package/src/scr_island.c +417 -3
- package/src/scr_json.c +643 -6
- package/src/scr_lib.c +122 -4
- package/src/scr_library.c +105 -2
- package/src/scr_net.c +112 -0
- package/src/scr_number.c +29 -19
- package/src/scr_runtime.h +358 -9
- package/src/scr_stream.c +49 -2
- package/src/scr_tls.c +172 -0
package/src/scr_runtime.h
CHANGED
|
@@ -48,8 +48,10 @@ void scr_init(void);
|
|
|
48
48
|
* the host-registered panic sink and abort only as the last resort: before
|
|
49
49
|
* registration, or if the sink returns (the ruled host-contract violation —
|
|
50
50
|
* a conforming sink longjmps to a host frame BELOW the entry, never back
|
|
51
|
-
* into library frames). Messages keep their trailing newline in both lanes
|
|
52
|
-
* the funnel
|
|
51
|
+
* into library frames). Messages keep their trailing newline in both lanes;
|
|
52
|
+
* the library funnel additionally assembles every DETECTED trap into the
|
|
53
|
+
* structured trap-teaching form before delivery (a message that already
|
|
54
|
+
* begins with the 0x01 marker passes verbatim) — see ScrLibSinkFn below. */
|
|
53
55
|
_Noreturn void scr_trap(const char *msg);
|
|
54
56
|
_Noreturn void scr_trap_fmt(const char *fmt, ...);
|
|
55
57
|
|
|
@@ -82,7 +84,17 @@ typedef struct ScrBytes ScrBytes;
|
|
|
82
84
|
* diagnostic code, 2 the trapping symbol as the host linked it, 3 the
|
|
83
85
|
* remediation; a missing or empty field means none; ignore any field past
|
|
84
86
|
* the fourth. Fields are (pointer, length) — never assume NUL termination.
|
|
85
|
-
* A plain-text host may print the whole buffer: the teaching leads it.
|
|
87
|
+
* A plain-text host may print the whole buffer: the teaching leads it.
|
|
88
|
+
*
|
|
89
|
+
* Every trap the runtime DETECTS arrives structured: the funnel assembles
|
|
90
|
+
* the baseline human line into field 0 unchanged, a stable code for the
|
|
91
|
+
* trap kind (the compiler registry's SC4013–SC4019 runtime family,
|
|
92
|
+
* classified in scr_library.c), the entry symbol recorded by the trapping
|
|
93
|
+
* entry's prologue, and the profile's remediation for that code when the
|
|
94
|
+
* program TU's overlay table declares one (the whole fourth field is
|
|
95
|
+
* absent otherwise). A message that already begins with the marker — a
|
|
96
|
+
* facade-authored structured throw, or the wrapper's compile-time-
|
|
97
|
+
* assembled SC4012 contract trap — passes through byte-for-byte. */
|
|
86
98
|
typedef void (*ScrLibSinkFn)(void *ctx, const uint8_t *msg, size_t msg_len,
|
|
87
99
|
uint64_t address);
|
|
88
100
|
void scr_library_set_sink(ScrLibSinkFn fn, void *ctx); /* latest wins */
|
|
@@ -90,8 +102,15 @@ void scr_library_set_sink(ScrLibSinkFn fn, void *ctx); /* latest wins */
|
|
|
90
102
|
/* Entry prologue: aborts deterministically when the library is poisoned (a
|
|
91
103
|
* trap already fired — no profile entry may run again; recovery is process
|
|
92
104
|
* restart). reset_arena additionally drops the result arena (the
|
|
93
|
-
* auto-reset posture, and the reset/collect entries' shared body).
|
|
94
|
-
|
|
105
|
+
* auto-reset posture, and the reset/collect entries' shared body).
|
|
106
|
+
* entry_symbol is the generated entry's external symbol exactly as the
|
|
107
|
+
* host linked it (a static string in the program TU): the prologue records
|
|
108
|
+
* it in the funnel's current-entry slot so a detected trap's structured
|
|
109
|
+
* message can name the trapping entry — sound as a single static slot
|
|
110
|
+
* because exactly one core is ever live and entries never nest. Init and
|
|
111
|
+
* the mode entries (reset, collect) record theirs too; the identity
|
|
112
|
+
* getters and sink registration touch no runtime and never trap. */
|
|
113
|
+
void scr_library_entry(bool reset_arena, const char *entry_symbol);
|
|
95
114
|
void scr_library_arena_reset(void);
|
|
96
115
|
/* The mode-provided collect entry's body: arena reset + a full cycle
|
|
97
116
|
* collection (snapshot-invariant by construction — collection frees only
|
|
@@ -124,6 +143,16 @@ void scr_library_check_exc(void);
|
|
|
124
143
|
* structured message is length-delimited, never NUL-scanned. */
|
|
125
144
|
_Noreturn void scr_trap_len(const char *msg, size_t len);
|
|
126
145
|
|
|
146
|
+
/* The runtime-trap overlay table, DEFINED by the generated program TU
|
|
147
|
+
* (both emissions emit identical data) and consumed by the funnel when it
|
|
148
|
+
* assembles a detected trap's structured message: flat triples of
|
|
149
|
+
* (code, teaching-or-NULL, remediation-or-NULL), one per runtime trap code
|
|
150
|
+
* (SC4013–SC4019 family) the profile declares text for; _len counts
|
|
151
|
+
* triples. A declared teaching replaces the baseline human line as field 0;
|
|
152
|
+
* a declared remediation becomes the optional fourth field. */
|
|
153
|
+
extern const char *const scr_library_trap_overlays[];
|
|
154
|
+
extern const size_t scr_library_trap_overlays_len;
|
|
155
|
+
|
|
127
156
|
/* Marshalling helpers the generated wrappers call (both emissions share
|
|
128
157
|
* these bodies, which is how the two lanes stay identical by
|
|
129
158
|
* construction). Inbound is borrowed-and-copied; outbound values MOVE into
|
|
@@ -449,6 +478,9 @@ void scr_undef_global_read(ScrStr *name);
|
|
|
449
478
|
void scr_error_set_code(ScrError *e, const char *code);
|
|
450
479
|
ScrStr *scr_error_code(ScrError *e);
|
|
451
480
|
void scr_throw_error_msg_code(int kind, const char *message, size_t len, const char *code);
|
|
481
|
+
/* The compiler-resolved Node-parity throw (error.nodeThrow): builtin
|
|
482
|
+
* error of `kind`, `code` stamped when non-empty. Borrows both. */
|
|
483
|
+
void scr_throw_node_coded(double kind, const ScrStr *code, const ScrStr *msg);
|
|
452
484
|
|
|
453
485
|
/* ── string methods ─────────────────────────────────────────────────
|
|
454
486
|
* ECMA-262 observable semantics (UTF-16 code units) computed over the
|
|
@@ -1552,6 +1584,13 @@ bool scr_stream_push_dyn(ScrStream *s, const ScrDyn *d); /* borrows d; tag
|
|
|
1552
1584
|
bool scr_stream_write_dyn(ScrStream *s, const ScrDyn *d, ScrClosure *cb); /* cb moves */
|
|
1553
1585
|
ScrPromise *scr_stream_next_chunk(ScrStream *s);
|
|
1554
1586
|
ScrPromise *scr_stream_next_chunk_dyn(ScrStream *s);
|
|
1587
|
+
/* node:stream/promises — the promise forms over the finished/pipeline
|
|
1588
|
+
* machinery above: a pending void promise the terminal watcher settles
|
|
1589
|
+
* (fulfilled on a clean finish, rejected with the finish status
|
|
1590
|
+
* otherwise — the stream's error or ERR_STREAM_PREMATURE_CLOSE).
|
|
1591
|
+
* Streams borrowed; +1 promises. */
|
|
1592
|
+
ScrPromise *scr_sp_finished(ScrStream *s);
|
|
1593
|
+
ScrPromise *scr_sp_pipeline(double n, ScrStream **streams);
|
|
1555
1594
|
/* Readable.from(array): +1 fully-seeded object-entry stream (one WHOLE
|
|
1556
1595
|
* chunk per element — strings or Buffers per the flag; hwm 1, already
|
|
1557
1596
|
* EOF'd). Borrows arr. */
|
|
@@ -2578,6 +2617,28 @@ typedef enum {
|
|
|
2578
2617
|
* (the dyn→closure stance): a cycle THROUGH a dyn-boxed promise is
|
|
2579
2618
|
* merely never collected. */
|
|
2580
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,
|
|
2581
2642
|
} ScrDynKind;
|
|
2582
2643
|
|
|
2583
2644
|
/* The handle-type tags the DOM can carry. The set is deliberately the
|
|
@@ -2597,6 +2658,10 @@ typedef enum {
|
|
|
2597
2658
|
typedef struct ScrDyn ScrDyn;
|
|
2598
2659
|
typedef struct ScrBytes ScrBytes; /* full definition below (C11 repeat) */
|
|
2599
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) */
|
|
2600
2665
|
|
|
2601
2666
|
/* The compiler-emitted call glue carried by a SCR_DYN_FUNC box: checks the
|
|
2602
2667
|
* dyn arguments against the boxed closure's declared parameter types (a
|
|
@@ -2622,6 +2687,16 @@ struct ScrDyn {
|
|
|
2622
2687
|
* coercion and toString() decode utf8, where a plain Uint8Array joins
|
|
2623
2688
|
* its elements ("1,2,3"). Everything else ignores it. */
|
|
2624
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;
|
|
2625
2700
|
union {
|
|
2626
2701
|
bool b;
|
|
2627
2702
|
double num;
|
|
@@ -2649,6 +2724,11 @@ struct ScrDyn {
|
|
|
2649
2724
|
* emitted converters guarantee it (direct box for promise<dyn>,
|
|
2650
2725
|
* adapter promise otherwise). */
|
|
2651
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;
|
|
2652
2732
|
} v;
|
|
2653
2733
|
};
|
|
2654
2734
|
|
|
@@ -2677,8 +2757,24 @@ ScrDyn *scr_dyn_obj_keys(const ScrDyn *v);
|
|
|
2677
2757
|
* TypeError; every other kind answers false. */
|
|
2678
2758
|
bool scr_dyn_has_own(const ScrDyn *v, const ScrStr *key);
|
|
2679
2759
|
/* Object.assign over DOM values (+1 target back; ToObject TypeError on a
|
|
2680
|
-
* 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. */
|
|
2681
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);
|
|
2682
2778
|
ScrDyn *scr_dyn_obj_values(const ScrDyn *v);
|
|
2683
2779
|
ScrDyn *scr_dyn_obj_entries(const ScrDyn *v);
|
|
2684
2780
|
|
|
@@ -2696,6 +2792,9 @@ ScrDyn *scr_dyn_new_num(double n);
|
|
|
2696
2792
|
ScrDyn *scr_dyn_new_str(ScrStr *s);
|
|
2697
2793
|
ScrDyn *scr_dyn_new_arr(void);
|
|
2698
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);
|
|
2699
2798
|
/* Wraps a fresh COPY of the u8 payload (the static→dyn boundary copies —
|
|
2700
2799
|
* DataView-backed sources copy their aliased window). Borrows b. */
|
|
2701
2800
|
ScrDyn *scr_dyn_new_bytes_copy(const ScrBytes *b);
|
|
@@ -2706,6 +2805,20 @@ ScrDyn *scr_dyn_new_buffer_copy(const ScrBytes *b);
|
|
|
2706
2805
|
* extraction (`u as Uint8Array`). */
|
|
2707
2806
|
ScrBytes *scr_dyn_bytes_copy_out(const ScrDyn *d);
|
|
2708
2807
|
void scr_dyn_arr_push(ScrDyn *arr, ScrDyn *item);
|
|
2808
|
+
/* Spread completion for a runtime-arity argument list (`f(...xs)` in the
|
|
2809
|
+
* checked-dynamic tier): flattens `src` into `arr` per JS's spread over the
|
|
2810
|
+
* DOM's iterable kinds — arrays element-by-element (retained), strings by
|
|
2811
|
+
* code POINT (the string iterator), bytes by byte — and throws V8's exact
|
|
2812
|
+
* SPREAD-CALL TypeError for every other kind (pending; callers check):
|
|
2813
|
+
* nullish sources spell the spread expression (`what`), everything else is
|
|
2814
|
+
* the generic "Spread syntax requires ..." text. Borrows src. */
|
|
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);
|
|
2709
2822
|
void scr_dyn_obj_set(ScrDyn *obj, const char *key, size_t key_len, ScrDyn *value);
|
|
2710
2823
|
/* The checked-dynamic keyed WRITE (`h.k = v` on a dyn receiver): OBJ sets
|
|
2711
2824
|
* the member (JS: later writes win, insertion order); undefined/null and
|
|
@@ -2719,9 +2832,17 @@ ScrStr *scr_dyn_typeof(const ScrDyn *d);
|
|
|
2719
2832
|
* enc — utf8 default; strings/numbers/booleans/arrays/objects answer
|
|
2720
2833
|
* JS-exactly; undefined/null throw the catchable TypeError). Borrows; +1. */
|
|
2721
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);
|
|
2722
2839
|
/* JS String() over the DOM kind (units render "null"/"undefined" where
|
|
2723
2840
|
* scr_dyn_to_string throws) — the web globals' WebIDL ToString. +1. */
|
|
2724
2841
|
ScrStr *scr_dyn_string_coerce(const ScrDyn *d);
|
|
2842
|
+
/* JS ToString WITH the object protocol (user toString/valueOf members
|
|
2843
|
+
* called, their throws propagating) — the WHATWG USVString conversions.
|
|
2844
|
+
* Borrows; +1 or NULL with the exception pending. */
|
|
2845
|
+
ScrStr *scr_dyn_string_coerce_js(const ScrDyn *d);
|
|
2725
2846
|
|
|
2726
2847
|
/* `d instanceof TypeError` (and the other builtin error classes) on a
|
|
2727
2848
|
* checked-dynamic value: the from_error cache resolves the DOM encoding
|
|
@@ -2792,6 +2913,10 @@ ScrDyn *scr_dyn_new_func(ScrClosure *clo, ScrDynThunk thunk, uint32_t arity, con
|
|
|
2792
2913
|
* boxed thunk (per-arg checks live there). `args` entries are BORROWED;
|
|
2793
2914
|
* the result is owned (+1), or NULL with the exception pending. */
|
|
2794
2915
|
ScrDyn *scr_dyn_call(const ScrDyn *d, ScrDyn *const *args, size_t argc, const char *what);
|
|
2916
|
+
/* scr_dyn_call over a DOM ARRAY's elements (the spread-application form —
|
|
2917
|
+
* `f(...args)` after the emitted argument array is built): argv IS the
|
|
2918
|
+
* array's items. Borrows both; result owned (+1), or NULL pending. */
|
|
2919
|
+
ScrDyn *scr_dyn_apply(const ScrDyn *d, const ScrDyn *args, const char *what);
|
|
2795
2920
|
|
|
2796
2921
|
/* Path spine for dynCheck error messages — a compile-time-shaped linked
|
|
2797
2922
|
* list the emitted builders stack-allocate per recursion level: `key`
|
|
@@ -2888,6 +3013,87 @@ ScrDyn *scr_dyn_new_promise_adapting(ScrPromise *src,
|
|
|
2888
3013
|
/* BORROWED peek at the boxed promise; NULL when d is not a promise box. */
|
|
2889
3014
|
ScrPromise *scr_dyn_promise_of(const ScrDyn *d);
|
|
2890
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
|
+
|
|
2891
3097
|
/* ── the ambient receiver (JS `this` inside listener/callback bodies) ──
|
|
2892
3098
|
* Node calls a handle's listeners with `this` bound to the emitting
|
|
2893
3099
|
* handle (server.listen(0, function() { this.address().port })), and a
|
|
@@ -2932,7 +3138,28 @@ void scr_dyn_check_listener(const ScrDyn *cb, const char *argname);
|
|
|
2932
3138
|
* generic ERR_INVALID_ARG_TYPE thrower over it (`expected` is the whole
|
|
2933
3139
|
* "of type ..." clause). The handle dispatchers' per-arg gates. */
|
|
2934
3140
|
const char *scr_dyn_specific_type(const ScrDyn *v, char *buf, size_t cap);
|
|
3141
|
+
/* ERR_INVALID_ARG_TYPE with the runtime-rendered Received tail (the
|
|
3142
|
+
* error.argTypeThrow libCall). Borrows all three; always throws. */
|
|
3143
|
+
void scr_throw_arg_type(const ScrStr *argname, const ScrStr *expected, const ScrDyn *got);
|
|
2935
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]);
|
|
2936
3163
|
/* Listener-closure builders for the handle dispatchers' .on(...) paths:
|
|
2937
3164
|
* a runtime-built ScrClosure whose capture is the boxed dyn listener and
|
|
2938
3165
|
* whose invoke boxes the event tuple back into the DOM and calls through
|
|
@@ -3007,6 +3234,12 @@ void scr_jb_put_f64(ScrJsonBuf *b, double v);
|
|
|
3007
3234
|
* as \u00XX, everything else (UTF-8 included) verbatim — exactly the JS
|
|
3008
3235
|
* JSON.stringify escape set for well-formed strings. */
|
|
3009
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);
|
|
3010
3243
|
/* JSON-serialize a DOM value into the buffer — the sc_jw_* walker for the
|
|
3011
3244
|
* dyn leaves the compiler cannot type: object members holding undefined
|
|
3012
3245
|
* DROP, array slots holding undefined print null (exactly Node). */
|
|
@@ -3680,11 +3913,27 @@ ScrJsval *scr_jsval_from_f64(double v);
|
|
|
3680
3913
|
ScrJsval *scr_jsval_from_bool(bool v);
|
|
3681
3914
|
ScrJsval *scr_jsval_from_str(const ScrStr *s);
|
|
3682
3915
|
ScrJsval *scr_jsval_from_json(const ScrStr *json);
|
|
3683
|
-
/* A CHECKED-DYNAMIC (DOM) value entering the island — deep copy
|
|
3684
|
-
* kinds
|
|
3685
|
-
*
|
|
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. */
|
|
3686
3926
|
ScrJsval *scr_jsval_from_dyn(const ScrDyn *d);
|
|
3687
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
|
+
|
|
3688
3937
|
/* Engine operations. Arithmetic yields a fresh cell (NULL = bridged);
|
|
3689
3938
|
* comparisons yield 0/1 (-1 = bridged); truthy/not never fail. */
|
|
3690
3939
|
ScrJsval *scr_jsval_binop(int op, ScrJsval *a, ScrJsval *b);
|
|
@@ -3720,6 +3969,13 @@ ScrJsval *scr_jsval_call_method(ScrJsval *o, const ScrStr *name, int argc, ScrJs
|
|
|
3720
3969
|
* anything else calls with this = o (non-callables throw in the engine). */
|
|
3721
3970
|
ScrJsval *scr_jsval_opt_call_method(ScrJsval *o, const ScrStr *name, int argc, ScrJsval **argv);
|
|
3722
3971
|
ScrJsval *scr_jsval_call(ScrJsval *f, int argc, ScrJsval **argv);
|
|
3972
|
+
/* Spread application on an island callee — `f(...pre, ...spread)` through
|
|
3973
|
+
* the prelude helper's REAL spread syntax (iterator protocols are the
|
|
3974
|
+
* engine's own; the guards front-run V8's exact spread-call TypeError
|
|
3975
|
+
* texts). `pre` is the engine array of leading fixed arguments; `what` the
|
|
3976
|
+
* spread expression's source spelling (the nullish text spells it).
|
|
3977
|
+
* Borrows everything; +1 out, or NULL with the exception bridged. */
|
|
3978
|
+
ScrJsval *scr_jsval_call_spread(ScrJsval *f, ScrJsval *pre, ScrJsval *spread, const ScrStr *what);
|
|
3723
3979
|
/* `new X(...)` on an island callee (jsOp construct) — JS_CallConstructor.
|
|
3724
3980
|
* Borrows everything; +1 out, or NULL with the exception bridged. */
|
|
3725
3981
|
ScrJsval *scr_jsval_construct(ScrJsval *f, int argc, ScrJsval **argv);
|
|
@@ -3867,6 +4123,12 @@ void scr_jsval_cast_fail(ScrJsval *v, const ScrStr *target);
|
|
|
3867
4123
|
*/
|
|
3868
4124
|
size_t scr_f64_to_str(double x, char *buf);
|
|
3869
4125
|
|
|
4126
|
+
/* The Ryū digit core (scr_number.c), shared with the Intl en-US number
|
|
4127
|
+
* formatter: the shortest round-tripping digits of a POSITIVE finite
|
|
4128
|
+
* double — value = 0.digits × 10^n, no trailing zeros, NUL-terminated.
|
|
4129
|
+
* Returns k, the digit count (≤ 17). */
|
|
4130
|
+
int scr_f64_digits(double x, char digits[18], int *n_out);
|
|
4131
|
+
|
|
3870
4132
|
/* ToString for template literals / string coercion. Returns +1. */
|
|
3871
4133
|
ScrStr *scr_f64_to_scrstr(double x);
|
|
3872
4134
|
ScrStr *scr_bool_to_scrstr(bool b); /* interned "true"/"false" */
|
|
@@ -3898,6 +4160,18 @@ bool scr_num_is_safe_integer(double x);
|
|
|
3898
4160
|
ScrStr *scr_num_to_exponential(double x);
|
|
3899
4161
|
ScrStr *scr_num_to_fixed0(double x);
|
|
3900
4162
|
|
|
4163
|
+
/* Object.is over two numbers — the spec's SameValue on doubles: NaN
|
|
4164
|
+
* equals NaN, +0 differs from -0, everything else is ==. Never throws. */
|
|
4165
|
+
bool scr_num_same_value(double a, double b);
|
|
4166
|
+
|
|
4167
|
+
/* Intl.NumberFormat("en-US").format(x) / x.toLocaleString("en-US") with
|
|
4168
|
+
* default options: decimal notation, 0–3 fraction digits rounded half-up
|
|
4169
|
+
* on the shortest round-tripping decimal (ICU's rounding input — NOT
|
|
4170
|
+
* toFixed's exact-value rounding), "," grouping every three integer
|
|
4171
|
+
* digits, "∞"/"NaN" texts, "-0" for negative inputs rounding to zero.
|
|
4172
|
+
* en-US is the one embedded locale. Result +1; never throws. */
|
|
4173
|
+
ScrStr *scr_intl_num_format_en_us(double x);
|
|
4174
|
+
|
|
3901
4175
|
/* ── Date, the composed slice (scr_lib.c) ─────────────────────────────
|
|
3902
4176
|
* Date values have no representation; the runtime surface is exactly
|
|
3903
4177
|
* Date.now() and toISOString over a millisecond time value. */
|
|
@@ -4052,6 +4326,14 @@ typedef enum ScrDataViewGet {
|
|
|
4052
4326
|
} ScrDataViewGet;
|
|
4053
4327
|
double scr_dataview_get(const ScrBytes *b, double byte_off, ScrDataViewGet kind, bool le);
|
|
4054
4328
|
|
|
4329
|
+
/* DataView setters (the integer/float kinds only — the BIG kinds never
|
|
4330
|
+
* lower: bigint arguments have no representation). Values coerce
|
|
4331
|
+
* JS-exactly: the integer kinds by modular truncation (ToUint32's residue
|
|
4332
|
+
* — the narrower widths store its low bytes, the same 2^width residue),
|
|
4333
|
+
* F32 by double→float round-to-nearest-even. Offsets go through ToIndex
|
|
4334
|
+
* with the getters' one RangeError. */
|
|
4335
|
+
void scr_dataview_set(ScrBytes *b, double byte_off, double value, ScrDataViewGet kind, bool le);
|
|
4336
|
+
|
|
4055
4337
|
/* Element read/write. Any invalid index — negative, fractional, NaN, or
|
|
4056
4338
|
* out of bounds — TRAPS like the array runtime (SEMANTICS.md documents
|
|
4057
4339
|
* the divergence from JS's undefined-read/ignored-write). Writes coerce
|
|
@@ -4122,6 +4404,49 @@ bool scr_bytes_is_encoding(const ScrStr *s);
|
|
|
4122
4404
|
bool scr_bytes_equals(const ScrBytes *a, const ScrBytes *b);
|
|
4123
4405
|
double scr_bytes_compare(const ScrBytes *src, const ScrBytes *target, double nargs,
|
|
4124
4406
|
double ts, double te, double ss, double se);
|
|
4407
|
+
/* Node's validateOffset ladder (buffer.js): non-integers (±Infinity and
|
|
4408
|
+
* NaN included) throw the 'an integer' ERR_OUT_OF_RANGE RangeError, the
|
|
4409
|
+
* rest the '>= 0 && <= max' render; max < 0 drops the upper bound.
|
|
4410
|
+
* Returns false after arming the pending throw. */
|
|
4411
|
+
bool scr_bytes_validate_off(const char *name, double value, double max);
|
|
4412
|
+
/* The checked-dynamic compare/equals validators (scr_bytes_io.c): Node's
|
|
4413
|
+
* argument ladder over DOM-boxed arguments — a non-bytes value throws
|
|
4414
|
+
* ERR_INVALID_ARG_TYPE with the API's own argument name ("buf1"/"buf2",
|
|
4415
|
+
* "otherBuffer", "target"), non-number offsets ERR_INVALID_ARG_TYPE
|
|
4416
|
+
* "of type number", out-of-range numbers the validateOffset RangeError;
|
|
4417
|
+
* an undefined offset takes its Node default. All arguments BORROWED. */
|
|
4418
|
+
double scr_buffer_compare_chk(const ScrDyn *a, const ScrDyn *b);
|
|
4419
|
+
bool scr_bytes_equals_chk(const ScrBytes *recv, const ScrDyn *other);
|
|
4420
|
+
double scr_bytes_compare_chk(const ScrBytes *src, const ScrDyn *target,
|
|
4421
|
+
const ScrDyn *ts, const ScrDyn *te,
|
|
4422
|
+
const ScrDyn *ss, const ScrDyn *se);
|
|
4423
|
+
/* new Buffer(number, encoding)'s string-arm type error (always throws;
|
|
4424
|
+
* borrowed). */
|
|
4425
|
+
ScrBytes *scr_buffer_new_string_fail(const ScrDyn *got);
|
|
4426
|
+
/* fs._toUnixTimestamp over a DOM time value: numeric strings and finite
|
|
4427
|
+
* numbers coerce (negatives answer now/1000), the rest throw Node's
|
|
4428
|
+
* ERR_INVALID_ARG_TYPE. Borrowed. */
|
|
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);
|
|
4447
|
+
/* The checked-dynamic max-listeners ladders (scr_events_emitter.c). */
|
|
4448
|
+
ScrEmitter *scr_emitter_set_max_chk(ScrEmitter *em, const ScrDyn *n);
|
|
4449
|
+
void scr_emitter_set_default_max_chk(const ScrDyn *n, const ScrStr *name);
|
|
4125
4450
|
double scr_bytes_index_of(const ScrBytes *b, const ScrBytes *needle, double off, double align, bool fwd);
|
|
4126
4451
|
double scr_bytes_index_of_num(const ScrBytes *b, double v, double off, bool fwd);
|
|
4127
4452
|
ScrBytes *scr_bytes_fill(ScrBytes *b, const ScrBytes *pattern, double nargs, double offset, double end);
|
|
@@ -4386,6 +4711,16 @@ void scr_net_server_on_connection(ScrNetServer *s, ScrClosure *cb /*moves*/, Scr
|
|
|
4386
4711
|
* server never fires it, like Node). */
|
|
4387
4712
|
void scr_net_server_on_secure_connection(ScrNetServer *s, ScrClosure *cb /*moves*/, ScrNetConnFn fn, bool once);
|
|
4388
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);
|
|
4389
4724
|
/* connect with a caller lookup (net.connect({ ..., lookup })): invokes
|
|
4390
4725
|
* lookup(hostname, options, answer-closure) synchronously; answer_fn is
|
|
4391
4726
|
* the emitted per-shape thunk that decodes the answer down to
|
|
@@ -4600,6 +4935,13 @@ void scr_tls_h2_client_wrap(ScrNetSocket *sock, ScrStr *host /*borrowed*/, bool
|
|
|
4600
4935
|
* the default pair, exactly Node. */
|
|
4601
4936
|
typedef struct ScrSecureCtx ScrSecureCtx;
|
|
4602
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);
|
|
4603
4945
|
ScrSecureCtx *scr_secure_ctx_retain(ScrSecureCtx *c);
|
|
4604
4946
|
void scr_secure_ctx_release(ScrSecureCtx *c);
|
|
4605
4947
|
void *scr_secure_ctx_retain_v(void *p);
|
|
@@ -5023,6 +5365,13 @@ void scr_dgram_bind(ScrDgramSocket *s, double port, ScrStr *host /*borrowed*/, S
|
|
|
5023
5365
|
void scr_dgram_connect(ScrDgramSocket *s, double port, ScrStr *host /*borrowed*/, ScrClosure *cb /*moves, nullable*/);
|
|
5024
5366
|
void scr_dgram_send_str(ScrDgramSocket *s, ScrStr *data /*borrowed*/, double port, ScrStr *host /*borrowed*/);
|
|
5025
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);
|
|
5026
5375
|
/* address() parts: ip THROWS "Not running" before bind/connect (+1
|
|
5027
5376
|
* otherwise); family/port are only called after ip succeeded. */
|
|
5028
5377
|
ScrStr *scr_dgram_addr_ip(ScrDgramSocket *s); /* +1, may throw */
|
package/src/scr_stream.c
CHANGED
|
@@ -683,7 +683,9 @@ static void *scr_stream_read_n(ScrStream *s, double size) {
|
|
|
683
683
|
st->r.hwm = h;
|
|
684
684
|
}
|
|
685
685
|
}
|
|
686
|
-
|
|
686
|
+
/* Node's read(): `if (n !== 0) state.emittedReadable = false` — the
|
|
687
|
+
* absent form is NaN there, which also clears; only read(0) keeps it. */
|
|
688
|
+
if (absent || n != 0) st->r.emitted_readable = false;
|
|
687
689
|
if (!absent && n == 0 && st->r.need_readable &&
|
|
688
690
|
(st->r.length >= st->r.hwm || st->r.ended)) {
|
|
689
691
|
if (st->r.length == 0 && st->r.ended) scr_stream_end_readable(s);
|
|
@@ -2148,6 +2150,49 @@ ScrStream *scr_stream_pipeline(double n_d, ScrStream **streams /*borrowed*/,
|
|
|
2148
2150
|
return scr_stream_retain(streams[n - 1]);
|
|
2149
2151
|
}
|
|
2150
2152
|
|
|
2153
|
+
/* ── node:stream/promises ─────────────────────────────────────────────
|
|
2154
|
+
* The promise forms ride the callback machinery above with a settling
|
|
2155
|
+
* watcher: caps[0] boxes the pending promise; the terminal status
|
|
2156
|
+
* fulfills (NULL) or rejects (the error moves through the exception
|
|
2157
|
+
* cell, the reject-pending pattern). */
|
|
2158
|
+
|
|
2159
|
+
static void scr_sp_settle_inv(ScrClosure *cb, ScrStream *s, ScrError *err) {
|
|
2160
|
+
(void)s;
|
|
2161
|
+
ScrPromise *p = scr_box_get_ref(cb->caps[0]); /* +1 */
|
|
2162
|
+
if (err != NULL) {
|
|
2163
|
+
scr_throw_obj(scr_error_retain(err), &scr_error_retain_v, &scr_error_release_v,
|
|
2164
|
+
scr_error_trace_arg());
|
|
2165
|
+
scr_promise_reject_pending(p);
|
|
2166
|
+
} else {
|
|
2167
|
+
scr_promise_fulfill_void(p);
|
|
2168
|
+
}
|
|
2169
|
+
scr_promise_release(p);
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
static ScrClosure *scr_sp_watcher(ScrPromise *p /*borrowed*/) {
|
|
2173
|
+
ScrClosure *w = scr_closure_new((void *)&scr_sp_settle_inv, 1);
|
|
2174
|
+
w->caps[0] = scr_box_new_obj(scr_promise_retain_v, scr_promise_release_v, scr_promise_trace_v);
|
|
2175
|
+
scr_box_set_ref(w->caps[0], scr_promise_retain(p));
|
|
2176
|
+
return w;
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
ScrPromise *scr_sp_finished(ScrStream *s) {
|
|
2180
|
+
ScrPromise *p = scr_promise_new();
|
|
2181
|
+
/* The cleanup closure is the callback form's return value; the promise
|
|
2182
|
+
* form exposes no unhook, so it drops here (the watcher stays parked —
|
|
2183
|
+
* scr_stream_finished retained it into the stream's list). */
|
|
2184
|
+
ScrClosure *cleanup = scr_stream_finished(s, scr_sp_watcher(p), &scr_sp_settle_inv);
|
|
2185
|
+
scr_closure_release(cleanup);
|
|
2186
|
+
return p;
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
ScrPromise *scr_sp_pipeline(double n, ScrStream **streams) {
|
|
2190
|
+
ScrPromise *p = scr_promise_new();
|
|
2191
|
+
ScrStream *dst = scr_stream_pipeline(n, streams, scr_sp_watcher(p), &scr_sp_settle_inv);
|
|
2192
|
+
scr_stream_release(dst);
|
|
2193
|
+
return p;
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2151
2196
|
/* ── the readable surface ─────────────────────────────────────────────── */
|
|
2152
2197
|
|
|
2153
2198
|
bool scr_stream_push(ScrStream *s, ScrBytes *chunk) {
|
|
@@ -2664,10 +2709,12 @@ double scr_stream_prop(ScrStream *s, const char *name) {
|
|
|
2664
2709
|
* arrives outside a _read call). */
|
|
2665
2710
|
static void scr_stream_emit_readable_now(ScrStream *s) {
|
|
2666
2711
|
ScrStreamState *st = s->st;
|
|
2667
|
-
|
|
2712
|
+
/* Node's emitReadable_ clears emittedReadable AFTER the emit (a
|
|
2713
|
+
* 'readable' listener observes true) and only when it really fired. */
|
|
2668
2714
|
if (!st->destroyed && !st->errored && (st->r.length > 0 || st->r.ended)) {
|
|
2669
2715
|
scr_stream_emit0(s, "readable");
|
|
2670
2716
|
if (scr_exc_pending()) return;
|
|
2717
|
+
st->r.emitted_readable = false;
|
|
2671
2718
|
}
|
|
2672
2719
|
st->r.need_readable = st->r.flowing != 1 && !st->r.ended &&
|
|
2673
2720
|
st->r.length <= st->r.hwm;
|