@scriptc/runtime 0.0.21 → 0.0.22

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scriptc/runtime",
3
- "version": "0.0.21",
3
+ "version": "0.0.22",
4
4
  "description": "scriptc native runtime — C sources, compiled into every scriptc binary",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://scriptc.dev",
package/src/scr_assert.c CHANGED
@@ -444,6 +444,8 @@ static bool scr_assert_dyn_same_value(const ScrDyn *a, const ScrDyn *b) {
444
444
  * === — exact for SameValue too, since wrap-time scalar
445
445
  * normalization leaves only reference kinds behind. */
446
446
  return a == b || scr_dyn_jsval_ops()->strict_eq(a->v.jsval.cell, b->v.jsval.cell);
447
+ case SCR_DYN_TYPED_REF:
448
+ return scr_dyn_strict_eq(a, b);
447
449
  default:
448
450
  return a == b; /* ARR/OBJ/BYTES: node identity */
449
451
  }
@@ -459,6 +461,18 @@ static bool scr_assert_dyn_same_value(const ScrDyn *a, const ScrDyn *b) {
459
461
  * memo here where Node carries one (documented divergence). */
460
462
  static bool scr_assert_dyn_deep_eq(const ScrDyn *a, const ScrDyn *b) {
461
463
  if (a == b) return true;
464
+ if (a->kind == SCR_DYN_TYPED_REF || b->kind == SCR_DYN_TYPED_REF) {
465
+ ScrDyn *ma = a->kind == SCR_DYN_TYPED_REF
466
+ ? scr_dyn_typed_ref_materialize(a)
467
+ : scr_dyn_retain((ScrDyn *)a);
468
+ ScrDyn *mb = b->kind == SCR_DYN_TYPED_REF
469
+ ? scr_dyn_typed_ref_materialize(b)
470
+ : scr_dyn_retain((ScrDyn *)b);
471
+ bool same = scr_assert_dyn_deep_eq(ma, mb);
472
+ scr_dyn_release(ma);
473
+ scr_dyn_release(mb);
474
+ return same;
475
+ }
462
476
  if (a->kind != b->kind) {
463
477
  /* A MIXED comparison with an island side (wrapped engine object vs
464
478
  * dyn data): Node walks both structurally — a plain `false` would
@@ -524,6 +538,8 @@ static bool scr_assert_dyn_deep_eq(const ScrDyn *a, const ScrDyn *b) {
524
538
  if (scr_dyn_jsval_ops()->strict_eq(a->v.jsval.cell, b->v.jsval.cell)) return true;
525
539
  scr_dyn_isl_fence(a, "deepStrictEqual");
526
540
  return false;
541
+ case SCR_DYN_TYPED_REF:
542
+ return false; /* both mixed and same-kind capsules returned above */
527
543
  }
528
544
  return false; /* unreachable */
529
545
  }
@@ -684,6 +700,12 @@ static void scr_assert_cf_value(ScrAssertBuf *b, const ScrDyn *d, size_t indent,
684
700
  ab_cstr(b, "[island value]");
685
701
  return;
686
702
  }
703
+ case SCR_DYN_TYPED_REF: {
704
+ ScrDyn *materialized = scr_dyn_typed_ref_materialize(d);
705
+ scr_assert_cf_value(b, materialized, indent, depth);
706
+ scr_dyn_release(materialized);
707
+ return;
708
+ }
687
709
  case SCR_DYN_OBJ: {
688
710
  /* The null-proto dictionary renders with Node's prefix in the
689
711
  * failure diff too (assertion_error.js inspects both sides). */
@@ -928,6 +950,7 @@ static bool scr_assert_print_myers(ScrAssertBuf *b, const ScrDiffOp *diff, size_
928
950
  static bool scr_assert_dyn_is_object(const ScrDyn *d) {
929
951
  return d->kind == SCR_DYN_ARR || d->kind == SCR_DYN_OBJ || d->kind == SCR_DYN_BYTES ||
930
952
  d->kind == SCR_DYN_HANDLE || d->kind == SCR_DYN_PROMISE ||
953
+ d->kind == SCR_DYN_TYPED_REF ||
931
954
  scr_dyn_isl_typeof_is(d, "object"); /* engine-held: the engine's typeof */
932
955
  }
933
956
 
package/src/scr_bytes.c CHANGED
@@ -86,6 +86,13 @@ void scr_bytes_release_v(void *b) { scr_bytes_release((ScrBytes *)b); }
86
86
 
87
87
  double scr_bytes_len(const ScrBytes *b) { return (double)b->len; }
88
88
 
89
+ void scr_bytes_copy_contents(ScrBytes *dst, const ScrBytes *src) {
90
+ if (dst->elem != src->elem || dst->len != src->len) {
91
+ scr_trap("scriptc: typed array snapshot shape changed\n");
92
+ }
93
+ memcpy(dst->data, src->data, dst->len * scr_bytes_elem_size(dst->elem));
94
+ }
95
+
89
96
  double scr_bytes_byte_len(const ScrBytes *b) {
90
97
  return (double)(b->len * scr_bytes_elem_size(b->elem));
91
98
  }
@@ -119,6 +119,12 @@ static void scr_dyn_display_buf(ScrJsonBuf *b, const ScrDyn *d) {
119
119
  * pending and appends nothing — the loud path). */
120
120
  scr_dyn_isl_tostr_buf(b, d);
121
121
  return;
122
+ case SCR_DYN_TYPED_REF: {
123
+ ScrDyn *materialized = scr_dyn_typed_ref_materialize(d);
124
+ scr_dyn_display_buf(b, materialized);
125
+ scr_dyn_release(materialized);
126
+ return;
127
+ }
122
128
  }
123
129
  }
124
130
 
@@ -306,6 +312,13 @@ static bool dyn_arr_proto_unimpl(const char *m) {
306
312
  for (size_t i = 0; names[i]; i++) if (dyn_name_is(m, names[i])) return true;
307
313
  return false;
308
314
  }
315
+ static bool dyn_arr_proto_mutates(const char *m) {
316
+ static const char *names[] = {
317
+ "push", "pop", "shift", "unshift", "reverse", "sort", NULL
318
+ };
319
+ for (size_t i = 0; names[i]; i++) if (dyn_name_is(m, names[i])) return true;
320
+ return false;
321
+ }
309
322
  static bool dyn_bytes_proto_real(const char *m) {
310
323
  static const char *names[] = { "slice", "at", "indexOf", "lastIndexOf", "includes", "join",
311
324
  "forEach", "map", "filter", "some", "every", "find", "findIndex", "reverse", "fill", "set",
@@ -315,7 +328,19 @@ static bool dyn_bytes_proto_real(const char *m) {
315
328
  return false;
316
329
  }
317
330
 
318
- ScrDyn *scr_dyn_invoke(ScrDyn *recv, const char *method, ScrDyn *const *args, size_t argc, const char *what) {
331
+ static ScrDyn *scr_dyn_invoke_impl(
332
+ ScrDyn *recv, const char *method, ScrDyn *const *args, size_t argc,
333
+ const char *what, ScrDyn *callback_recv);
334
+
335
+ ScrDyn *scr_dyn_invoke(ScrDyn *recv, const char *method,
336
+ ScrDyn *const *args, size_t argc,
337
+ const char *what) {
338
+ return scr_dyn_invoke_impl(recv, method, args, argc, what, NULL);
339
+ }
340
+
341
+ static ScrDyn *scr_dyn_invoke_impl(
342
+ ScrDyn *recv, const char *method, ScrDyn *const *args, size_t argc,
343
+ const char *what, ScrDyn *callback_recv) {
319
344
  if (recv->kind == SCR_DYN_UNDEF || recv->kind == SCR_DYN_NULL) {
320
345
  ScrJsonBuf b;
321
346
  scr_jb_init(&b);
@@ -347,6 +372,26 @@ ScrDyn *scr_dyn_invoke(ScrDyn *recv, const char *method, ScrDyn *const *args, si
347
372
  return scr_dyn_jsval_ops()->invoke(recv->v.jsval.cell, method, args, argc, what);
348
373
  }
349
374
 
375
+ /* Live Web-boundary capsules expose the prototype of their materialized
376
+ * value. Run the ordinary dispatch against the stable snapshot, then
377
+ * commit successful mutations back into the original static value.
378
+ * Mutators such as reverse/sort return their receiver, so translate that
379
+ * snapshot identity back to the externally visible capsule. */
380
+ if (recv->kind == SCR_DYN_TYPED_REF) {
381
+ ScrDyn *materialized = scr_dyn_typed_ref_materialize(recv);
382
+ bool mutates = materialized->kind == SCR_DYN_ARR &&
383
+ dyn_arr_proto_mutates(method);
384
+ ScrDyn *result = scr_dyn_invoke_impl(
385
+ materialized, method, args, argc, what, recv);
386
+ if (mutates && !scr_exc_pending()) scr_dyn_typed_ref_commit(recv);
387
+ if (result == materialized) {
388
+ scr_dyn_release(result);
389
+ result = scr_dyn_retain(recv);
390
+ }
391
+ scr_dyn_release(materialized);
392
+ return result;
393
+ }
394
+
350
395
  /* OBJ: the own member calls (own properties shadow prototypes in JS
351
396
  * too); anything else is Node's is-not-a-function. */
352
397
  if (recv->kind == SCR_DYN_OBJ) {
@@ -556,11 +601,17 @@ ScrDyn *scr_dyn_invoke(ScrDyn *recv, const char *method, ScrDyn *const *args, si
556
601
  if (!dyn_cb_check(args, argc)) return NULL;
557
602
  ScrDyn *cb = args[0];
558
603
  ScrDyn *out = (dyn_name_is(method, "map") || dyn_name_is(method, "filter")) ? scr_dyn_new_arr() : NULL;
559
- /* JS iterates the LIVE array (a push mid-loop is visited); reading
560
- * len fresh each step matches that. */
561
- for (size_t i = 0; i < recv->v.arr.len; i++) {
604
+ /* Array iteration methods snapshot length before the first callback.
605
+ * A shrinking callback can remove a later dense entry; an expanding
606
+ * callback must not make the new tail observable to this pass. Live
607
+ * Web-boundary capsules are the externally visible receiver, so pass
608
+ * that capsule as callback arg 3: mutations through the callback's
609
+ * array argument then commit directly to the original static array. */
610
+ size_t n = len;
611
+ ScrDyn *visible_recv = callback_recv ? callback_recv : recv;
612
+ for (size_t i = 0; i < n && i < recv->v.arr.len; i++) {
562
613
  ScrDyn *item = scr_dyn_retain(recv->v.arr.items[i]);
563
- ScrDyn *r = dyn_call_cb(cb, item, i, recv);
614
+ ScrDyn *r = dyn_call_cb(cb, item, i, visible_recv);
564
615
  if (!r) { scr_dyn_release(item); scr_dyn_release(out); return NULL; }
565
616
  if (dyn_name_is(method, "map")) {
566
617
  scr_dyn_arr_push(out, r); /* ownership moves in */
@@ -597,7 +648,8 @@ ScrDyn *scr_dyn_invoke(ScrDyn *recv, const char *method, ScrDyn *const *args, si
597
648
  size_t n = recv->v.arr.len;
598
649
  for (size_t i = 0; i < n && i < recv->v.arr.len; i++) {
599
650
  ScrDyn *item = scr_dyn_retain(recv->v.arr.items[i]);
600
- ScrDyn *r = dyn_call_cb(cb, item, i, recv);
651
+ ScrDyn *r = dyn_call_cb(
652
+ cb, item, i, callback_recv ? callback_recv : recv);
601
653
  scr_dyn_release(item);
602
654
  if (!r) { scr_dyn_release(out); return NULL; }
603
655
  if (r->kind == SCR_DYN_ARR) {