@scriptc/runtime 0.0.7 → 0.0.8
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_exception.c +20 -0
- package/src/scr_island.c +80 -5
- package/src/scr_json.c +62 -0
- package/src/scr_library.c +14 -3
- package/src/scr_object.c +18 -0
- package/src/scr_runtime.h +52 -3
package/package.json
CHANGED
package/src/scr_exception.c
CHANGED
|
@@ -185,6 +185,26 @@ ScrStr *scr_caught_to_string(const ScrCaught *c) {
|
|
|
185
185
|
void scr_library_check_exc(void) {
|
|
186
186
|
if (!scr_exc_pending()) return;
|
|
187
187
|
static char buf[1024]; /* the message is copied out before the payload dies */
|
|
188
|
+
/* The ratified verbatim rule: a thrown message that ALREADY begins with
|
|
189
|
+
* the structured trap-teaching marker (0x01) is delivered exactly as
|
|
190
|
+
* authored — no "Uncaught " prefix, no added newline — which is how a
|
|
191
|
+
* facade-authored structured teaching rides the throw channel through to
|
|
192
|
+
* the sink. Both throw idioms qualify: a thrown string, and an Error
|
|
193
|
+
* whose .message starts with the marker. Everything else keeps the
|
|
194
|
+
* baseline "Uncaught ..." shape below, whose first byte is printable —
|
|
195
|
+
* the guarantee the marker's unambiguity rests on. */
|
|
196
|
+
const ScrStr *marked = NULL;
|
|
197
|
+
if (scr_exc_kind == SCR_EXC_STR) {
|
|
198
|
+
marked = (const ScrStr *)scr_exc_payload;
|
|
199
|
+
} else if (scr_exc_kind == SCR_EXC_OBJ && scr_error_is(scr_exc_payload)) {
|
|
200
|
+
marked = ((const ScrError *)scr_exc_payload)->message;
|
|
201
|
+
}
|
|
202
|
+
if (marked != NULL && marked->len > 0 && (uint8_t)marked->data[0] == 0x01) {
|
|
203
|
+
size_t take = marked->len > sizeof buf ? sizeof buf : marked->len;
|
|
204
|
+
memcpy(buf, marked->data, take);
|
|
205
|
+
scr_exc_reset(); /* the payload is released before the funnel poisons */
|
|
206
|
+
scr_trap_len(buf, take);
|
|
207
|
+
}
|
|
188
208
|
size_t n = 0;
|
|
189
209
|
const char prefix[] = "Uncaught ";
|
|
190
210
|
memcpy(buf, prefix, sizeof prefix - 1);
|
package/src/scr_island.c
CHANGED
|
@@ -1412,8 +1412,27 @@ static JSValue isl_hostfn_invoke(JSContext *ctx, JSValueConst this_val, int argc
|
|
|
1412
1412
|
IslHostFn *b = JS_GetOpaque(func_data[0], isl_hostfn_class_id);
|
|
1413
1413
|
if (!b) return JS_ThrowTypeError(ctx, "detached scriptc host function");
|
|
1414
1414
|
ScrJsval *cells[ISL_HOSTFN_MAX_ARITY];
|
|
1415
|
-
|
|
1416
|
-
|
|
1415
|
+
int ncells;
|
|
1416
|
+
if (b->arity < 0) {
|
|
1417
|
+
/* The ISLAND-REST shape (negative arity = -(leading declared + 1)):
|
|
1418
|
+
* leading params pad/drop like any host call; the trailing cell is a
|
|
1419
|
+
* fresh ENGINE ARRAY of the surplus arguments — the closure's rest
|
|
1420
|
+
* binding IS the engine's own arguments array. */
|
|
1421
|
+
int leading = -b->arity - 1;
|
|
1422
|
+
for (int i = 0; i < leading; i++) {
|
|
1423
|
+
cells[i] = isl_cell_new(i < argc ? JS_DupValue(ctx, argv[i]) : JS_UNDEFINED);
|
|
1424
|
+
}
|
|
1425
|
+
JSValue rest = JS_NewArray(ctx);
|
|
1426
|
+
for (int i = leading; i < argc; i++) {
|
|
1427
|
+
JS_SetPropertyUint32(ctx, rest, (uint32_t)(i - leading), JS_DupValue(ctx, argv[i]));
|
|
1428
|
+
}
|
|
1429
|
+
cells[leading] = isl_cell_new(rest);
|
|
1430
|
+
ncells = leading + 1;
|
|
1431
|
+
} else {
|
|
1432
|
+
for (int i = 0; i < b->arity; i++) {
|
|
1433
|
+
cells[i] = isl_cell_new(i < argc ? JS_DupValue(ctx, argv[i]) : JS_UNDEFINED);
|
|
1434
|
+
}
|
|
1435
|
+
ncells = b->arity;
|
|
1417
1436
|
}
|
|
1418
1437
|
bool strayed_before = isl_anchor_strayed;
|
|
1419
1438
|
isl_host_depth++;
|
|
@@ -1429,7 +1448,7 @@ static JSValue isl_hostfn_invoke(JSContext *ctx, JSValueConst this_val, int argc
|
|
|
1429
1448
|
isl_anchor_here();
|
|
1430
1449
|
isl_anchor_strayed = strayed_before;
|
|
1431
1450
|
}
|
|
1432
|
-
for (int i = 0; i <
|
|
1451
|
+
for (int i = 0; i < ncells; i++) scr_jsval_release(cells[i]);
|
|
1433
1452
|
if (scr_exc_pending()) {
|
|
1434
1453
|
if (r) scr_jsval_release(r);
|
|
1435
1454
|
return isl_throw_pending(ctx);
|
|
@@ -1443,7 +1462,9 @@ static JSValue isl_hostfn_invoke(JSContext *ctx, JSValueConst this_val, int argc
|
|
|
1443
1462
|
ScrJsval *scr_jsval_from_closure(ScrClosure *c, int arity,
|
|
1444
1463
|
ScrJsval *(*adapt)(ScrClosure *, ScrJsval **)) {
|
|
1445
1464
|
isl_entry();
|
|
1446
|
-
|
|
1465
|
+
/* Negative arity = the island-rest shape; the CELL count is the leading
|
|
1466
|
+
* declared params + the one rest-array slot. */
|
|
1467
|
+
if ((arity < 0 ? -arity : arity) > ISL_HOSTFN_MAX_ARITY) {
|
|
1447
1468
|
fprintf(stderr, "scriptc: island callback arity %d exceeds %d\n", arity,
|
|
1448
1469
|
ISL_HOSTFN_MAX_ARITY);
|
|
1449
1470
|
abort(); /* the frontend fences this; reaching here is a compiler bug */
|
|
@@ -1459,7 +1480,7 @@ ScrJsval *scr_jsval_from_closure(ScrClosure *c, int arity,
|
|
|
1459
1480
|
JSValue box = JS_NewObjectClass(isl_ctx, isl_hostfn_class_id);
|
|
1460
1481
|
JS_SetOpaque(box, b);
|
|
1461
1482
|
JSValueConst data[1] = {box};
|
|
1462
|
-
JSValue fn = JS_NewCFunctionData(isl_ctx, isl_hostfn_invoke, arity, 0, 1, data);
|
|
1483
|
+
JSValue fn = JS_NewCFunctionData(isl_ctx, isl_hostfn_invoke, arity < 0 ? -arity - 1 : arity, 0, 1, data);
|
|
1463
1484
|
JS_FreeValue(isl_ctx, box); /* fn's func_data holds its own reference */
|
|
1464
1485
|
return isl_cell_new(fn);
|
|
1465
1486
|
}
|
|
@@ -1717,6 +1738,60 @@ ScrJsval *scr_jsval_obj_lit(int npairs, ScrJsval **kv) {
|
|
|
1717
1738
|
return isl_cell_new(o);
|
|
1718
1739
|
}
|
|
1719
1740
|
|
|
1741
|
+
/* The engine-native TemplateStringsArray for an island tag call: `kv`
|
|
1742
|
+
* carries n cooked strings then n raw strings — a fresh array whose
|
|
1743
|
+
* `.raw` property holds the raw spellings, exactly the object a tagged
|
|
1744
|
+
* template hands its tag (a JSON marshal would drop `.raw`, and tags
|
|
1745
|
+
* dispatch on it). */
|
|
1746
|
+
ScrJsval *scr_jsval_tpl_strings(int n, ScrJsval **kv) {
|
|
1747
|
+
isl_entry();
|
|
1748
|
+
JSValue cooked = JS_NewArray(isl_ctx);
|
|
1749
|
+
JSValue raw = JS_NewArray(isl_ctx);
|
|
1750
|
+
for (int i = 0; i < n; i++) {
|
|
1751
|
+
JS_SetPropertyUint32(isl_ctx, cooked, (uint32_t)i, JS_DupValue(isl_ctx, kv[i]->v));
|
|
1752
|
+
JS_SetPropertyUint32(isl_ctx, raw, (uint32_t)i, JS_DupValue(isl_ctx, kv[n + i]->v));
|
|
1753
|
+
}
|
|
1754
|
+
JS_SetPropertyStr(isl_ctx, cooked, "raw", raw); /* consumes raw */
|
|
1755
|
+
return isl_cell_new(cooked);
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
/* Spread completion for an island-native literal: copies `src`'s own
|
|
1759
|
+
* enumerable properties onto `obj` — the engine's own Object.assign (the
|
|
1760
|
+
* spec's CopyDataProperties; null/undefined sources spread nothing) — and
|
|
1761
|
+
* answers the target retained (+1). NULL with the exception pending when
|
|
1762
|
+
* a source getter throws. */
|
|
1763
|
+
ScrJsval *scr_jsval_obj_spread(ScrJsval *obj, ScrJsval *src) {
|
|
1764
|
+
isl_entry();
|
|
1765
|
+
if (JS_IsNull(src->v) || JS_IsUndefined(src->v)) return scr_jsval_retain(obj);
|
|
1766
|
+
JSValue global = JS_GetGlobalObject(isl_ctx);
|
|
1767
|
+
JSValue object_ctor = JS_GetPropertyStr(isl_ctx, global, "Object");
|
|
1768
|
+
JS_FreeValue(isl_ctx, global);
|
|
1769
|
+
JSValue assign = JS_GetPropertyStr(isl_ctx, object_ctor, "assign");
|
|
1770
|
+
JS_FreeValue(isl_ctx, object_ctor);
|
|
1771
|
+
JSValueConst args[2] = { obj->v, src->v };
|
|
1772
|
+
JSValue r = JS_Call(isl_ctx, assign, JS_UNDEFINED, 2, args);
|
|
1773
|
+
JS_FreeValue(isl_ctx, assign);
|
|
1774
|
+
if (JS_IsException(r)) {
|
|
1775
|
+
isl_bridge_exception();
|
|
1776
|
+
return NULL;
|
|
1777
|
+
}
|
|
1778
|
+
JS_FreeValue(isl_ctx, r); /* assign answers the target itself */
|
|
1779
|
+
return scr_jsval_retain(obj);
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
/* Getter completion for an island-native literal: defines `key` on `obj`
|
|
1783
|
+
* as an engine GETTER invoking `fn` (a marshaled host function), and
|
|
1784
|
+
* answers the object retained (+1) so builds chain. Enumerable +
|
|
1785
|
+
* configurable, no setter — exactly a JS object-literal `get k() {}`. */
|
|
1786
|
+
ScrJsval *scr_jsval_define_getter(ScrJsval *obj, ScrJsval *key, ScrJsval *fn) {
|
|
1787
|
+
isl_entry();
|
|
1788
|
+
JSAtom k = JS_ValueToAtom(isl_ctx, key->v);
|
|
1789
|
+
JS_DefinePropertyGetSet(isl_ctx, obj->v, k, JS_DupValue(isl_ctx, fn->v), JS_UNDEFINED,
|
|
1790
|
+
JS_PROP_ENUMERABLE | JS_PROP_CONFIGURABLE);
|
|
1791
|
+
JS_FreeAtom(isl_ctx, k);
|
|
1792
|
+
return scr_jsval_retain(obj);
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1720
1795
|
ScrJsval *scr_jsval_arr_lit(int n, ScrJsval **elems) {
|
|
1721
1796
|
isl_entry();
|
|
1722
1797
|
JSValue a = JS_NewArray(isl_ctx);
|
package/src/scr_json.c
CHANGED
|
@@ -1078,6 +1078,26 @@ void scr_dyn_key_set(ScrDyn *recv, ScrStr *key, ScrDyn *value) {
|
|
|
1078
1078
|
scr_dyn_obj_set(recv, key->data, key->len, scr_dyn_retain(value));
|
|
1079
1079
|
return;
|
|
1080
1080
|
}
|
|
1081
|
+
if (recv->kind == SCR_DYN_ARR) {
|
|
1082
|
+
/* An INDEX write on a DOM array (`args[i] = v` — the variadic-rest
|
|
1083
|
+
* rebuild): a canonical numeric key sets/extends the element, holes
|
|
1084
|
+
* padding with undefined exactly like JS length growth. Non-index
|
|
1085
|
+
* keys keep the throw below (DOM arrays carry no expando table). */
|
|
1086
|
+
size_t idx = 0;
|
|
1087
|
+
int is_index = key->len > 0 && !(key->len > 1 && key->data[0] == '0');
|
|
1088
|
+
for (size_t i = 0; is_index && i < key->len; i++) {
|
|
1089
|
+
if (key->data[i] < '0' || key->data[i] > '9') is_index = 0;
|
|
1090
|
+
else idx = idx * 10 + (size_t)(key->data[i] - '0');
|
|
1091
|
+
}
|
|
1092
|
+
if (is_index) {
|
|
1093
|
+
while (recv->v.arr.len <= idx) {
|
|
1094
|
+
scr_dyn_arr_push(recv, scr_dyn_retain(scr_dyn_undefined()));
|
|
1095
|
+
}
|
|
1096
|
+
scr_dyn_release(recv->v.arr.items[idx]);
|
|
1097
|
+
recv->v.arr.items[idx] = scr_dyn_retain(value);
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1081
1101
|
if (recv->kind == SCR_DYN_HANDLE) {
|
|
1082
1102
|
scr_dyn_handle_key_set(recv, key, value);
|
|
1083
1103
|
return;
|
|
@@ -2089,6 +2109,48 @@ static ScrDyn *scr_dyn_objwalk(const ScrDyn *v, ScrObjWalk mode) {
|
|
|
2089
2109
|
}
|
|
2090
2110
|
|
|
2091
2111
|
ScrDyn *scr_dyn_obj_keys(const ScrDyn *v) { return scr_dyn_objwalk(v, SCR_OBJWALK_KEYS); }
|
|
2112
|
+
|
|
2113
|
+
/* Object.assign over DOM values: copies `src`'s own members onto `target`
|
|
2114
|
+
* (last write wins) and answers the target retained (+1). Nullish
|
|
2115
|
+
* receivers throw Node's ToObject TypeError; nullish sources copy
|
|
2116
|
+
* nothing; non-object sources copy nothing DOM-representable. */
|
|
2117
|
+
ScrDyn *scr_dyn_assign(ScrDyn *target, const ScrDyn *src) {
|
|
2118
|
+
if (target->kind == SCR_DYN_UNDEF || target->kind == SCR_DYN_NULL) {
|
|
2119
|
+
const char *m = "Cannot convert undefined or null to object";
|
|
2120
|
+
scr_throw_error_msg(SCR_ERR_TYPE, m, strlen(m));
|
|
2121
|
+
return NULL;
|
|
2122
|
+
}
|
|
2123
|
+
if (target->kind == SCR_DYN_OBJ && src->kind == SCR_DYN_OBJ) {
|
|
2124
|
+
for (size_t i = 0; i < src->v.obj.len; i++) {
|
|
2125
|
+
scr_dyn_obj_set(target, src->v.obj.entries[i].key,
|
|
2126
|
+
src->v.obj.entries[i].key_len,
|
|
2127
|
+
scr_dyn_retain(src->v.obj.entries[i].value));
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
return scr_dyn_retain(target);
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2133
|
+
bool scr_dyn_has_own(const ScrDyn *v, const ScrStr *key) {
|
|
2134
|
+
if (v->kind == SCR_DYN_UNDEF || v->kind == SCR_DYN_NULL) {
|
|
2135
|
+
const char *m = "Cannot convert undefined or null to object";
|
|
2136
|
+
scr_throw_error_msg(SCR_ERR_TYPE, m, strlen(m));
|
|
2137
|
+
return false;
|
|
2138
|
+
}
|
|
2139
|
+
if (v->kind == SCR_DYN_OBJ) {
|
|
2140
|
+
return scr_dyn_obj_get(v, key->data, key->len) != NULL;
|
|
2141
|
+
}
|
|
2142
|
+
if (v->kind == SCR_DYN_ARR) {
|
|
2143
|
+
if (key->len == 6 && memcmp(key->data, "length", 6) == 0) return true;
|
|
2144
|
+
size_t idx = 0;
|
|
2145
|
+
int is_index = key->len > 0 && !(key->len > 1 && key->data[0] == '0');
|
|
2146
|
+
for (size_t i = 0; is_index && i < key->len; i++) {
|
|
2147
|
+
if (key->data[i] < '0' || key->data[i] > '9') is_index = 0;
|
|
2148
|
+
else idx = idx * 10 + (size_t)(key->data[i] - '0');
|
|
2149
|
+
}
|
|
2150
|
+
return is_index != 0 && idx < v->v.arr.len;
|
|
2151
|
+
}
|
|
2152
|
+
return false;
|
|
2153
|
+
}
|
|
2092
2154
|
ScrDyn *scr_dyn_obj_values(const ScrDyn *v) { return scr_dyn_objwalk(v, SCR_OBJWALK_VALUES); }
|
|
2093
2155
|
ScrDyn *scr_dyn_obj_entries(const ScrDyn *v) { return scr_dyn_objwalk(v, SCR_OBJWALK_ENTRIES); }
|
|
2094
2156
|
|
package/src/scr_library.c
CHANGED
|
@@ -60,6 +60,14 @@ __attribute__((noinline)) _Noreturn void scr_trap(const char *msg) {
|
|
|
60
60
|
scr_library_trap_deliver(msg, strlen(msg), SCR_TRAP_ADDR());
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
__attribute__((noinline)) _Noreturn void scr_trap_len(const char *msg, size_t len) {
|
|
64
|
+
/* The length-delimited funnel entry: structured trap-teaching messages
|
|
65
|
+
* and verbatim 0x01-led thrown messages are byte-counted, never
|
|
66
|
+
* NUL-scanned (a thrown JS string may embed NUL). Same poison-deliver-
|
|
67
|
+
* abort discipline as scr_trap. */
|
|
68
|
+
scr_library_trap_deliver(msg, len, SCR_TRAP_ADDR());
|
|
69
|
+
}
|
|
70
|
+
|
|
63
71
|
__attribute__((noinline)) _Noreturn void scr_trap_fmt(const char *fmt, ...) {
|
|
64
72
|
static char buf[512]; /* no malloc on the invariant-failure path */
|
|
65
73
|
va_list ap;
|
|
@@ -125,13 +133,16 @@ ScrStr *scr_library_str_in(const uint8_t *p, size_t len) {
|
|
|
125
133
|
return scr_str_new(len == 0 ? "" : (const char *)p, len);
|
|
126
134
|
}
|
|
127
135
|
|
|
128
|
-
ScrBytes *scr_library_bytes_in(const uint8_t *p, size_t len) {
|
|
136
|
+
ScrBytes *scr_library_bytes_in(const uint8_t *p, size_t len, const char *trap_msg) {
|
|
129
137
|
ScrBytes *b = scr_bytes_new(SCR_BYTES_U8, (double)len);
|
|
130
138
|
if (b == NULL) {
|
|
131
139
|
/* scr_bytes_new throws only for lengths past 2^53-1 — an impossible
|
|
132
|
-
* host buffer; funnel the contract violation instead of a NULL deref.
|
|
140
|
+
* host buffer; funnel the contract violation instead of a NULL deref.
|
|
141
|
+
* The message is the wrapper's compiler-assembled structured
|
|
142
|
+
* trap-teaching form (code SC4012, the trapping export's symbol, the
|
|
143
|
+
* profile's teaching and remediation) — opaque bytes here. */
|
|
133
144
|
scr_exc_clear();
|
|
134
|
-
scr_trap(
|
|
145
|
+
scr_trap(trap_msg);
|
|
135
146
|
}
|
|
136
147
|
if (len > 0 && p != NULL) memcpy(b->data, p, len);
|
|
137
148
|
return b;
|
package/src/scr_object.c
CHANGED
|
@@ -14,6 +14,24 @@ ScrStr *scr_classobj_name(ScrClassObj *c) {
|
|
|
14
14
|
return scr_str_retain((ScrStr *)c->name);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
/* The keyed-write MISS on a fixed-shape (signature-free) record: JS would
|
|
18
|
+
* ADD the property, which a monomorphic struct cannot — the write throws
|
|
19
|
+
* the catchable TypeError naming the key instead (the documented
|
|
20
|
+
* divergence; the emitted per-shape keyed-write helpers call this after
|
|
21
|
+
* the declared-field chain misses). */
|
|
22
|
+
void scr_record_key_miss(ScrStr *k) {
|
|
23
|
+
const char *base = "Cannot add property '";
|
|
24
|
+
ScrStr *head = scr_str_new(base, strlen(base));
|
|
25
|
+
ScrStr *with_key = scr_str_concat(head, k);
|
|
26
|
+
scr_str_release(head);
|
|
27
|
+
const char *tail_c = "' to a fixed-shape object";
|
|
28
|
+
ScrStr *tail = scr_str_new(tail_c, strlen(tail_c));
|
|
29
|
+
ScrStr *msg = scr_str_concat(with_key, tail);
|
|
30
|
+
scr_str_release(with_key);
|
|
31
|
+
scr_str_release(tail);
|
|
32
|
+
scr_throw_error(SCR_ERR_TYPE, msg); /* takes ownership */
|
|
33
|
+
}
|
|
34
|
+
|
|
17
35
|
#ifdef SCR_RC_AUDIT
|
|
18
36
|
static long scr_live_objects = 0;
|
|
19
37
|
long scr_obj_live_count(void) { return scr_live_objects; }
|
package/src/scr_runtime.h
CHANGED
|
@@ -67,7 +67,22 @@ typedef struct ScrBytes ScrBytes;
|
|
|
67
67
|
* call; address is the trap site's return address (0 when the toolchain
|
|
68
68
|
* cannot supply one); ctx is the registration's opaque pointer. The sink
|
|
69
69
|
* must not call back into any library entry and must not unwind or longjmp
|
|
70
|
-
* back into library frames.
|
|
70
|
+
* back into library frames.
|
|
71
|
+
*
|
|
72
|
+
* Message shape (the ratified structured trap-teaching encoding): a
|
|
73
|
+
* BASELINE message is plain text whose first byte is printable (>= 0x20) —
|
|
74
|
+
* no emitter path ever produces an unstructured message starting below
|
|
75
|
+
* 0x20. A STRUCTURED message begins with the marker byte 0x01 followed by
|
|
76
|
+
* the human teaching text and 0x1F-separated fields:
|
|
77
|
+
*
|
|
78
|
+
* 0x01 text 0x1F code 0x1F symbol [ 0x1F remediation ]
|
|
79
|
+
*
|
|
80
|
+
* so msg_len > 0 && msg[0] == 0x01 is the one version test. Parse: split
|
|
81
|
+
* the bytes after the marker on 0x1F — field 0 is the human text, 1 the
|
|
82
|
+
* diagnostic code, 2 the trapping symbol as the host linked it, 3 the
|
|
83
|
+
* remediation; a missing or empty field means none; ignore any field past
|
|
84
|
+
* the fourth. Fields are (pointer, length) — never assume NUL termination.
|
|
85
|
+
* A plain-text host may print the whole buffer: the teaching leads it. */
|
|
71
86
|
typedef void (*ScrLibSinkFn)(void *ctx, const uint8_t *msg, size_t msg_len,
|
|
72
87
|
uint64_t address);
|
|
73
88
|
void scr_library_set_sink(ScrLibSinkFn fn, void *ctx); /* latest wins */
|
|
@@ -96,16 +111,29 @@ void scr_library_register_reset(void (*fn)(void));
|
|
|
96
111
|
/* An escaped exception at an entry boundary: renders the same "Uncaught
|
|
97
112
|
* ..." text the executable epilogue prints, releases the payload, and
|
|
98
113
|
* routes the text through the trap funnel. No-op when nothing is pending.
|
|
99
|
-
*
|
|
114
|
+
* The ratified verbatim rule: a thrown message that ALREADY begins with the
|
|
115
|
+
* structured marker 0x01 (a thrown string, or an Error whose .message
|
|
116
|
+
* starts with it) is delivered byte-for-byte — no "Uncaught " prefix, no
|
|
117
|
+
* added newline — which is how facade-authored structured teachings ride
|
|
118
|
+
* the throw channel to the sink. Defined in scr_exception.c (it owns the
|
|
119
|
+
* cell). */
|
|
100
120
|
void scr_library_check_exc(void);
|
|
101
121
|
|
|
122
|
+
/* The length-taking funnel entry (library lane only): delivers exactly the
|
|
123
|
+
* given bytes to the sink — the verbatim path above needs it because a
|
|
124
|
+
* structured message is length-delimited, never NUL-scanned. */
|
|
125
|
+
_Noreturn void scr_trap_len(const char *msg, size_t len);
|
|
126
|
+
|
|
102
127
|
/* Marshalling helpers the generated wrappers call (both emissions share
|
|
103
128
|
* these bodies, which is how the two lanes stay identical by
|
|
104
129
|
* construction). Inbound is borrowed-and-copied; outbound values MOVE into
|
|
105
130
|
* the result arena and stay valid until the next arena reset. String
|
|
106
131
|
* results are NUL-terminated after *out_len bytes (ScrStr's layout). */
|
|
107
132
|
ScrStr *scr_library_str_in(const uint8_t *p, size_t len); /* +1 */
|
|
108
|
-
|
|
133
|
+
/* trap_msg is the wrapper's compiler-assembled host-contract trap message
|
|
134
|
+
* (structured trap-teaching bytes naming this entry's symbol), delivered
|
|
135
|
+
* through the funnel when len falls outside the marshalling class. */
|
|
136
|
+
ScrBytes *scr_library_bytes_in(const uint8_t *p, size_t len, const char *trap_msg); /* +1, u8 */
|
|
109
137
|
void scr_library_str_out(ScrStr *s, const uint8_t **out, size_t *out_len);
|
|
110
138
|
void scr_library_bytes_out(ScrBytes *b, const uint8_t **out, size_t *out_len);
|
|
111
139
|
|
|
@@ -287,6 +315,10 @@ void *scr_classobj_retain_v(void *c);
|
|
|
287
315
|
void scr_classobj_release_v(void *c);
|
|
288
316
|
/* `X.name` (+1 — a no-op retain on the interned immortal). */
|
|
289
317
|
ScrStr *scr_classobj_name(ScrClassObj *c);
|
|
318
|
+
/* The keyed-write miss on a fixed-shape record: throws the catchable
|
|
319
|
+
* TypeError naming the key (JS would add the property — the documented
|
|
320
|
+
* monomorphic-struct divergence). scr_object.c. */
|
|
321
|
+
void scr_record_key_miss(ScrStr *k);
|
|
290
322
|
|
|
291
323
|
/* ── error objects (scr_error.c) ──────────────────────────────────────
|
|
292
324
|
* `Error` and its lib subclasses (TypeError/RangeError/SyntaxError) are a
|
|
@@ -2640,6 +2672,13 @@ ScrDyn *scr_dyn_obj_get(const ScrDyn *d, const char *key, size_t key_len);
|
|
|
2640
2672
|
* member nodes. null/undefined receivers throw Node's catchable
|
|
2641
2673
|
* TypeError. */
|
|
2642
2674
|
ScrDyn *scr_dyn_obj_keys(const ScrDyn *v);
|
|
2675
|
+
/* Object.hasOwn over a DOM receiver: OBJ member presence, ARR index
|
|
2676
|
+
* bounds ("length" included); nullish receivers throw Node's ToObject
|
|
2677
|
+
* TypeError; every other kind answers false. */
|
|
2678
|
+
bool scr_dyn_has_own(const ScrDyn *v, const ScrStr *key);
|
|
2679
|
+
/* Object.assign over DOM values (+1 target back; ToObject TypeError on a
|
|
2680
|
+
* nullish target). */
|
|
2681
|
+
ScrDyn *scr_dyn_assign(ScrDyn *target, const ScrDyn *src);
|
|
2643
2682
|
ScrDyn *scr_dyn_obj_values(const ScrDyn *v);
|
|
2644
2683
|
ScrDyn *scr_dyn_obj_entries(const ScrDyn *v);
|
|
2645
2684
|
|
|
@@ -3765,6 +3804,16 @@ ScrPromise *scr_jsval_bridge_promise(ScrJsval *v, int payload);
|
|
|
3765
3804
|
* marshaled strings) or an array from elements. Borrow argv; +1 out.
|
|
3766
3805
|
* Cannot fail (allocation failure aborts, like every runtime OOM). */
|
|
3767
3806
|
ScrJsval *scr_jsval_obj_lit(int npairs, ScrJsval **kv);
|
|
3807
|
+
/* Getter completion for an island literal: defines `key` on `obj` as an
|
|
3808
|
+
* engine getter invoking `fn`; answers the object retained (+1). */
|
|
3809
|
+
ScrJsval *scr_jsval_define_getter(ScrJsval *obj, ScrJsval *key, ScrJsval *fn);
|
|
3810
|
+
/* The engine TemplateStringsArray for an island tag call: n cooked then n
|
|
3811
|
+
* raw strings; the result array carries `.raw` (+1). */
|
|
3812
|
+
ScrJsval *scr_jsval_tpl_strings(int n, ScrJsval **kv);
|
|
3813
|
+
/* Spread completion for an island literal: engine CopyDataProperties of
|
|
3814
|
+
* `src` onto `obj`; answers the target (+1), NULL + pending on a getter
|
|
3815
|
+
* throw. */
|
|
3816
|
+
ScrJsval *scr_jsval_obj_spread(ScrJsval *obj, ScrJsval *src);
|
|
3768
3817
|
ScrJsval *scr_jsval_arr_lit(int n, ScrJsval **elems);
|
|
3769
3818
|
|
|
3770
3819
|
/* Marshal out (island → static): validated, STRICT extraction — a
|