@hew-lang/sandbox-vm 0.6.2 → 0.6.4

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.
Files changed (40) hide show
  1. package/README.md +43 -4
  2. package/cli/test-runner.mjs +4 -1
  3. package/dist/interpreter/interpreter.d.ts +1 -1
  4. package/dist/interpreter/interpreter.js +1 -1
  5. package/dist/interpreter/parity-runner.js +26 -1
  6. package/dist/interpreter/run-program.d.ts +3 -2
  7. package/dist/interpreter/run-program.js +5 -3
  8. package/dist/interpreter/schema-validator.d.ts +9 -4
  9. package/dist/interpreter/schema-validator.js +15 -49
  10. package/dist/interpreter/types.d.ts +4 -0
  11. package/dist/interpreter/v1/browser-directory.d.ts +107 -0
  12. package/dist/interpreter/v1/browser-directory.js +288 -0
  13. package/dist/interpreter/v1/calendar.d.ts +4 -0
  14. package/dist/interpreter/v1/calendar.js +64 -0
  15. package/dist/interpreter/v1/codecs.js +2 -2
  16. package/dist/interpreter/v1/exec.d.ts +2 -2
  17. package/dist/interpreter/v1/exec.js +439 -183
  18. package/dist/interpreter/v1/instructions.generated.d.ts +1135 -0
  19. package/dist/interpreter/v1/instructions.generated.js +106 -0
  20. package/dist/interpreter/v1/package-graph.d.ts +2 -0
  21. package/dist/interpreter/v1/package-graph.js +729 -0
  22. package/dist/interpreter/v1/package-validator.generated.d.ts +3 -0
  23. package/dist/interpreter/v1/package-validator.generated.js +75846 -0
  24. package/dist/interpreter/v1/package.d.ts +5 -680
  25. package/dist/interpreter/v1/package.js +0 -12
  26. package/dist/interpreter/v1/scheduler.d.ts +5 -1
  27. package/dist/interpreter/v1/scheduler.js +32 -3
  28. package/dist/interpreter/v1/shims.d.ts +250 -7
  29. package/dist/interpreter/v1/shims.js +429 -150
  30. package/dist/interpreter/v1/structural.d.ts +2 -28
  31. package/dist/interpreter/v1/timestamp.d.ts +7 -0
  32. package/dist/interpreter/v1/timestamp.js +54 -0
  33. package/dist/interpreter/v1/validate.d.ts +8 -2
  34. package/dist/interpreter/v1/validate.js +190 -202
  35. package/dist/interpreter/v1/value-operations.d.ts +7 -2
  36. package/dist/interpreter/v1/value-operations.js +13 -6
  37. package/dist/interpreter/values.d.ts +4 -0
  38. package/dist/interpreter/values.js +6 -0
  39. package/dist/interpreter/worker.js +4 -3
  40. package/package.json +4 -4
@@ -1,12 +1,8 @@
1
+ import { DIRECTORY_OPERATIONS, } from "./browser-directory.js";
2
+ import { executeCalendar } from "./calendar.js";
1
3
  import { charProperty, charCase } from "../unicode.js";
2
- /// The VM's runtime-family and extern shim table.
3
- ///
4
- /// This table is the runtime-family admission authority: a package may name a
5
- /// runtime family or an extern symbol exactly when there is a shim here for it.
6
- /// A family or symbol with no entry is rejected at load, so there is no second
7
- /// reject list to keep in step with this one. `FileRead` is refused by its
8
- /// absence, and a `NativeIo` suspension by an operation missing from
9
- /// [`SUPPORTED_NATIVE_IO`].
4
+ /// Runtime implementations and their host execution registration. Admission and
5
+ /// execution consume the same ordinary, resumable or refused disposition.
10
6
  import { UNIT, cloneValue, compareUtf8, stringValue, renderStdout, } from "../values.js";
11
7
  import { seededMt } from "./mt19937.js";
12
8
  /// A language-visible fault raised inside a shim. The executor routes it to the
@@ -19,127 +15,252 @@ export class ShimFault extends Error {
19
15
  this.name = "ShimFault";
20
16
  }
21
17
  }
22
- /// Resolve a declared runtime family to its shim, or `undefined` when the VM
23
- /// has none. Both the load-time validator and the executor go through here, so
24
- /// admission and execution can never disagree about what is implemented.
25
- export function resolveRuntimeShim(entry) {
18
+ function ordinary(shim) {
19
+ return { kind: "ordinary", shim };
20
+ }
21
+ function refused(capability, native = false) {
22
+ return {
23
+ kind: "refused",
24
+ category: native ? "native_only" : "not_implemented",
25
+ capability,
26
+ };
27
+ }
28
+ function resumable(continuation) {
29
+ return { kind: "resumable", ...continuation };
30
+ }
31
+ /// A registered algorithm may still require a host-supplied Wasm bridge.
32
+ export function registrationRefusal(registration, bridges) {
33
+ if (registration.kind === "refused")
34
+ return registration;
35
+ if (registration.kind === "directory" &&
36
+ registration.operation.action === "root" &&
37
+ !bridges.directoryRoots?.[registration.operation.access])
38
+ return {
39
+ ...refused(`directoryRoots.${registration.operation.access}`),
40
+ message: `This operation requires a host-supplied OPFS ${registration.operation.access} directory handle.`,
41
+ };
42
+ return "bridge" in registration &&
43
+ registration.bridge &&
44
+ typeof bridges[registration.bridge] !== "function"
45
+ ? refused(registration.bridge)
46
+ : null;
47
+ }
48
+ export const CODEC_REGISTRATION = {
49
+ kind: "resumable",
50
+ bridge: "codecBridge",
51
+ };
52
+ /// Each typed runtime identity has exactly one host disposition. An added Rust
53
+ /// family or nested operation must acquire a disposition before TypeScript builds.
54
+ export function resolveRuntime(entry) {
26
55
  switch (entry.family) {
27
56
  case "SupervisorPool":
28
- return ["Len", "Member", "Get"].includes(String(entry.detail))
29
- ? () => {
30
- throw new Error("SupervisorPool requires its resumable executor");
31
- }
32
- : undefined;
33
- case "ActorCaller":
34
- case "ActorRefusalLog":
35
- case "StructuralFormat":
36
- return () => {
37
- throw new Error("StructuralFormat requires its resumable executor");
38
- };
39
- case "FileRead":
40
- return entry.detail === "LastError" ? () => str("") : undefined;
57
+ return resumable({ handler: "supervisor_pool", operation: entry.detail });
41
58
  case "Print":
42
- return printShim(entry.detail);
43
- case "RcNew":
44
- case "RcClone":
45
- case "RcDowngrade":
46
- case "WeakCloneRc":
47
- case "WeakUpgradeRc":
48
- case "RcGet":
49
- case "RcIsUnique":
50
- case "RcSet":
51
- case "RcStrongCount":
52
- case "RcWeakCount":
53
- return () => {
54
- throw new Error("shared operation requires its resumable executor");
55
- };
56
- case "Vector":
57
- return ["Contains", "Set", "Clear"].includes(String(entry.detail))
58
- ? () => {
59
- throw new Error("vector Contains requires its selected Eq executor");
59
+ return ordinary(printShim(entry.detail));
60
+ case "FileRead":
61
+ switch (entry.detail) {
62
+ case "HasError":
63
+ case "LastErrorKind":
64
+ case "LastErrno":
65
+ case "LastError": {
66
+ const operation = entry.detail;
67
+ return ordinary((host) => host.fileError(operation));
60
68
  }
61
- : VECTOR_SHIMS[detailName(entry.detail)];
69
+ default:
70
+ return refused(`FileRead::${entry.detail}`, true);
71
+ }
72
+ case "AsyncIo":
73
+ case "Tcp":
74
+ return refused(`${entry.family}::${entry.detail}`, true);
75
+ case "Semaphore":
76
+ case "Service":
77
+ case "VecContainsScalar":
78
+ case "VecGet":
79
+ case "VecSliceRange":
80
+ return refused(`${entry.family}::${entry.detail}`);
81
+ case "Encoding":
82
+ case "VecScalar":
83
+ return refused(entry.family);
84
+ case "Vector":
85
+ switch (entry.detail) {
86
+ case "Contains":
87
+ case "Set":
88
+ case "Clear":
89
+ return resumable({
90
+ handler: "collection",
91
+ family: "Vector",
92
+ operation: entry.detail,
93
+ });
94
+ case "Pop":
95
+ case "GetBorrow":
96
+ case "TakeFirst":
97
+ case "TakeAll":
98
+ case "Append":
99
+ return refused(`Vector::${entry.detail}`);
100
+ default:
101
+ return ordinary(VECTOR_SHIMS[entry.detail]);
102
+ }
62
103
  case "Array":
63
- return entry.detail === "Set"
64
- ? () => {
65
- throw new Error("array mutation requires its resumable executor");
104
+ switch (entry.detail) {
105
+ case "Set":
106
+ return resumable({
107
+ handler: "collection",
108
+ family: "Vector",
109
+ operation: entry.detail,
110
+ });
111
+ case "Len":
112
+ case "Index":
113
+ case "IndexBorrow":
114
+ return ordinary(VECTOR_SHIMS[entry.detail]);
115
+ default: {
116
+ const exhaustive = entry;
117
+ throw new Error(`unknown array operation ${String(exhaustive)}`);
66
118
  }
67
- : entry.detail === "IndexBorrow"
68
- ? (_host, args) => sequenceElement(args)
69
- : ["Len", "Index"].includes(String(entry.detail))
70
- ? VECTOR_SHIMS[detailName(entry.detail)]
71
- : undefined;
119
+ }
72
120
  case "Map":
121
+ return resumable({
122
+ handler: "collection",
123
+ family: "Map",
124
+ operation: entry.detail,
125
+ });
73
126
  case "Set":
74
- return [
75
- "New",
76
- "Len",
77
- "Index",
78
- "Get",
79
- "GetBorrow",
80
- "ContainsKey",
81
- "Contains",
82
- "Insert",
83
- "Remove",
84
- "Clear",
85
- "Keys",
86
- "Values",
87
- "Entries",
88
- "Elements",
89
- ].includes(detailName(entry.detail))
90
- ? () => {
91
- throw new Error("collection operation requires its resumable executor");
92
- }
93
- : undefined;
127
+ return resumable({
128
+ handler: "collection",
129
+ family: "Set",
130
+ operation: entry.detail,
131
+ });
94
132
  case "MathIntrinsic":
95
- return MATH_SHIMS[detailName(entry.detail)];
133
+ return ordinary(MATH_SHIMS[entry.detail]);
96
134
  case "FloatMethod":
97
- return FLOAT_METHOD_SHIMS[detailName(entry.detail)];
135
+ return ordinary(FLOAT_METHOD_SHIMS[entry.detail]);
98
136
  case "IntMethod":
99
- return intMethodShim(entry.detail);
137
+ return ordinary(intMethodShim(entry.detail));
100
138
  case "IntArith":
101
- return intArithShim(entry.detail);
102
- default:
103
- return UNIT_FAMILY_SHIMS[entry.family];
139
+ return ordinary(intArithShim(entry.detail));
140
+ default: {
141
+ const registration = UNIT_FAMILIES[entry.family];
142
+ return typeof registration === "function"
143
+ ? ordinary(registration)
144
+ : registration;
145
+ }
146
+ }
147
+ }
148
+ export function resolveExtern(entry) {
149
+ if (Object.hasOwn(DIRECTORY_OPERATIONS, entry.symbol))
150
+ return {
151
+ kind: "directory",
152
+ operation: DIRECTORY_OPERATIONS[entry.symbol],
153
+ };
154
+ const registration = Object.hasOwn(EXTERN_SHIMS, entry.symbol)
155
+ ? EXTERN_SHIMS[entry.symbol]
156
+ : undefined;
157
+ if (typeof registration === "function")
158
+ return ordinary(registration);
159
+ return (registration ?? {
160
+ ...refused(entry.symbol, entry.native_capability != null),
161
+ description: entry.native_capability ?? undefined,
162
+ });
163
+ }
164
+ const SUSPENSION_ROUTES = {
165
+ GeneratorNext: "GeneratorNext",
166
+ Yield: "Yield",
167
+ Sleep: "Sleep",
168
+ Safepoint: "Safepoint",
169
+ Ask: "Ask",
170
+ Await: "Await",
171
+ Join: "Join",
172
+ Select: "Select",
173
+ StreamSend: "StreamSend",
174
+ StreamNext: "StreamNext",
175
+ NativeIo: "NativeIo",
176
+ Read: refused("Read", true),
177
+ Accept: refused("Accept", true),
178
+ SleepUntil: refused("SleepUntil"),
179
+ ServiceAcquire: refused("ServiceAcquire"),
180
+ SemaphoreAcquire: refused("SemaphoreAcquire"),
181
+ ActorSend: refused("ActorSend"),
182
+ RestartWait: refused("RestartWait"),
183
+ CallClosure: refused("CallClosure"),
184
+ Timeout: refused("Timeout"),
185
+ ScopeDeadline: refused("ScopeDeadline"),
186
+ Offload: refused("Offload"),
187
+ };
188
+ export function suspensionRefusal(kind) {
189
+ const route = SUSPENSION_ROUTES[kind];
190
+ return typeof route === "string" ? null : route;
191
+ }
192
+ function executableSuspension(term) {
193
+ return suspensionRefusal(term.kind) === null;
194
+ }
195
+ const NATIVE_IO_ROUTES = {
196
+ StdinReadLine: "StdinReadLine",
197
+ SinkFinish: "SinkFinish",
198
+ TcpRead: refused("NativeIo::TcpRead", true),
199
+ TcpWrite: refused("NativeIo::TcpWrite", true),
200
+ TcpAccept: refused("NativeIo::TcpAccept", true),
201
+ TcpConnect: refused("NativeIo::TcpConnect", true),
202
+ TcpConnectTimeout: refused("NativeIo::TcpConnectTimeout", true),
203
+ TlsConnect: refused("NativeIo::TlsConnect", true),
204
+ TlsRead: refused("NativeIo::TlsRead", true),
205
+ TlsWrite: refused("NativeIo::TlsWrite", true),
206
+ FileRead: "FileRead",
207
+ FileWrite: "FileWrite",
208
+ };
209
+ function nativeIoRefusal(operation) {
210
+ const route = NATIVE_IO_ROUTES[operation];
211
+ return typeof route === "string" ? null : route;
212
+ }
213
+ function executableNativeIo(term) {
214
+ return nativeIoRefusal(term.detail.operation) === null;
215
+ }
216
+ /// The executor handles exactly the resumable identities registered above.
217
+ export function resolveSuspension(term) {
218
+ if (!executableSuspension(term))
219
+ return suspensionRefusal(term.kind);
220
+ if (term.kind === "NativeIo") {
221
+ if (!executableNativeIo(term))
222
+ return nativeIoRefusal(term.detail.operation);
223
+ return { kind: "resumable", term };
104
224
  }
225
+ return { kind: "resumable", term };
105
226
  }
106
- export function resolveExternShim(symbol) {
107
- return EXTERN_SHIMS[symbol];
108
- }
109
- /// The suspend kinds a sequential package may carry. `NativeIo` is admitted
110
- /// per operation through [`SUPPORTED_NATIVE_IO`] instead.
111
- export const SUPPORTED_SUSPEND_KINDS = new Set([
112
- "GeneratorNext",
113
- "Yield",
114
- "Sleep",
115
- "Safepoint",
116
- "Ask",
117
- "Await",
118
- "Join",
119
- "Select",
120
- "StreamSend",
121
- "StreamNext",
122
- ]);
123
- /// The VM serves replay standard input and in-memory sink closure.
124
- export const SUPPORTED_NATIVE_IO = new Set([
125
- "StdinReadLine",
126
- "SinkFinish",
127
- ]);
128
227
  // ── families ────────────────────────────────────────────────────────────────
129
228
  /// `Print { kind, newline }`. The rendering follows the value's own
130
229
  /// representation: casts normalize an integer into its target range, so the
131
230
  /// declared `kind` never changes how a value prints.
132
231
  function printShim(detail) {
133
- if (typeof detail !== "object" || detail === null) {
134
- return undefined;
135
- }
136
- const newline = detail.newline === true;
232
+ const newline = detail.newline;
137
233
  return (host, args) => {
138
234
  host.writeStdout(newline ? `${renderStdout(arg(args, 0))}\n` : renderStdout(arg(args, 0)));
139
235
  return UNIT;
140
236
  };
141
237
  }
142
- const UNIT_FAMILY_SHIMS = {
238
+ const UNIT_FAMILIES = {
239
+ TimestampNow: (host, _args, _variant, aggregate) => {
240
+ const millis = host.unixTimeMillis();
241
+ if (!Number.isFinite(millis))
242
+ throw new ShimFault("integer_overflow", "host wall clock is not finite");
243
+ const seconds = Math.floor(millis / 1000);
244
+ let nanos = Math.round((millis - seconds * 1000) * 1_000_000);
245
+ let whole = BigInt(seconds);
246
+ if (nanos === 1_000_000_000) {
247
+ whole += 1n;
248
+ nanos = 0;
249
+ }
250
+ if (whole < -(1n << 63n) ||
251
+ whole >= 1n << 63n ||
252
+ nanos < 0 ||
253
+ nanos >= 1_000_000_000)
254
+ throw new ShimFault("integer_overflow", "host wall clock exceeds timestamp range");
255
+ if (!aggregate || aggregate.builtin !== "Timestamp")
256
+ throw new TypeError("timestamp clock lacks its aggregate descriptor");
257
+ return {
258
+ kind: "record",
259
+ typeId: aggregate.name,
260
+ shape: aggregate.id,
261
+ fields: [int(whole), int(BigInt(nanos))],
262
+ };
263
+ },
143
264
  StderrWrite: (host, args) => {
144
265
  host.writeStderr(text(args, 0));
145
266
  return UNIT;
@@ -156,14 +277,8 @@ const UNIT_FAMILY_SHIMS = {
156
277
  StreamFromGenerator: (host, args) => host.generatorStream(arg(args, 0)),
157
278
  SinkFromEncoder: (host, args) => host.encoderSink(arg(args, 0), arg(args, 1)),
158
279
  SinkClone: (host, args) => host.cloneSink(arg(args, 0)),
159
- SinkClose: (host, args) => {
160
- host.closePipe(arg(args, 0));
161
- return UNIT;
162
- },
163
- StreamClose: (host, args) => {
164
- host.closePipe(arg(args, 0));
165
- return UNIT;
166
- },
280
+ SinkClose: resumable({ handler: "close" }),
281
+ StreamClose: resumable({ handler: "close" }),
167
282
  StringConcat: (_host, args) => str(`${text(args, 0)}${text(args, 1)}`),
168
283
  StringClone: (_host, args) => cloneValue(arg(args, 0)),
169
284
  StringEquals: (_host, args) => bool(text(args, 0) === text(args, 1)),
@@ -291,9 +406,7 @@ const UNIT_FAMILY_SHIMS = {
291
406
  CharFromI64: checkedChar,
292
407
  CharFromU64: checkedChar,
293
408
  CharToString: (_host, args) => str(renderStdout(arg(args, 0))),
294
- BytesDecodeUtf8: () => {
295
- throw new Error("UTF-8 decode requires its checked result carrier");
296
- },
409
+ BytesDecodeUtf8: resumable({ handler: "utf8_decode" }),
297
410
  // TextDecoder replaces each maximal invalid subsequence with U+FFFD, as
298
411
  // native lossy decoding does.
299
412
  BytesDecodeUtf8Lossy: (_host, args) => str(decodeUtf8(arg(args, 0))),
@@ -388,6 +501,164 @@ const UNIT_FAMILY_SHIMS = {
388
501
  ],
389
502
  };
390
503
  },
504
+ ActorDemonitor: refused("ActorDemonitor"),
505
+ ActorLink: refused("ActorLink"),
506
+ ActorMonitor: refused("ActorMonitor"),
507
+ ActorCaller: resumable({ handler: "actor_caller" }),
508
+ ActorRefusalLog: resumable({ handler: "actor_refusal_log" }),
509
+ ActorUnlink: refused("ActorUnlink"),
510
+ AutoMutexAlloc: refused("AutoMutexAlloc"),
511
+ AutoMutexFree: refused("AutoMutexFree"),
512
+ AutoMutexLock: refused("AutoMutexLock"),
513
+ AutoMutexUnlock: refused("AutoMutexUnlock"),
514
+ DequePopFront: refused("DequePopFront"),
515
+ DequePopBack: refused("DequePopBack"),
516
+ CancelTokenIsRequested: refused("CancelTokenIsRequested"),
517
+ CancelTokenRelease: refused("CancelTokenRelease"),
518
+ CancelTokenRetain: refused("CancelTokenRetain"),
519
+ ActorRequestRelease: refused("ActorRequestRelease"),
520
+ ActorCallFree: refused("ActorCallFree"),
521
+ ActorRequestTake: refused("ActorRequestTake"),
522
+ DurationAbs: refused("DurationAbs"),
523
+ DurationHours: refused("DurationHours"),
524
+ DurationIsZero: refused("DurationIsZero"),
525
+ DurationMicros: refused("DurationMicros"),
526
+ DurationMillis: refused("DurationMillis"),
527
+ DurationMins: refused("DurationMins"),
528
+ DurationNanos: refused("DurationNanos"),
529
+ DurationSecs: refused("DurationSecs"),
530
+ DynBoxAlloc: refused("DynBoxAlloc"),
531
+ DynBoxFree: refused("DynBoxFree"),
532
+ HashMapContainsKeyLayout: refused("HashMapContainsKeyLayout"),
533
+ HashMapClearLayout: refused("HashMapClearLayout"),
534
+ HashMapCloneLayout: refused("HashMapCloneLayout"),
535
+ HashMapEntriesLayout: refused("HashMapEntriesLayout"),
536
+ HashMapFreeLayout: refused("HashMapFreeLayout"),
537
+ HashMapGetLayout: refused("HashMapGetLayout"),
538
+ HashMapInsertLayout: refused("HashMapInsertLayout"),
539
+ HashMapKeysLayout: refused("HashMapKeysLayout"),
540
+ HashMapLenLayout: refused("HashMapLenLayout"),
541
+ HashMapNew: refused("HashMapNew"),
542
+ HashMapNewWithLayout: refused("HashMapNewWithLayout"),
543
+ HashMapRemoveLayout: refused("HashMapRemoveLayout"),
544
+ HashMapValuesLayout: refused("HashMapValuesLayout"),
545
+ HashSetContainsLayout: refused("HashSetContainsLayout"),
546
+ HashSetClearLayout: refused("HashSetClearLayout"),
547
+ HashSetCloneLayout: refused("HashSetCloneLayout"),
548
+ HashSetFreeLayout: refused("HashSetFreeLayout"),
549
+ HashSetInsertLayout: refused("HashSetInsertLayout"),
550
+ HashSetIsEmptyLayout: refused("HashSetIsEmptyLayout"),
551
+ HashSetLenLayout: refused("HashSetLenLayout"),
552
+ HashSetNew: refused("HashSetNew"),
553
+ HashSetNewWithLayout: refused("HashSetNewWithLayout"),
554
+ HashSetRemoveLayout: refused("HashSetRemoveLayout"),
555
+ HashSetToVecLayout: refused("HashSetToVecLayout"),
556
+ InstantDurationSince: refused("InstantDurationSince"),
557
+ InstantElapsed: refused("InstantElapsed"),
558
+ InstantNow: refused("InstantNow"),
559
+ NodeConnect: refused("NodeConnect"),
560
+ NodeId: refused("NodeId"),
561
+ NodeIdDisplay: refused("NodeIdDisplay"),
562
+ LocationNodeId: refused("LocationNodeId"),
563
+ LocationIncarnation: refused("LocationIncarnation"),
564
+ LocationDisplay: refused("LocationDisplay"),
565
+ NodeIdentityKey: refused("NodeIdentityKey"),
566
+ NodeLoadKeys: refused("NodeLoadKeys"),
567
+ NodeLookup: refused("NodeLookup"),
568
+ NodeRegister: refused("NodeRegister"),
569
+ NodeSetTransport: refused("NodeSetTransport"),
570
+ NodeShutdown: refused("NodeShutdown"),
571
+ NodeStart: refused("NodeStart"),
572
+ MetricCounterRegister: refused("MetricCounterRegister"),
573
+ MetricCounterInc: refused("MetricCounterInc"),
574
+ MetricCounterAdd: refused("MetricCounterAdd"),
575
+ MetricGaugeRegister: refused("MetricGaugeRegister"),
576
+ MetricGaugeSet: refused("MetricGaugeSet"),
577
+ MetricGaugeInc: refused("MetricGaugeInc"),
578
+ MetricGaugeDec: refused("MetricGaugeDec"),
579
+ MetricGaugeAdd: refused("MetricGaugeAdd"),
580
+ MetricHistogramRegister: refused("MetricHistogramRegister"),
581
+ MetricHistogramRegisterSimple: refused("MetricHistogramRegisterSimple"),
582
+ MetricHistogramRecord: refused("MetricHistogramRecord"),
583
+ MetricVecRegister: refused("MetricVecRegister"),
584
+ MetricVecWith: refused("MetricVecWith"),
585
+ ObserveReadU64: refused("ObserveReadU64"),
586
+ ObserveScrape: refused("ObserveScrape"),
587
+ ObserveSeries: refused("ObserveSeries"),
588
+ ObserveBarrier: refused("ObserveBarrier"),
589
+ RcClone: resumable({ handler: "shared", operation: "RcClone" }),
590
+ RcDowngrade: resumable({ handler: "shared", operation: "RcDowngrade" }),
591
+ RcDrop: refused("RcDrop"),
592
+ RcGet: resumable({ handler: "shared", operation: "RcGet" }),
593
+ RcIsUnique: resumable({ handler: "shared", operation: "RcIsUnique" }),
594
+ RcNew: resumable({ handler: "shared", operation: "RcNew" }),
595
+ RcSet: resumable({ handler: "shared", operation: "RcSet" }),
596
+ RcStrongCount: resumable({ handler: "shared", operation: "RcStrongCount" }),
597
+ RcWeakCount: resumable({ handler: "shared", operation: "RcWeakCount" }),
598
+ WeakCloneRc: resumable({ handler: "shared", operation: "WeakCloneRc" }),
599
+ WeakDropRc: refused("WeakDropRc"),
600
+ WeakUpgradeRc: resumable({ handler: "shared", operation: "WeakUpgradeRc" }),
601
+ RegexCapture: refused("RegexCapture"),
602
+ RegexCompile: refused("RegexCompile"),
603
+ RegexFreeCapture: refused("RegexFreeCapture"),
604
+ RegexHandle: refused("RegexHandle"),
605
+ RegexMatch: refused("RegexMatch"),
606
+ ReplyChannelCancel: refused("ReplyChannelCancel"),
607
+ ReplyChannelFree: refused("ReplyChannelFree"),
608
+ ReplyChannelNew: refused("ReplyChannelNew"),
609
+ ReplyPayloadFree: refused("ReplyPayloadFree"),
610
+ ReplyWait: refused("ReplyWait"),
611
+ SelectFirst: refused("SelectFirst"),
612
+ StreamChunks: refused("StreamChunks"),
613
+ StreamForward: refused("StreamForward"),
614
+ StreamLines: refused("StreamLines"),
615
+ StreamNextLayout: refused("StreamNextLayout"),
616
+ StreamSendLayout: refused("StreamSendLayout"),
617
+ StreamTake: refused("StreamTake"),
618
+ StreamTryNextLayout: refused("StreamTryNextLayout"),
619
+ StreamTrySendLayout: refused("StreamTrySendLayout"),
620
+ StructuralFormat: resumable({ handler: "structural_format" }),
621
+ StringLines: refused("StringLines"),
622
+ ProcessExit: refused("ProcessExit"),
623
+ SupervisorDirectId: refused("SupervisorDirectId"),
624
+ SupervisorChildGet: refused("SupervisorChildGet"),
625
+ LocalPidSupervisorChildGet: refused("LocalPidSupervisorChildGet"),
626
+ SupervisorNestedGet: refused("SupervisorNestedGet"),
627
+ SupervisorPoolChildGet: refused("SupervisorPoolChildGet"),
628
+ LocalPidSupervisorPoolChildRefGet: refused("LocalPidSupervisorPoolChildRefGet"),
629
+ SupervisorPoolLen: refused("SupervisorPoolLen"),
630
+ SupervisorStop: refused("SupervisorStop"),
631
+ TlsAttachLocal: refused("TlsAttachLocal"),
632
+ WebSocketAttachLocal: refused("WebSocketAttachLocal"),
633
+ TaskFree: refused("TaskFree"),
634
+ GeneratorFree: refused("GeneratorFree"),
635
+ VecAppend: refused("VecAppend"),
636
+ VecClear: refused("VecClear"),
637
+ VecClone: refused("VecClone"),
638
+ VecCloneLayout: refused("VecCloneLayout"),
639
+ VecCloneOwned: refused("VecCloneOwned"),
640
+ VecContainsLayout: refused("VecContainsLayout"),
641
+ VecTakeAll: refused("VecTakeAll"),
642
+ VecContainsOwned: refused("VecContainsOwned"),
643
+ VecIsEmpty: refused("VecIsEmpty"),
644
+ VecJoinStr: refused("VecJoinStr"),
645
+ VecLen: refused("VecLen"),
646
+ VecNew: refused("VecNew"),
647
+ VecPopBool: refused("VecPopBool"),
648
+ VecPopLayout: refused("VecPopLayout"),
649
+ VecPopOwned: refused("VecPopOwned"),
650
+ VecPushBool: refused("VecPushBool"),
651
+ VecPushLayout: refused("VecPushLayout"),
652
+ VecPushOwned: refused("VecPushOwned"),
653
+ VecPushOwnedMove: refused("VecPushOwnedMove"),
654
+ VecRemoveAtBool: refused("VecRemoveAtBool"),
655
+ VecRemoveAtLayout: refused("VecRemoveAtLayout"),
656
+ VecRemoveAtOwned: refused("VecRemoveAtOwned"),
657
+ VecSetBool: refused("VecSetBool"),
658
+ VecSetLayout: refused("VecSetLayout"),
659
+ VecSetOwned: refused("VecSetOwned"),
660
+ VecSetOwnedMove: refused("VecSetOwnedMove"),
661
+ VtableDispatchPanicOnOob: refused("VtableDispatchPanicOnOob"),
391
662
  };
392
663
  const VECTOR_SHIMS = {
393
664
  New: () => ({ kind: "vector", elementType: "", items: [] }),
@@ -596,8 +867,6 @@ const FLOAT_METHOD_SHIMS = {
596
867
  },
597
868
  IsSignNegative: (_host, args) => bool(toBits(real(args, 0)) >> 63n === 1n),
598
869
  };
599
- /// The receiver width an `IntMethod`/`IntArith` detail names. The VM is a
600
- /// 64-bit target, so the pointer-sized widths are 64 bits wide.
601
870
  const INT_WIDTHS = {
602
871
  I8: { bits: 8, signed: true },
603
872
  I16: { bits: 16, signed: true },
@@ -610,15 +879,6 @@ const INT_WIDTHS = {
610
879
  U64: { bits: 64, signed: false },
611
880
  Usize: { bits: 64, signed: false },
612
881
  };
613
- /// `[op, width]`, as `RuntimeCallFamily` serializes a two-field variant.
614
- function intDetail(detail) {
615
- if (!Array.isArray(detail) || detail.length !== 2) {
616
- return undefined;
617
- }
618
- const [op, width] = detail;
619
- const shape = typeof width === "string" ? INT_WIDTHS[width] : undefined;
620
- return typeof op === "string" && shape ? [op, shape] : undefined;
621
- }
622
882
  function wrapTo(width, value) {
623
883
  return width.signed
624
884
  ? BigInt.asIntN(width.bits, value)
@@ -642,11 +902,8 @@ function popcount(value) {
642
902
  /// works on the receiver's unsigned bit pattern and the rotate amount is taken
643
903
  /// modulo the width.
644
904
  function intMethodShim(detail) {
645
- const parsed = intDetail(detail);
646
- if (!parsed) {
647
- return undefined;
648
- }
649
- const [op, width] = parsed;
905
+ const [op, name] = detail;
906
+ const width = INT_WIDTHS[name];
650
907
  const bits = BigInt(width.bits);
651
908
  const unsigned = (args) => BigInt.asUintN(width.bits, integer(args, 0));
652
909
  const result = (pattern) => int(wrapTo(width, pattern));
@@ -703,30 +960,34 @@ function intMethodShim(detail) {
703
960
  return (_host, args) => rotate(args, true);
704
961
  case "RotateRight":
705
962
  return (_host, args) => rotate(args, false);
706
- default:
707
- return undefined;
963
+ default: {
964
+ const exhaustive = op;
965
+ throw new Error(`unknown integer operation ${String(exhaustive)}`);
966
+ }
708
967
  }
709
968
  }
710
969
  /// Non-trapping integer arithmetic at the receiver's width: wrapping keeps
711
970
  /// the low bits, saturating clamps to the width's bounds and checked answers
712
971
  /// `None` where native's overflow flag is set.
713
972
  function intArithShim(detail) {
714
- const parsed = intDetail(detail);
715
- if (!parsed) {
716
- return undefined;
717
- }
718
- const [kind, width] = parsed;
973
+ const [kind, name] = detail;
974
+ const width = INT_WIDTHS[name];
719
975
  const [min, max] = intBounds(width);
976
+ const add = (x, y) => x + y;
977
+ const sub = (x, y) => x - y;
978
+ const mul = (x, y) => x * y;
720
979
  const operations = {
721
- Add: (x, y) => x + y,
722
- Sub: (x, y) => x - y,
723
- Mul: (x, y) => x * y,
980
+ WrappingAdd: ["Wrapping", add],
981
+ WrappingSub: ["Wrapping", sub],
982
+ WrappingMul: ["Wrapping", mul],
983
+ SaturatingAdd: ["Saturating", add],
984
+ SaturatingSub: ["Saturating", sub],
985
+ SaturatingMul: ["Saturating", mul],
986
+ CheckedAdd: ["Checked", add],
987
+ CheckedSub: ["Checked", sub],
988
+ CheckedMul: ["Checked", mul],
724
989
  };
725
- const mode = ["Wrapping", "Saturating", "Checked"].find((prefix) => kind.startsWith(prefix));
726
- const apply = mode ? operations[kind.slice(mode.length)] : undefined;
727
- if (!mode || !apply) {
728
- return undefined;
729
- }
990
+ const [mode, apply] = operations[kind];
730
991
  const exact = (args) => apply(wrapTo(width, integer(args, 0)), wrapTo(width, integer(args, 1)));
731
992
  switch (mode) {
732
993
  case "Wrapping":
@@ -766,6 +1027,27 @@ function bigMax(left, right) {
766
1027
  }
767
1028
  // ── externs ─────────────────────────────────────────────────────────────────
768
1029
  const EXTERN_SHIMS = {
1030
+ hew_path_separator: () => str("/"),
1031
+ hew_calendar_format: {
1032
+ kind: "ordinary",
1033
+ bridge: "calendarBridge",
1034
+ shim: (host, args, _variant, shape) => executeCalendar(host.calendarBridge, "hew_calendar_format", args, shape),
1035
+ },
1036
+ hew_calendar_parse: {
1037
+ kind: "ordinary",
1038
+ bridge: "calendarBridge",
1039
+ shim: (host, args, _variant, shape) => executeCalendar(host.calendarBridge, "hew_calendar_parse", args, shape),
1040
+ },
1041
+ hew_calendar_components: {
1042
+ kind: "ordinary",
1043
+ bridge: "calendarBridge",
1044
+ shim: (host, args, _variant, shape) => executeCalendar(host.calendarBridge, "hew_calendar_components", args, shape),
1045
+ },
1046
+ hew_calendar_from_parts: {
1047
+ kind: "ordinary",
1048
+ bridge: "calendarBridge",
1049
+ shim: (host, args, _variant, shape) => executeCalendar(host.calendarBridge, "hew_calendar_from_parts", args, shape),
1050
+ },
769
1051
  hew_args_count: (host) => int(BigInt(host.argv.length)),
770
1052
  // A native null managed string is canonical empty. Each result owns fresh
771
1053
  // string storage; releasing it cannot change the host's supplied arguments.
@@ -904,9 +1186,6 @@ function pattern(host, value) {
904
1186
  return value.kind === "string" ? value.value : renderStdout(value);
905
1187
  }
906
1188
  // ── operand helpers ─────────────────────────────────────────────────────────
907
- function detailName(detail) {
908
- return typeof detail === "string" ? detail : "";
909
- }
910
1189
  function arg(args, at) {
911
1190
  return args[at] ?? UNIT;
912
1191
  }