@hew-lang/sandbox-vm 0.6.2 → 0.6.3

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 +1 -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 +75902 -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 +430 -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,165 @@ 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
+ NodeAllowPeer: refused("NodeAllowPeer"),
560
+ NodeConnect: refused("NodeConnect"),
561
+ NodeId: refused("NodeId"),
562
+ NodeIdDisplay: refused("NodeIdDisplay"),
563
+ LocationNodeId: refused("LocationNodeId"),
564
+ LocationIncarnation: refused("LocationIncarnation"),
565
+ LocationDisplay: refused("LocationDisplay"),
566
+ NodeIdentityKey: refused("NodeIdentityKey"),
567
+ NodeLoadKeys: refused("NodeLoadKeys"),
568
+ NodeLookup: refused("NodeLookup"),
569
+ NodeRegister: refused("NodeRegister"),
570
+ NodeSetTransport: refused("NodeSetTransport"),
571
+ NodeShutdown: refused("NodeShutdown"),
572
+ NodeStart: refused("NodeStart"),
573
+ MetricCounterRegister: refused("MetricCounterRegister"),
574
+ MetricCounterInc: refused("MetricCounterInc"),
575
+ MetricCounterAdd: refused("MetricCounterAdd"),
576
+ MetricGaugeRegister: refused("MetricGaugeRegister"),
577
+ MetricGaugeSet: refused("MetricGaugeSet"),
578
+ MetricGaugeInc: refused("MetricGaugeInc"),
579
+ MetricGaugeDec: refused("MetricGaugeDec"),
580
+ MetricGaugeAdd: refused("MetricGaugeAdd"),
581
+ MetricHistogramRegister: refused("MetricHistogramRegister"),
582
+ MetricHistogramRegisterSimple: refused("MetricHistogramRegisterSimple"),
583
+ MetricHistogramRecord: refused("MetricHistogramRecord"),
584
+ MetricVecRegister: refused("MetricVecRegister"),
585
+ MetricVecWith: refused("MetricVecWith"),
586
+ ObserveReadU64: refused("ObserveReadU64"),
587
+ ObserveScrape: refused("ObserveScrape"),
588
+ ObserveSeries: refused("ObserveSeries"),
589
+ ObserveBarrier: refused("ObserveBarrier"),
590
+ RcClone: resumable({ handler: "shared", operation: "RcClone" }),
591
+ RcDowngrade: resumable({ handler: "shared", operation: "RcDowngrade" }),
592
+ RcDrop: refused("RcDrop"),
593
+ RcGet: resumable({ handler: "shared", operation: "RcGet" }),
594
+ RcIsUnique: resumable({ handler: "shared", operation: "RcIsUnique" }),
595
+ RcNew: resumable({ handler: "shared", operation: "RcNew" }),
596
+ RcSet: resumable({ handler: "shared", operation: "RcSet" }),
597
+ RcStrongCount: resumable({ handler: "shared", operation: "RcStrongCount" }),
598
+ RcWeakCount: resumable({ handler: "shared", operation: "RcWeakCount" }),
599
+ WeakCloneRc: resumable({ handler: "shared", operation: "WeakCloneRc" }),
600
+ WeakDropRc: refused("WeakDropRc"),
601
+ WeakUpgradeRc: resumable({ handler: "shared", operation: "WeakUpgradeRc" }),
602
+ RegexCapture: refused("RegexCapture"),
603
+ RegexCompile: refused("RegexCompile"),
604
+ RegexFreeCapture: refused("RegexFreeCapture"),
605
+ RegexHandle: refused("RegexHandle"),
606
+ RegexMatch: refused("RegexMatch"),
607
+ ReplyChannelCancel: refused("ReplyChannelCancel"),
608
+ ReplyChannelFree: refused("ReplyChannelFree"),
609
+ ReplyChannelNew: refused("ReplyChannelNew"),
610
+ ReplyPayloadFree: refused("ReplyPayloadFree"),
611
+ ReplyWait: refused("ReplyWait"),
612
+ SelectFirst: refused("SelectFirst"),
613
+ StreamChunks: refused("StreamChunks"),
614
+ StreamForward: refused("StreamForward"),
615
+ StreamLines: refused("StreamLines"),
616
+ StreamNextLayout: refused("StreamNextLayout"),
617
+ StreamSendLayout: refused("StreamSendLayout"),
618
+ StreamTake: refused("StreamTake"),
619
+ StreamTryNextLayout: refused("StreamTryNextLayout"),
620
+ StreamTrySendLayout: refused("StreamTrySendLayout"),
621
+ StructuralFormat: resumable({ handler: "structural_format" }),
622
+ StringLines: refused("StringLines"),
623
+ ProcessExit: refused("ProcessExit"),
624
+ SupervisorDirectId: refused("SupervisorDirectId"),
625
+ SupervisorChildGet: refused("SupervisorChildGet"),
626
+ LocalPidSupervisorChildGet: refused("LocalPidSupervisorChildGet"),
627
+ SupervisorNestedGet: refused("SupervisorNestedGet"),
628
+ SupervisorPoolChildGet: refused("SupervisorPoolChildGet"),
629
+ LocalPidSupervisorPoolChildRefGet: refused("LocalPidSupervisorPoolChildRefGet"),
630
+ SupervisorPoolLen: refused("SupervisorPoolLen"),
631
+ SupervisorStop: refused("SupervisorStop"),
632
+ TlsAttachLocal: refused("TlsAttachLocal"),
633
+ WebSocketAttachLocal: refused("WebSocketAttachLocal"),
634
+ TaskFree: refused("TaskFree"),
635
+ GeneratorFree: refused("GeneratorFree"),
636
+ VecAppend: refused("VecAppend"),
637
+ VecClear: refused("VecClear"),
638
+ VecClone: refused("VecClone"),
639
+ VecCloneLayout: refused("VecCloneLayout"),
640
+ VecCloneOwned: refused("VecCloneOwned"),
641
+ VecContainsLayout: refused("VecContainsLayout"),
642
+ VecTakeAll: refused("VecTakeAll"),
643
+ VecContainsOwned: refused("VecContainsOwned"),
644
+ VecIsEmpty: refused("VecIsEmpty"),
645
+ VecJoinStr: refused("VecJoinStr"),
646
+ VecLen: refused("VecLen"),
647
+ VecNew: refused("VecNew"),
648
+ VecPopBool: refused("VecPopBool"),
649
+ VecPopLayout: refused("VecPopLayout"),
650
+ VecPopOwned: refused("VecPopOwned"),
651
+ VecPushBool: refused("VecPushBool"),
652
+ VecPushLayout: refused("VecPushLayout"),
653
+ VecPushOwned: refused("VecPushOwned"),
654
+ VecPushOwnedMove: refused("VecPushOwnedMove"),
655
+ VecRemoveAtBool: refused("VecRemoveAtBool"),
656
+ VecRemoveAtLayout: refused("VecRemoveAtLayout"),
657
+ VecRemoveAtOwned: refused("VecRemoveAtOwned"),
658
+ VecSetBool: refused("VecSetBool"),
659
+ VecSetLayout: refused("VecSetLayout"),
660
+ VecSetOwned: refused("VecSetOwned"),
661
+ VecSetOwnedMove: refused("VecSetOwnedMove"),
662
+ VtableDispatchPanicOnOob: refused("VtableDispatchPanicOnOob"),
391
663
  };
392
664
  const VECTOR_SHIMS = {
393
665
  New: () => ({ kind: "vector", elementType: "", items: [] }),
@@ -596,8 +868,6 @@ const FLOAT_METHOD_SHIMS = {
596
868
  },
597
869
  IsSignNegative: (_host, args) => bool(toBits(real(args, 0)) >> 63n === 1n),
598
870
  };
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
871
  const INT_WIDTHS = {
602
872
  I8: { bits: 8, signed: true },
603
873
  I16: { bits: 16, signed: true },
@@ -610,15 +880,6 @@ const INT_WIDTHS = {
610
880
  U64: { bits: 64, signed: false },
611
881
  Usize: { bits: 64, signed: false },
612
882
  };
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
883
  function wrapTo(width, value) {
623
884
  return width.signed
624
885
  ? BigInt.asIntN(width.bits, value)
@@ -642,11 +903,8 @@ function popcount(value) {
642
903
  /// works on the receiver's unsigned bit pattern and the rotate amount is taken
643
904
  /// modulo the width.
644
905
  function intMethodShim(detail) {
645
- const parsed = intDetail(detail);
646
- if (!parsed) {
647
- return undefined;
648
- }
649
- const [op, width] = parsed;
906
+ const [op, name] = detail;
907
+ const width = INT_WIDTHS[name];
650
908
  const bits = BigInt(width.bits);
651
909
  const unsigned = (args) => BigInt.asUintN(width.bits, integer(args, 0));
652
910
  const result = (pattern) => int(wrapTo(width, pattern));
@@ -703,30 +961,34 @@ function intMethodShim(detail) {
703
961
  return (_host, args) => rotate(args, true);
704
962
  case "RotateRight":
705
963
  return (_host, args) => rotate(args, false);
706
- default:
707
- return undefined;
964
+ default: {
965
+ const exhaustive = op;
966
+ throw new Error(`unknown integer operation ${String(exhaustive)}`);
967
+ }
708
968
  }
709
969
  }
710
970
  /// Non-trapping integer arithmetic at the receiver's width: wrapping keeps
711
971
  /// the low bits, saturating clamps to the width's bounds and checked answers
712
972
  /// `None` where native's overflow flag is set.
713
973
  function intArithShim(detail) {
714
- const parsed = intDetail(detail);
715
- if (!parsed) {
716
- return undefined;
717
- }
718
- const [kind, width] = parsed;
974
+ const [kind, name] = detail;
975
+ const width = INT_WIDTHS[name];
719
976
  const [min, max] = intBounds(width);
977
+ const add = (x, y) => x + y;
978
+ const sub = (x, y) => x - y;
979
+ const mul = (x, y) => x * y;
720
980
  const operations = {
721
- Add: (x, y) => x + y,
722
- Sub: (x, y) => x - y,
723
- Mul: (x, y) => x * y,
981
+ WrappingAdd: ["Wrapping", add],
982
+ WrappingSub: ["Wrapping", sub],
983
+ WrappingMul: ["Wrapping", mul],
984
+ SaturatingAdd: ["Saturating", add],
985
+ SaturatingSub: ["Saturating", sub],
986
+ SaturatingMul: ["Saturating", mul],
987
+ CheckedAdd: ["Checked", add],
988
+ CheckedSub: ["Checked", sub],
989
+ CheckedMul: ["Checked", mul],
724
990
  };
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
- }
991
+ const [mode, apply] = operations[kind];
730
992
  const exact = (args) => apply(wrapTo(width, integer(args, 0)), wrapTo(width, integer(args, 1)));
731
993
  switch (mode) {
732
994
  case "Wrapping":
@@ -766,6 +1028,27 @@ function bigMax(left, right) {
766
1028
  }
767
1029
  // ── externs ─────────────────────────────────────────────────────────────────
768
1030
  const EXTERN_SHIMS = {
1031
+ hew_path_separator: () => str("/"),
1032
+ hew_calendar_format: {
1033
+ kind: "ordinary",
1034
+ bridge: "calendarBridge",
1035
+ shim: (host, args, _variant, shape) => executeCalendar(host.calendarBridge, "hew_calendar_format", args, shape),
1036
+ },
1037
+ hew_calendar_parse: {
1038
+ kind: "ordinary",
1039
+ bridge: "calendarBridge",
1040
+ shim: (host, args, _variant, shape) => executeCalendar(host.calendarBridge, "hew_calendar_parse", args, shape),
1041
+ },
1042
+ hew_calendar_components: {
1043
+ kind: "ordinary",
1044
+ bridge: "calendarBridge",
1045
+ shim: (host, args, _variant, shape) => executeCalendar(host.calendarBridge, "hew_calendar_components", args, shape),
1046
+ },
1047
+ hew_calendar_from_parts: {
1048
+ kind: "ordinary",
1049
+ bridge: "calendarBridge",
1050
+ shim: (host, args, _variant, shape) => executeCalendar(host.calendarBridge, "hew_calendar_from_parts", args, shape),
1051
+ },
769
1052
  hew_args_count: (host) => int(BigInt(host.argv.length)),
770
1053
  // A native null managed string is canonical empty. Each result owns fresh
771
1054
  // string storage; releasing it cannot change the host's supplied arguments.
@@ -904,9 +1187,6 @@ function pattern(host, value) {
904
1187
  return value.kind === "string" ? value.value : renderStdout(value);
905
1188
  }
906
1189
  // ── operand helpers ─────────────────────────────────────────────────────────
907
- function detailName(detail) {
908
- return typeof detail === "string" ? detail : "";
909
- }
910
1190
  function arg(args, at) {
911
1191
  return args[at] ?? UNIT;
912
1192
  }