gofront 1.8.0 → 1.9.1
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/README.md +3 -3
- package/package.json +6 -5
- package/src/backend/js/expressions.js +1157 -408
- package/src/backend/js/index.js +327 -153
- package/src/backend/js/natives.js +383 -0
- package/src/backend/js/runtime.js +559 -2552
- package/src/backend/js/statements.js +670 -158
- package/src/backend/js/stdlib/index.js +45 -93
- package/src/backend/js/templ.js +32 -45
- package/src/backend/js/type-info.js +298 -19
- package/src/backend/shared/fixed-float.js +20 -0
- package/src/backend/shared/fmt-types.js +91 -170
- package/src/backend/shared/host-unicode.js +36 -0
- package/src/backend/wasm/boundary.js +490 -965
- package/src/backend/wasm/emit-builtins.js +884 -256
- package/src/backend/wasm/emit-exprs.js +185 -77
- package/src/backend/wasm/emit-maps.js +17 -367
- package/src/backend/wasm/emit-shared.js +4 -1
- package/src/backend/wasm/emit-stmts.js +524 -240
- package/src/backend/wasm/emit.js +176 -38
- package/src/backend/wasm/globals.js +48 -8
- package/src/backend/wasm/glue.js +2 -4
- package/src/backend/wasm/index.js +44 -530
- package/src/backend/wasm/method-expr.js +12 -1
- package/src/backend/wasm/module-emitter.js +299 -770
- package/src/backend/wasm/monomorph.js +139 -8
- package/src/backend/wasm/natives.js +600 -0
- package/src/backend/wasm/prescan.js +5 -153
- package/src/backend/wasm/prune-funcs.js +89 -0
- package/src/backend/wasm/stdlib/index.js +2 -32
- package/src/backend/wasm/types.js +97 -20
- package/src/backend/wasm/variadic.js +9 -4
- package/src/cli/cli-core.js +5 -1
- package/src/cli/test-runner.js +115 -342
- package/src/compiler.js +113 -130
- package/src/lexer/lexer.js +106 -11
- package/src/lexer/templ-lexer.js +61 -18
- package/src/lexer/tokens.js +1 -0
- package/src/link/stdlib.js +355 -132
- package/src/link/type-names.js +204 -0
- package/src/link/wasm.js +30 -6
- package/src/lower/bounds.js +153 -0
- package/src/lower/captures.js +92 -33
- package/src/lower/embedding.js +62 -5
- package/src/lower/errors-as.js +196 -0
- package/src/lower/fmt-formatters.js +929 -0
- package/src/lower/functions.js +225 -7
- package/src/lower/gen-types.js +293 -0
- package/src/lower/index.js +14 -2
- package/src/lower/json-codecs.js +334 -245
- package/src/lower/ownership.js +25 -7
- package/src/lower/reachability.js +69 -51
- package/src/lower/walk.js +12 -0
- package/src/parser/declarations.js +30 -5
- package/src/parser/expressions.js +111 -57
- package/src/parser/statements.js +108 -0
- package/src/parser/templ.js +44 -5
- package/src/parser/types.js +12 -0
- package/src/resolver.js +1 -2
- package/src/typechecker/assignability.js +214 -19
- package/src/typechecker/const-fold.js +70 -27
- package/src/typechecker/constants.js +156 -8
- package/src/typechecker/expressions.js +490 -108
- package/src/typechecker/index.js +346 -42
- package/src/typechecker/init-order.js +136 -40
- package/src/typechecker/operand-text.js +41 -0
- package/src/typechecker/resolve.js +490 -65
- package/src/typechecker/statements.js +288 -27
- package/src/typechecker/stdlib/excluded.js +9 -5
- package/src/typechecker/stdlib/index.js +25 -9
- package/src/typechecker/termination.js +10 -1
- package/src/typechecker/types.js +287 -575
- package/stdlib/bytes/buffer.go +479 -0
- package/stdlib/bytes/bytes.go +1010 -0
- package/stdlib/bytes/reader.go +161 -0
- package/stdlib/context/context.go +115 -0
- package/stdlib/crypto/rand/rand.go +34 -0
- package/stdlib/crypto/sha256/sha256.go +249 -0
- package/stdlib/encoding/base64/base64.go +331 -0
- package/stdlib/encoding/binary/binary.go +332 -0
- package/stdlib/encoding/hex/hex.go +140 -0
- package/stdlib/encoding/json/json.go +62 -0
- package/stdlib/errors/errors.go +174 -0
- package/stdlib/fmt/errors.go +110 -0
- package/stdlib/fmt/format.go +732 -0
- package/stdlib/fmt/print.go +1232 -0
- package/stdlib/gom/gom.go +293 -0
- package/stdlib/html/html.go +251 -0
- package/stdlib/internal/fmtrt/fmtrt.go +163 -0
- package/stdlib/internal/jsonrt/dec.go +171 -38
- package/stdlib/internal/jsonrt/enc.go +186 -36
- package/stdlib/internal/jsonrt/scanner.go +17 -8
- package/stdlib/io/io.go +157 -1
- package/stdlib/maps/maps.go +131 -0
- package/stdlib/math/bits/bits.go +507 -0
- package/stdlib/math/extra.go +16 -14
- package/stdlib/math/math.go +439 -0
- package/stdlib/math/rand/rand.go +297 -0
- package/stdlib/os/os.go +93 -0
- package/stdlib/path/filepath/filepath.go +47 -0
- package/stdlib/path/path.go +394 -0
- package/stdlib/regexp/regexp.go +231 -0
- package/stdlib/slices/slices.go +526 -0
- package/stdlib/slices/sort.go +209 -0
- package/stdlib/slices/zsort_cmp.go +480 -0
- package/stdlib/slices/zsort_ordered.go +482 -0
- package/stdlib/sort/sort.go +391 -452
- package/stdlib/sort/zsort_func.go +480 -0
- package/stdlib/sort/zsort_iface.go +480 -0
- package/stdlib/strconv/float.go +1699 -0
- package/stdlib/strconv/isprint.go +752 -0
- package/stdlib/strconv/quote.go +235 -50
- package/stdlib/strconv/strconv.go +616 -0
- package/stdlib/strings/builder.go +95 -0
- package/stdlib/strings/reader.go +163 -0
- package/stdlib/strings/replacer.go +102 -0
- package/stdlib/strings/strings.go +807 -0
- package/stdlib/sync/sync.go +268 -0
- package/stdlib/testing/async_js.go +61 -0
- package/stdlib/testing/benchmark.go +297 -0
- package/stdlib/testing/testing.go +523 -0
- package/stdlib/time/duration.go +233 -0
- package/stdlib/time/format.go +745 -0
- package/stdlib/time/parse.go +790 -0
- package/stdlib/time/sleep_js.go +63 -0
- package/stdlib/time/time.go +834 -0
- package/stdlib/unicode/unicode.go +141 -3
- package/stdlib/unicode/utf8/utf8.go +464 -0
- package/src/backend/js/fmt-runtime.js +0 -573
- package/src/backend/js/stdlib/base64.js +0 -12
- package/src/backend/js/stdlib/binary.js +0 -102
- package/src/backend/js/stdlib/bits.js +0 -119
- package/src/backend/js/stdlib/builder.js +0 -98
- package/src/backend/js/stdlib/bytes.js +0 -368
- package/src/backend/js/stdlib/errors.js +0 -45
- package/src/backend/js/stdlib/fmt.js +0 -517
- package/src/backend/js/stdlib/gom.js +0 -155
- package/src/backend/js/stdlib/hex.js +0 -17
- package/src/backend/js/stdlib/html.js +0 -20
- package/src/backend/js/stdlib/io.js +0 -137
- package/src/backend/js/stdlib/json.js +0 -1167
- package/src/backend/js/stdlib/maps.js +0 -37
- package/src/backend/js/stdlib/math.js +0 -85
- package/src/backend/js/stdlib/os.js +0 -13
- package/src/backend/js/stdlib/path.js +0 -48
- package/src/backend/js/stdlib/rand.js +0 -32
- package/src/backend/js/stdlib/regexp.js +0 -54
- package/src/backend/js/stdlib/sha256.js +0 -12
- package/src/backend/js/stdlib/shared.js +0 -17
- package/src/backend/js/stdlib/simd.js +0 -34
- package/src/backend/js/stdlib/slices.js +0 -107
- package/src/backend/js/stdlib/sort.js +0 -30
- package/src/backend/js/stdlib/strconv.js +0 -79
- package/src/backend/js/stdlib/strings.js +0 -301
- package/src/backend/js/stdlib/sync.js +0 -13
- package/src/backend/js/stdlib/testing.js +0 -41
- package/src/backend/js/stdlib/time.js +0 -152
- package/src/backend/js/stdlib/unicode.js +0 -25
- package/src/backend/js/stdlib/utf8.js +0 -26
- package/src/backend/wasm/stdlib/bytes.js +0 -6716
- package/src/backend/wasm/stdlib/core.js +0 -10278
- package/src/backend/wasm/stdlib/io.js +0 -3578
- package/src/backend/wasm/stdlib/packages.js +0 -2402
- package/src/backend/wasm/stdlib/pure.js +0 -720
- package/src/backend/wasm/stdlib/time.js +0 -2229
- package/src/typechecker/stdlib/core.js +0 -1079
- package/src/typechecker/stdlib/extended.js +0 -1210
- package/stdlib/bytes/iter.go +0 -192
- package/stdlib/bytes/search.go +0 -240
- package/stdlib/bytes/split.go +0 -218
- package/stdlib/errors/overlay.go +0 -12
- package/stdlib/maps/iter.go +0 -65
- package/stdlib/slices/extra.go +0 -73
- package/stdlib/slices/iter.go +0 -113
- package/stdlib/strings/extra.go +0 -35
- package/stdlib/strings/iter.go +0 -122
- package/stdlib/sync/extra.go +0 -105
- package/stdlib/unicode/utf8/bytes.go +0 -239
|
@@ -31,26 +31,18 @@
|
|
|
31
31
|
// module's exported linear memory; JS sees a zero-copy TypedArray over
|
|
32
32
|
// `memory.buffer`. Only TypedArrays that already alias that memory (ones
|
|
33
33
|
// handed out by this facade) may be passed back in.
|
|
34
|
-
// - `*testing.T`: the harness's JS test object, passed as an opaque
|
|
35
|
-
// externref (test methods are routed back to JS via `env.testing_*`).
|
|
36
34
|
|
|
37
35
|
import { BROWSER_GLOBALS } from "../../typechecker/types.js";
|
|
36
|
+
import { FIXED_FLOAT_JS } from "../shared/fixed-float.js";
|
|
38
37
|
import {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
HELPER_PATH_CLEAN,
|
|
44
|
-
HELPER_SHA256,
|
|
45
|
-
HELPER_SPRINT,
|
|
46
|
-
HELPER_SPRINTF,
|
|
47
|
-
HELPER_STRCONV,
|
|
48
|
-
} from "../js/runtime.js";
|
|
38
|
+
unicodeIsJs,
|
|
39
|
+
unicodeToLowerJs,
|
|
40
|
+
unicodeToUpperJs,
|
|
41
|
+
} from "../shared/host-unicode.js";
|
|
49
42
|
import {
|
|
50
43
|
anonIfaceName,
|
|
51
44
|
getInterfaceMethodList,
|
|
52
45
|
getSharedInfo,
|
|
53
|
-
isTestingT,
|
|
54
46
|
} from "./types.js";
|
|
55
47
|
|
|
56
48
|
// ── Type classification ──────────────────────────────────────
|
|
@@ -87,8 +79,16 @@ function toRef(info) {
|
|
|
87
79
|
return { kind: "ref", nullable: true, typeIndex: info.typeIndex };
|
|
88
80
|
}
|
|
89
81
|
|
|
82
|
+
// The facade and its wasm export names build identifiers from a struct's name,
|
|
83
|
+
// so the dot of a stdlib type (`strings.Builder`) becomes `$`.
|
|
90
84
|
function structDesc(info, ptr) {
|
|
91
|
-
return {
|
|
85
|
+
return {
|
|
86
|
+
k: "struct",
|
|
87
|
+
name: info.name.replaceAll(".", "$"),
|
|
88
|
+
ptr,
|
|
89
|
+
info,
|
|
90
|
+
wType: toRef(info),
|
|
91
|
+
};
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
function funcSigFromAst(t) {
|
|
@@ -111,17 +111,9 @@ function funcSigFromAst(t) {
|
|
|
111
111
|
// Returns a descriptor `{ k, ... }`; `k === "unsupported"` carries `what`.
|
|
112
112
|
function classifyType(goType, mod) {
|
|
113
113
|
if (!goType) return { k: "void" };
|
|
114
|
-
if (isTestingT(goType)) return { k: "extern", wType: "externref" };
|
|
115
114
|
|
|
116
115
|
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
117
116
|
if (goType.name === "error") return { k: "error", wType: "anyref" };
|
|
118
|
-
if (goType.name === "time.Duration" || goType.name === "Duration")
|
|
119
|
-
return { k: "i64", unsigned: false, wType: "i64" };
|
|
120
|
-
if (goType.name === "time.Time" || goType.name === "Time") {
|
|
121
|
-
const info = mod.getStructType("time.Time");
|
|
122
|
-
if (info)
|
|
123
|
-
return { k: "time", name: "time.Time", info, wType: toRef(info) };
|
|
124
|
-
}
|
|
125
117
|
const info = mod.getStructType(goType.name);
|
|
126
118
|
if (info) return structDesc(info, false);
|
|
127
119
|
const resolved = mod.checker?.types?.get(goType.name);
|
|
@@ -213,7 +205,12 @@ function classifyBasic(n) {
|
|
|
213
205
|
if (I32_INTS.has(n))
|
|
214
206
|
return { k: "i32", unsigned: UNSIGNED.has(n), wType: "i32" };
|
|
215
207
|
if (I64_INTS.has(n))
|
|
216
|
-
return {
|
|
208
|
+
return {
|
|
209
|
+
k: "i64",
|
|
210
|
+
unsigned: UNSIGNED.has(n),
|
|
211
|
+
is64: n === "int64" || n === "uint64",
|
|
212
|
+
wType: "i64",
|
|
213
|
+
};
|
|
217
214
|
const d = BASIC_DESCS[n];
|
|
218
215
|
return d ? { ...d } : { k: "unsupported", what: `type '${n}'` };
|
|
219
216
|
}
|
|
@@ -229,12 +226,6 @@ function classifyNamed(t, mod) {
|
|
|
229
226
|
return classifySimd(t.underlying ?? t, mod, t.name);
|
|
230
227
|
}
|
|
231
228
|
if (t.name === "error") return { k: "error", wType: "anyref" };
|
|
232
|
-
if (t.name === "time.Duration")
|
|
233
|
-
return { k: "i64", unsigned: false, wType: "i64" };
|
|
234
|
-
if (t.name === "time.Time") {
|
|
235
|
-
const info = mod.getStructType("time.Time");
|
|
236
|
-
if (info) return { k: "time", name: "time.Time", info, wType: toRef(info) };
|
|
237
|
-
}
|
|
238
229
|
const info = mod.getStructType(t.name);
|
|
239
230
|
if (info) return structDesc(info, false);
|
|
240
231
|
if (t.underlying) return classifyType(t.underlying, mod);
|
|
@@ -294,10 +285,9 @@ function classifyPointer(t, mod) {
|
|
|
294
285
|
if (base.k === "unsupported") return base;
|
|
295
286
|
if (base.k === "struct" && !base.ptr) return { ...base, ptr: true };
|
|
296
287
|
if (base.k === "anon_struct" && !base.ptr) return { ...base, ptr: true };
|
|
297
|
-
if (base.k === "time" && !base.ptr) return { ...base, ptr: true };
|
|
298
288
|
const boxInfo = mod.getBoxType(t.base);
|
|
299
289
|
const ptrInfo = mod.getPtrType ? mod.getPtrType(t.base) : null;
|
|
300
|
-
const key = `${base.k}${base.unsigned ? "_u" : ""}_${boxInfo.typeIndex}`;
|
|
290
|
+
const key = `${base.k}${base.unsigned ? "_u" : ""}${base.is64 ? "_64" : ""}_${boxInfo.typeIndex}`;
|
|
301
291
|
return {
|
|
302
292
|
k: "ptr_box",
|
|
303
293
|
base,
|
|
@@ -379,7 +369,11 @@ function classifySlice(t, mod) {
|
|
|
379
369
|
// so they get separate helper keys.
|
|
380
370
|
key:
|
|
381
371
|
wTypeKey(sliceInfo.elemWType) +
|
|
382
|
-
(elem.k === "f32x4" || elem.k === "mask4"
|
|
372
|
+
(elem.k === "f32x4" || elem.k === "mask4"
|
|
373
|
+
? `_${elem.k}`
|
|
374
|
+
: elem.is64
|
|
375
|
+
? "_i64"
|
|
376
|
+
: ""),
|
|
383
377
|
wType: { kind: "ref", nullable: true, typeIndex: sliceInfo.typeIndex },
|
|
384
378
|
};
|
|
385
379
|
}
|
|
@@ -399,7 +393,7 @@ function classifyArray(t, mod) {
|
|
|
399
393
|
elem,
|
|
400
394
|
size: arraySize(t),
|
|
401
395
|
arrInfo,
|
|
402
|
-
key: wTypeKey(arrInfo.elemWType),
|
|
396
|
+
key: wTypeKey(arrInfo.elemWType) + (elem.is64 ? "_i64" : ""),
|
|
403
397
|
wType: { kind: "ref", nullable: true, typeIndex: arrInfo.typeIndex },
|
|
404
398
|
};
|
|
405
399
|
}
|
|
@@ -574,6 +568,9 @@ export function collectBoundaryMeta(progs, funcDecls, mod) {
|
|
|
574
568
|
for (const p of progs) {
|
|
575
569
|
const pkgName = p.pkg?.name ?? "main";
|
|
576
570
|
const pkgTarget = p.target ?? "wasm";
|
|
571
|
+
// The tests of a package run inside the module: only the generated
|
|
572
|
+
// driver crosses the boundary.
|
|
573
|
+
if (isTestSource(p._path ?? p._filename)) continue;
|
|
577
574
|
for (const d of p.decls ?? []) {
|
|
578
575
|
if (d.kind === "TypeDecl" && d.type?.kind === "StructType") {
|
|
579
576
|
collectStructDecl(d, pkgName, pkgTarget, meta, mod);
|
|
@@ -587,6 +584,7 @@ export function collectBoundaryMeta(progs, funcDecls, mod) {
|
|
|
587
584
|
|
|
588
585
|
for (const fn of funcDecls) {
|
|
589
586
|
if (fn._isClosure || fn._pkgTarget !== "wasm") continue;
|
|
587
|
+
if (isTestSource(fn._srcFile) && fn.name !== TEST_DRIVER) continue;
|
|
590
588
|
if (fn._isMethod) collectMethodMeta(fn, meta, errors, mod);
|
|
591
589
|
else collectFuncMeta(fn, meta, errors, mod);
|
|
592
590
|
}
|
|
@@ -595,12 +593,19 @@ export function collectBoundaryMeta(progs, funcDecls, mod) {
|
|
|
595
593
|
return meta;
|
|
596
594
|
}
|
|
597
595
|
|
|
596
|
+
// The driver function the test runner compiles in (src/cli/test-runner.js).
|
|
597
|
+
const TEST_DRIVER = "GofrontRunTests";
|
|
598
|
+
|
|
599
|
+
const isTestSource = (file) => Boolean(file?.endsWith("_test.go"));
|
|
600
|
+
|
|
598
601
|
function collectStructDecl(d, pkgName, pkgTarget, meta, mod) {
|
|
599
|
-
if (
|
|
602
|
+
if (meta.structByName.has(d.name)) return;
|
|
600
603
|
const info = mod.getStructType(d.name);
|
|
601
604
|
if (!info) return;
|
|
602
605
|
const s = { name: d.name, pkgName, pkgTarget, info, methods: [] };
|
|
603
|
-
|
|
606
|
+
// An unexported struct has no class of its own, but its exported methods
|
|
607
|
+
// reach JS through the exported structs that embed it.
|
|
608
|
+
if (isExported(d.name)) meta.structs.push(s);
|
|
604
609
|
meta.structByName.set(d.name, s);
|
|
605
610
|
}
|
|
606
611
|
|
|
@@ -755,9 +760,6 @@ function visitNeed(desc, needs, errors, mod) {
|
|
|
755
760
|
needs.simd = desc.arr;
|
|
756
761
|
visitNeed(desc.arr, needs, errors, mod);
|
|
757
762
|
return;
|
|
758
|
-
case "time":
|
|
759
|
-
needs.time = true;
|
|
760
|
-
return;
|
|
761
763
|
case "slice":
|
|
762
764
|
case "array": {
|
|
763
765
|
const map = desc.k === "slice" ? needs.slices : needs.arrays;
|
|
@@ -834,7 +836,6 @@ function collectNeeds(meta) {
|
|
|
834
836
|
funcs: new Map(), // key -> desc
|
|
835
837
|
ifaces: new Map(), // interface name -> desc
|
|
836
838
|
error: false,
|
|
837
|
-
time: false,
|
|
838
839
|
simd: null, // array desc carrying vectors across the boundary
|
|
839
840
|
shared: false, // any shared buffer on the surface
|
|
840
841
|
};
|
|
@@ -862,11 +863,20 @@ export function scanBoundaryImports(mod, meta) {
|
|
|
862
863
|
const needs = collectNeeds(meta);
|
|
863
864
|
meta._needs = needs;
|
|
864
865
|
for (const [key, desc] of needs.funcs) {
|
|
866
|
+
const paramDescs = desc.params ?? [];
|
|
867
|
+
const returnDescs = desc.returns ?? [];
|
|
865
868
|
mod.getOrAddFuncImport(
|
|
866
869
|
"env",
|
|
867
870
|
`__invoke$${key}`,
|
|
868
|
-
[
|
|
869
|
-
|
|
871
|
+
[
|
|
872
|
+
"externref",
|
|
873
|
+
...desc.closureInfo.paramWTypes.map((w, i) =>
|
|
874
|
+
extType(w, paramDescs[i]?.is64),
|
|
875
|
+
),
|
|
876
|
+
],
|
|
877
|
+
desc.closureInfo.returnWTypes.map((w, i) =>
|
|
878
|
+
extType(w, returnDescs[i]?.is64),
|
|
879
|
+
),
|
|
870
880
|
);
|
|
871
881
|
}
|
|
872
882
|
}
|
|
@@ -884,19 +894,21 @@ function isGcRef(wType) {
|
|
|
884
894
|
// the converting helpers are registered first thing in addBoundaryHelpers.
|
|
885
895
|
const v128Conv = { from: null, to: null };
|
|
886
896
|
|
|
887
|
-
function extType(wType) {
|
|
897
|
+
function extType(wType, is64 = false) {
|
|
888
898
|
if (wType === "v128") return "externref";
|
|
889
|
-
if (wType === "i64") return "f64";
|
|
899
|
+
if (wType === "i64") return is64 ? "i64" : "f64";
|
|
890
900
|
if (isGcRef(wType)) return "externref";
|
|
891
901
|
return wType;
|
|
892
902
|
}
|
|
893
|
-
function needsConv(wTypes) {
|
|
894
|
-
return wTypes.some(
|
|
903
|
+
function needsConv(wTypes, descs = []) {
|
|
904
|
+
return wTypes.some(
|
|
905
|
+
(w, i) => (w === "i64" && !descs[i]?.is64) || w === "v128" || isGcRef(w),
|
|
906
|
+
);
|
|
895
907
|
}
|
|
896
908
|
// Instructions converting the value on the stack from its boundary form.
|
|
897
|
-
function fromExt(wType) {
|
|
909
|
+
function fromExt(wType, is64 = false) {
|
|
898
910
|
if (wType === "v128") return [{ op: "call", funcIndex: v128Conv.from }];
|
|
899
|
-
if (wType === "i64") return [{ op: "i64.trunc_sat_f64_s" }];
|
|
911
|
+
if (wType === "i64") return is64 ? [] : [{ op: "i64.trunc_sat_f64_s" }];
|
|
900
912
|
if (wType === "anyref") return [{ op: "any.convert_extern" }];
|
|
901
913
|
if (isGcRef(wType)) {
|
|
902
914
|
const out = [{ op: "any.convert_extern" }];
|
|
@@ -907,22 +919,25 @@ function fromExt(wType) {
|
|
|
907
919
|
return [];
|
|
908
920
|
}
|
|
909
921
|
// Instructions converting the value on the stack to its boundary form.
|
|
910
|
-
function toExt(wType) {
|
|
922
|
+
function toExt(wType, is64 = false) {
|
|
911
923
|
if (wType === "v128") return [{ op: "call", funcIndex: v128Conv.to }];
|
|
912
|
-
if (wType === "i64") return [{ op: "f64.convert_i64_s" }];
|
|
924
|
+
if (wType === "i64") return is64 ? [] : [{ op: "f64.convert_i64_s" }];
|
|
913
925
|
if (isGcRef(wType)) return [{ op: "extern.convert_any" }];
|
|
914
926
|
return [];
|
|
915
927
|
}
|
|
916
928
|
// Rewrites the values on top of the stack (types `wTypes`) with `conv`,
|
|
917
929
|
// spilling through locals starting at `localBase` when more than one.
|
|
918
|
-
function convertResults(wTypes, conv, localBase) {
|
|
919
|
-
if (wTypes.length === 0 || !needsConv(wTypes)) return [];
|
|
920
|
-
if (wTypes.length === 1) return conv(wTypes[0]);
|
|
930
|
+
function convertResults(wTypes, conv, localBase, descs = []) {
|
|
931
|
+
if (wTypes.length === 0 || !needsConv(wTypes, descs)) return [];
|
|
932
|
+
if (wTypes.length === 1) return conv(wTypes[0], descs[0]?.is64);
|
|
921
933
|
const out = [];
|
|
922
934
|
for (let i = wTypes.length - 1; i >= 0; i--)
|
|
923
935
|
out.push({ op: "local.set", index: localBase + i });
|
|
924
936
|
for (let i = 0; i < wTypes.length; i++)
|
|
925
|
-
out.push(
|
|
937
|
+
out.push(
|
|
938
|
+
{ op: "local.get", index: localBase + i },
|
|
939
|
+
...conv(wTypes[i], descs[i]?.is64),
|
|
940
|
+
);
|
|
926
941
|
return out;
|
|
927
942
|
}
|
|
928
943
|
|
|
@@ -1022,19 +1037,19 @@ export function addBoundaryHelpers(mod, meta) {
|
|
|
1022
1037
|
);
|
|
1023
1038
|
}
|
|
1024
1039
|
// Parameter `i` converted from its boundary form.
|
|
1025
|
-
const getIn = (i, wType) => [get(i), ...fromExt(wType)];
|
|
1040
|
+
const getIn = (i, wType, is64 = false) => [get(i), ...fromExt(wType, is64)];
|
|
1026
1041
|
const EXT = "externref";
|
|
1027
1042
|
|
|
1028
|
-
for (const [name, { info }] of needs.structs) {
|
|
1043
|
+
for (const [name, { info, fields }] of needs.structs) {
|
|
1029
1044
|
const ref = toRef(info);
|
|
1030
1045
|
const ti = info.typeIndex;
|
|
1031
1046
|
const fieldWTypes = info.fields.map((f) => f.wType);
|
|
1032
1047
|
addFunc(
|
|
1033
1048
|
`__new_${name}`,
|
|
1034
|
-
fieldWTypes.map(extType),
|
|
1049
|
+
fieldWTypes.map((w, i) => extType(w, fields[i]?.desc?.is64)),
|
|
1035
1050
|
[EXT],
|
|
1036
1051
|
[
|
|
1037
|
-
...fieldWTypes.flatMap((w, i) => getIn(i, w)),
|
|
1052
|
+
...fieldWTypes.flatMap((w, i) => getIn(i, w, fields[i]?.desc?.is64)),
|
|
1038
1053
|
{ op: "struct.new", typeIndex: ti },
|
|
1039
1054
|
...toExt(ref),
|
|
1040
1055
|
],
|
|
@@ -1064,23 +1079,24 @@ export function addBoundaryHelpers(mod, meta) {
|
|
|
1064
1079
|
);
|
|
1065
1080
|
for (let i = 0; i < info.fields.length; i++) {
|
|
1066
1081
|
const f = info.fields[i];
|
|
1082
|
+
const is64 = Boolean(fields[i]?.desc?.is64);
|
|
1067
1083
|
addFunc(
|
|
1068
1084
|
`__get_${name}_${f.name}`,
|
|
1069
1085
|
[EXT],
|
|
1070
|
-
[extType(f.wType)],
|
|
1086
|
+
[extType(f.wType, is64)],
|
|
1071
1087
|
[
|
|
1072
1088
|
...getIn(0, ref),
|
|
1073
1089
|
{ op: "struct.get", typeIndex: ti, fieldIndex: i },
|
|
1074
|
-
...toExt(f.wType),
|
|
1090
|
+
...toExt(f.wType, is64),
|
|
1075
1091
|
],
|
|
1076
1092
|
);
|
|
1077
1093
|
addFunc(
|
|
1078
1094
|
`__set_${name}_${f.name}`,
|
|
1079
|
-
[EXT, extType(f.wType)],
|
|
1095
|
+
[EXT, extType(f.wType, is64)],
|
|
1080
1096
|
[],
|
|
1081
1097
|
[
|
|
1082
1098
|
...getIn(0, ref),
|
|
1083
|
-
...getIn(1, f.wType),
|
|
1099
|
+
...getIn(1, f.wType, is64),
|
|
1084
1100
|
{ op: "struct.set", typeIndex: ti, fieldIndex: i },
|
|
1085
1101
|
],
|
|
1086
1102
|
);
|
|
@@ -1106,25 +1122,26 @@ export function addBoundaryHelpers(mod, meta) {
|
|
|
1106
1122
|
["i32"],
|
|
1107
1123
|
[...getIn(0, ref), { op: "array.len" }],
|
|
1108
1124
|
);
|
|
1125
|
+
const is64 = Boolean(desc.elem?.is64);
|
|
1109
1126
|
addFunc(
|
|
1110
1127
|
`__array_get_${key}`,
|
|
1111
1128
|
[EXT, "i32"],
|
|
1112
|
-
[extType(arrInfo.elemWType)],
|
|
1129
|
+
[extType(arrInfo.elemWType, is64)],
|
|
1113
1130
|
[
|
|
1114
1131
|
...getIn(0, ref),
|
|
1115
1132
|
get(1),
|
|
1116
1133
|
{ op: "array.get", typeIndex: arrInfo.typeIndex },
|
|
1117
|
-
...toExt(arrInfo.elemWType),
|
|
1134
|
+
...toExt(arrInfo.elemWType, is64),
|
|
1118
1135
|
],
|
|
1119
1136
|
);
|
|
1120
1137
|
addFunc(
|
|
1121
1138
|
`__array_set_${key}`,
|
|
1122
|
-
[EXT, "i32", extType(arrInfo.elemWType)],
|
|
1139
|
+
[EXT, "i32", extType(arrInfo.elemWType, is64)],
|
|
1123
1140
|
[],
|
|
1124
1141
|
[
|
|
1125
1142
|
...getIn(0, ref),
|
|
1126
1143
|
get(1),
|
|
1127
|
-
...getIn(2, arrInfo.elemWType),
|
|
1144
|
+
...getIn(2, arrInfo.elemWType, is64),
|
|
1128
1145
|
{ op: "array.set", typeIndex: arrInfo.typeIndex },
|
|
1129
1146
|
],
|
|
1130
1147
|
);
|
|
@@ -1135,6 +1152,7 @@ export function addBoundaryHelpers(mod, meta) {
|
|
|
1135
1152
|
const ref = desc.wType;
|
|
1136
1153
|
const arrTI = sliceInfo.arrInfo.typeIndex;
|
|
1137
1154
|
const sTI = sliceInfo.typeIndex;
|
|
1155
|
+
const is64 = Boolean(desc.elem?.is64);
|
|
1138
1156
|
const elemAddr = [
|
|
1139
1157
|
...getIn(0, ref),
|
|
1140
1158
|
{ op: "struct.get", typeIndex: sTI, fieldIndex: 0 },
|
|
@@ -1166,11 +1184,11 @@ export function addBoundaryHelpers(mod, meta) {
|
|
|
1166
1184
|
addFunc(
|
|
1167
1185
|
`__slice_get_${key}`,
|
|
1168
1186
|
[EXT, "i32"],
|
|
1169
|
-
[extType(sliceInfo.elemWType)],
|
|
1187
|
+
[extType(sliceInfo.elemWType, is64)],
|
|
1170
1188
|
[
|
|
1171
1189
|
...elemAddr,
|
|
1172
1190
|
{ op: "array.get", typeIndex: arrTI },
|
|
1173
|
-
...toExt(sliceInfo.elemWType),
|
|
1191
|
+
...toExt(sliceInfo.elemWType, is64),
|
|
1174
1192
|
],
|
|
1175
1193
|
);
|
|
1176
1194
|
addFunc(
|
|
@@ -1191,11 +1209,11 @@ export function addBoundaryHelpers(mod, meta) {
|
|
|
1191
1209
|
);
|
|
1192
1210
|
addFunc(
|
|
1193
1211
|
`__slice_set_${key}`,
|
|
1194
|
-
[EXT, "i32", extType(sliceInfo.elemWType)],
|
|
1212
|
+
[EXT, "i32", extType(sliceInfo.elemWType, is64)],
|
|
1195
1213
|
[],
|
|
1196
1214
|
[
|
|
1197
1215
|
...elemAddr,
|
|
1198
|
-
...getIn(2, sliceInfo.elemWType),
|
|
1216
|
+
...getIn(2, sliceInfo.elemWType, is64),
|
|
1199
1217
|
{ op: "array.set", typeIndex: arrTI },
|
|
1200
1218
|
],
|
|
1201
1219
|
);
|
|
@@ -1205,6 +1223,8 @@ export function addBoundaryHelpers(mod, meta) {
|
|
|
1205
1223
|
const ci = desc.closureInfo;
|
|
1206
1224
|
const invokeIdx = mod.importCache.get(`env.__invoke$${key}`);
|
|
1207
1225
|
const nParams = ci.paramWTypes.length;
|
|
1226
|
+
const paramDescs = desc.params ?? [];
|
|
1227
|
+
const returnDescs = desc.returns ?? [];
|
|
1208
1228
|
// Thunk: wasm closure body calling the JS callback (boundary forms out, back in).
|
|
1209
1229
|
const thunkIdx = addFunc(
|
|
1210
1230
|
`__jsthunk$${key}`,
|
|
@@ -1213,12 +1233,17 @@ export function addBoundaryHelpers(mod, meta) {
|
|
|
1213
1233
|
[
|
|
1214
1234
|
get(0),
|
|
1215
1235
|
{ op: "extern.convert_any" },
|
|
1216
|
-
...ci.paramWTypes.flatMap((w, i) => [
|
|
1236
|
+
...ci.paramWTypes.flatMap((w, i) => [
|
|
1237
|
+
get(i + 1),
|
|
1238
|
+
...toExt(w, paramDescs[i]?.is64),
|
|
1239
|
+
]),
|
|
1217
1240
|
{ op: "call", funcIndex: invokeIdx },
|
|
1218
|
-
...convertResults(ci.returnWTypes, fromExt, nParams + 1),
|
|
1241
|
+
...convertResults(ci.returnWTypes, fromExt, nParams + 1, returnDescs),
|
|
1219
1242
|
],
|
|
1220
1243
|
false,
|
|
1221
|
-
ci.returnWTypes.length > 1
|
|
1244
|
+
ci.returnWTypes.length > 1
|
|
1245
|
+
? ci.returnWTypes.map((w, i) => extType(w, returnDescs[i]?.is64))
|
|
1246
|
+
: [],
|
|
1222
1247
|
);
|
|
1223
1248
|
mod.addRefFuncElement(thunkIdx);
|
|
1224
1249
|
addFunc(
|
|
@@ -1236,16 +1261,18 @@ export function addBoundaryHelpers(mod, meta) {
|
|
|
1236
1261
|
// JS calling a wasm closure (boundary forms in, results out).
|
|
1237
1262
|
addFunc(
|
|
1238
1263
|
`__call_fn$${key}`,
|
|
1239
|
-
[EXT, ...ci.paramWTypes.map(extType)],
|
|
1240
|
-
ci.returnWTypes.map(extType),
|
|
1264
|
+
[EXT, ...ci.paramWTypes.map((w, i) => extType(w, paramDescs[i]?.is64))],
|
|
1265
|
+
ci.returnWTypes.map((w, i) => extType(w, returnDescs[i]?.is64)),
|
|
1241
1266
|
[
|
|
1242
1267
|
...getIn(0, desc.wType),
|
|
1243
1268
|
{ op: "struct.get", typeIndex: ci.typeIndex, fieldIndex: 1 },
|
|
1244
|
-
...ci.paramWTypes.flatMap((w, i) =>
|
|
1269
|
+
...ci.paramWTypes.flatMap((w, i) =>
|
|
1270
|
+
getIn(i + 1, w, paramDescs[i]?.is64),
|
|
1271
|
+
),
|
|
1245
1272
|
...getIn(0, desc.wType),
|
|
1246
1273
|
{ op: "struct.get", typeIndex: ci.typeIndex, fieldIndex: 0 },
|
|
1247
1274
|
{ op: "call_ref", typeIndex: ci.funcTypeIndex },
|
|
1248
|
-
...convertResults(ci.returnWTypes, toExt, nParams + 1),
|
|
1275
|
+
...convertResults(ci.returnWTypes, toExt, nParams + 1, returnDescs),
|
|
1249
1276
|
],
|
|
1250
1277
|
true,
|
|
1251
1278
|
ci.returnWTypes.length > 1 ? ci.returnWTypes : [],
|
|
@@ -1263,17 +1290,20 @@ export function addBoundaryHelpers(mod, meta) {
|
|
|
1263
1290
|
if (sig?.form !== "func") return;
|
|
1264
1291
|
const paramW = sig.params;
|
|
1265
1292
|
const resultW = sig.results;
|
|
1266
|
-
|
|
1293
|
+
const paramDescs = entry.params ?? [];
|
|
1294
|
+
const resultDescs = entry.returns ?? [];
|
|
1295
|
+
if (!needsConv(paramW, paramDescs) && !needsConv(resultW, resultDescs))
|
|
1296
|
+
return;
|
|
1267
1297
|
// Exported names become JS identifiers: no dot of a qualified type.
|
|
1268
1298
|
entry.callName = `__x_${entry.exportName}`.replaceAll(".", "_");
|
|
1269
1299
|
addFunc(
|
|
1270
1300
|
entry.callName,
|
|
1271
|
-
paramW.map(extType),
|
|
1272
|
-
resultW.map(extType),
|
|
1301
|
+
paramW.map((w, i) => extType(w, paramDescs[i]?.is64)),
|
|
1302
|
+
resultW.map((w, i) => extType(w, resultDescs[i]?.is64)),
|
|
1273
1303
|
[
|
|
1274
|
-
...paramW.flatMap((w, i) => getIn(i, w)),
|
|
1304
|
+
...paramW.flatMap((w, i) => getIn(i, w, paramDescs[i]?.is64)),
|
|
1275
1305
|
{ op: "call", funcIndex: fnIdx },
|
|
1276
|
-
...convertResults(resultW, toExt, paramW.length),
|
|
1306
|
+
...convertResults(resultW, toExt, paramW.length, resultDescs),
|
|
1277
1307
|
],
|
|
1278
1308
|
true,
|
|
1279
1309
|
resultW.length > 1 ? resultW : [],
|
|
@@ -1318,16 +1348,16 @@ export function addBoundaryHelpers(mod, meta) {
|
|
|
1318
1348
|
}
|
|
1319
1349
|
|
|
1320
1350
|
for (const [name, desc] of needs.anonStructs) {
|
|
1321
|
-
const { info } = desc;
|
|
1351
|
+
const { info, fields } = desc;
|
|
1322
1352
|
const ref = desc.wType;
|
|
1323
1353
|
const ti = info.typeIndex;
|
|
1324
1354
|
const fieldWTypes = info.fields.map((f) => f.wType);
|
|
1325
1355
|
addFunc(
|
|
1326
1356
|
`__new_${name}`,
|
|
1327
|
-
fieldWTypes.map(extType),
|
|
1357
|
+
fieldWTypes.map((w, i) => extType(w, fields[i]?.desc?.is64)),
|
|
1328
1358
|
[EXT],
|
|
1329
1359
|
[
|
|
1330
|
-
...fieldWTypes.flatMap((w, i) => getIn(i, w)),
|
|
1360
|
+
...fieldWTypes.flatMap((w, i) => getIn(i, w, fields[i]?.desc?.is64)),
|
|
1331
1361
|
{ op: "struct.new", typeIndex: ti },
|
|
1332
1362
|
...toExt(ref),
|
|
1333
1363
|
],
|
|
@@ -1344,23 +1374,24 @@ export function addBoundaryHelpers(mod, meta) {
|
|
|
1344
1374
|
);
|
|
1345
1375
|
for (let i = 0; i < info.fields.length; i++) {
|
|
1346
1376
|
const f = info.fields[i];
|
|
1377
|
+
const is64 = Boolean(fields[i]?.desc?.is64);
|
|
1347
1378
|
addFunc(
|
|
1348
1379
|
`__get_${name}_${f.name}`,
|
|
1349
1380
|
[EXT],
|
|
1350
|
-
[extType(f.wType)],
|
|
1381
|
+
[extType(f.wType, is64)],
|
|
1351
1382
|
[
|
|
1352
1383
|
...getIn(0, ref),
|
|
1353
1384
|
{ op: "struct.get", typeIndex: ti, fieldIndex: i },
|
|
1354
|
-
...toExt(f.wType),
|
|
1385
|
+
...toExt(f.wType, is64),
|
|
1355
1386
|
],
|
|
1356
1387
|
);
|
|
1357
1388
|
addFunc(
|
|
1358
1389
|
`__set_${name}_${f.name}`,
|
|
1359
|
-
[EXT, extType(f.wType)],
|
|
1390
|
+
[EXT, extType(f.wType, is64)],
|
|
1360
1391
|
[],
|
|
1361
1392
|
[
|
|
1362
1393
|
...getIn(0, ref),
|
|
1363
|
-
...getIn(1, f.wType),
|
|
1394
|
+
...getIn(1, f.wType, is64),
|
|
1364
1395
|
{ op: "struct.set", typeIndex: ti, fieldIndex: i },
|
|
1365
1396
|
],
|
|
1366
1397
|
);
|
|
@@ -1368,15 +1399,20 @@ export function addBoundaryHelpers(mod, meta) {
|
|
|
1368
1399
|
}
|
|
1369
1400
|
|
|
1370
1401
|
for (const [key, desc] of needs.boxes) {
|
|
1371
|
-
const { boxInfo } = desc;
|
|
1402
|
+
const { boxInfo, base } = desc;
|
|
1372
1403
|
const ref = desc.wType;
|
|
1373
1404
|
const ti = boxInfo.typeIndex;
|
|
1374
1405
|
const w = boxInfo.wType;
|
|
1406
|
+
const is64 = Boolean(base?.is64);
|
|
1375
1407
|
addFunc(
|
|
1376
1408
|
`__box_new_${key}`,
|
|
1377
|
-
[extType(w)],
|
|
1409
|
+
[extType(w, is64)],
|
|
1378
1410
|
[EXT],
|
|
1379
|
-
[
|
|
1411
|
+
[
|
|
1412
|
+
...getIn(0, w, is64),
|
|
1413
|
+
{ op: "struct.new", typeIndex: ti },
|
|
1414
|
+
...toExt(ref),
|
|
1415
|
+
],
|
|
1380
1416
|
);
|
|
1381
1417
|
const cast = {
|
|
1382
1418
|
op: "ref.cast",
|
|
@@ -1386,29 +1422,29 @@ export function addBoundaryHelpers(mod, meta) {
|
|
|
1386
1422
|
addFunc(
|
|
1387
1423
|
`__box_get_${key}`,
|
|
1388
1424
|
[EXT],
|
|
1389
|
-
[extType(w)],
|
|
1425
|
+
[extType(w, is64)],
|
|
1390
1426
|
[
|
|
1391
1427
|
...getIn(0, ref),
|
|
1392
1428
|
cast,
|
|
1393
1429
|
{ op: "struct.get", typeIndex: ti, fieldIndex: 0 },
|
|
1394
|
-
...toExt(w),
|
|
1430
|
+
...toExt(w, is64),
|
|
1395
1431
|
],
|
|
1396
1432
|
);
|
|
1397
1433
|
addFunc(
|
|
1398
1434
|
`__box_set_${key}`,
|
|
1399
|
-
[EXT, extType(w)],
|
|
1435
|
+
[EXT, extType(w, is64)],
|
|
1400
1436
|
[],
|
|
1401
1437
|
[
|
|
1402
1438
|
...getIn(0, ref),
|
|
1403
1439
|
cast,
|
|
1404
|
-
...getIn(1, w),
|
|
1440
|
+
...getIn(1, w, is64),
|
|
1405
1441
|
{ op: "struct.set", typeIndex: ti, fieldIndex: 0 },
|
|
1406
1442
|
],
|
|
1407
1443
|
);
|
|
1408
1444
|
}
|
|
1409
1445
|
|
|
1410
1446
|
for (const [key, desc] of needs.maps) {
|
|
1411
|
-
const { mapInfo, keySliceDesc, valSliceDesc } = desc;
|
|
1447
|
+
const { mapInfo, keySliceDesc, valSliceDesc, keyDesc, valDesc } = desc;
|
|
1412
1448
|
const makeIdx = mod.resolveFuncIndex(mapInfo.makeFuncName);
|
|
1413
1449
|
addFunc(
|
|
1414
1450
|
`__map_new_${key}`,
|
|
@@ -1419,12 +1455,16 @@ export function addBoundaryHelpers(mod, meta) {
|
|
|
1419
1455
|
const setIdx = mod.resolveFuncIndex(mapInfo.setFuncName);
|
|
1420
1456
|
addFunc(
|
|
1421
1457
|
`__map_set_${key}`,
|
|
1422
|
-
[
|
|
1458
|
+
[
|
|
1459
|
+
EXT,
|
|
1460
|
+
extType(mapInfo.keyWType, keyDesc?.is64),
|
|
1461
|
+
extType(mapInfo.valWType, valDesc?.is64),
|
|
1462
|
+
],
|
|
1423
1463
|
[],
|
|
1424
1464
|
[
|
|
1425
1465
|
...getIn(0, desc.wType),
|
|
1426
|
-
...getIn(1, mapInfo.keyWType),
|
|
1427
|
-
...getIn(2, mapInfo.valWType),
|
|
1466
|
+
...getIn(1, mapInfo.keyWType, keyDesc?.is64),
|
|
1467
|
+
...getIn(2, mapInfo.valWType, valDesc?.is64),
|
|
1428
1468
|
{ op: "call", funcIndex: setIdx },
|
|
1429
1469
|
],
|
|
1430
1470
|
);
|
|
@@ -1483,80 +1523,27 @@ export function addBoundaryHelpers(mod, meta) {
|
|
|
1483
1523
|
);
|
|
1484
1524
|
}
|
|
1485
1525
|
|
|
1486
|
-
if (needs.time) {
|
|
1487
|
-
const timeInfo = mod.getStructType("time.Time");
|
|
1488
|
-
if (timeInfo) {
|
|
1489
|
-
const timeWType = toRef(timeInfo);
|
|
1490
|
-
addFunc(
|
|
1491
|
-
"__time_make",
|
|
1492
|
-
["f64", "i32"],
|
|
1493
|
-
[EXT],
|
|
1494
|
-
[
|
|
1495
|
-
get(0),
|
|
1496
|
-
{ op: "i64.trunc_sat_f64_s" },
|
|
1497
|
-
{ op: "i64.const", value: 1000000n },
|
|
1498
|
-
{ op: "i64.mul" },
|
|
1499
|
-
get(1),
|
|
1500
|
-
{ op: "ref.null", heapType: "any" },
|
|
1501
|
-
{ op: "struct.new", typeIndex: timeInfo.typeIndex },
|
|
1502
|
-
...toExt(timeWType),
|
|
1503
|
-
],
|
|
1504
|
-
);
|
|
1505
|
-
addFunc(
|
|
1506
|
-
"__time_unix_milli",
|
|
1507
|
-
[EXT],
|
|
1508
|
-
["f64"],
|
|
1509
|
-
[
|
|
1510
|
-
get(0),
|
|
1511
|
-
{ op: "ref.is_null" },
|
|
1512
|
-
{ op: "if", blockType: "f64" },
|
|
1513
|
-
{ op: "f64.const", value: 0 },
|
|
1514
|
-
{ op: "else" },
|
|
1515
|
-
...getIn(0, timeWType),
|
|
1516
|
-
{ op: "struct.get", typeIndex: timeInfo.typeIndex, fieldIndex: 0 },
|
|
1517
|
-
{ op: "i64.const", value: 1000000n },
|
|
1518
|
-
{ op: "i64.div_s" },
|
|
1519
|
-
{ op: "f64.convert_i64_s" },
|
|
1520
|
-
{ op: "end" },
|
|
1521
|
-
],
|
|
1522
|
-
);
|
|
1523
|
-
addFunc(
|
|
1524
|
-
"__time_offset",
|
|
1525
|
-
[EXT],
|
|
1526
|
-
["i32"],
|
|
1527
|
-
[
|
|
1528
|
-
get(0),
|
|
1529
|
-
{ op: "ref.is_null" },
|
|
1530
|
-
{ op: "if", blockType: "i32" },
|
|
1531
|
-
{ op: "i32.const", value: 0 },
|
|
1532
|
-
{ op: "else" },
|
|
1533
|
-
...getIn(0, timeWType),
|
|
1534
|
-
{ op: "struct.get", typeIndex: timeInfo.typeIndex, fieldIndex: 1 },
|
|
1535
|
-
{ op: "end" },
|
|
1536
|
-
],
|
|
1537
|
-
);
|
|
1538
|
-
}
|
|
1539
|
-
}
|
|
1540
|
-
|
|
1541
1526
|
for (const c of meta.consts ?? []) {
|
|
1542
1527
|
if (!c.dynamic) continue;
|
|
1543
1528
|
const g = mod.resolveGlobal(c.name);
|
|
1544
1529
|
if (!g) continue;
|
|
1530
|
+
const is64 = Boolean(c.desc?.is64);
|
|
1545
1531
|
addFunc(
|
|
1546
1532
|
`__const_${c.name}`,
|
|
1547
1533
|
[],
|
|
1548
|
-
[extType(c.desc.wType)],
|
|
1549
|
-
[{ op: "global.get", index: g.index }, ...toExt(c.desc.wType)],
|
|
1534
|
+
[extType(c.desc.wType, is64)],
|
|
1535
|
+
[{ op: "global.get", index: g.index }, ...toExt(c.desc.wType, is64)],
|
|
1550
1536
|
);
|
|
1551
1537
|
}
|
|
1552
1538
|
for (const v of meta.vars ?? []) {
|
|
1553
1539
|
const g = v.shared ? null : mod.resolveGlobal(v.name);
|
|
1554
1540
|
if (!g) continue;
|
|
1541
|
+
const is64 = Boolean(v.desc?.is64);
|
|
1555
1542
|
addFunc(
|
|
1556
1543
|
`__var_${v.name}`,
|
|
1557
1544
|
[],
|
|
1558
|
-
[extType(v.desc.wType)],
|
|
1559
|
-
[{ op: "global.get", index: g.index }, ...toExt(v.desc.wType)],
|
|
1545
|
+
[extType(v.desc.wType, is64)],
|
|
1546
|
+
[{ op: "global.get", index: g.index }, ...toExt(v.desc.wType, is64)],
|
|
1560
1547
|
);
|
|
1561
1548
|
}
|
|
1562
1549
|
}
|
|
@@ -1625,6 +1612,13 @@ function addIfaceHelpers(desc, mod, addFunc, addTrampoline) {
|
|
|
1625
1612
|
|
|
1626
1613
|
const P = "__gfw_"; // facade helper prefix
|
|
1627
1614
|
|
|
1615
|
+
// Pieces of the strings host imports (written for use inside the templates
|
|
1616
|
+
// below, where a backslash escape must be doubled).
|
|
1617
|
+
const GO_SPACE =
|
|
1618
|
+
"[ \\t\\n\\v\\f\\r\\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]";
|
|
1619
|
+
const BAD_RUNE = "r < 0 || r > 0x10FFFF || (r >= 0xD800 && r <= 0xDFFF)";
|
|
1620
|
+
const SURROGATE = "(v >= 0xD800 && v <= 0xDFFF)";
|
|
1621
|
+
|
|
1628
1622
|
// JS expression converting JS value `v` into the wasm representation.
|
|
1629
1623
|
function inExpr(desc, v) {
|
|
1630
1624
|
switch (desc.k) {
|
|
@@ -1633,7 +1627,7 @@ function inExpr(desc, v) {
|
|
|
1633
1627
|
case "i32":
|
|
1634
1628
|
return `(${v} | 0)`;
|
|
1635
1629
|
case "i64":
|
|
1636
|
-
return `${P}i64in(${v})`;
|
|
1630
|
+
return desc.is64 ? `BigInt(${v})` : `${P}i64in(${v})`;
|
|
1637
1631
|
case "f32":
|
|
1638
1632
|
case "f64":
|
|
1639
1633
|
return `(+${v})`;
|
|
@@ -1647,8 +1641,6 @@ function inExpr(desc, v) {
|
|
|
1647
1641
|
return `${P}f32x4in(${v})`;
|
|
1648
1642
|
case "mask4":
|
|
1649
1643
|
return `${P}mask4in(${v})`;
|
|
1650
|
-
case "time":
|
|
1651
|
-
return desc.ptr ? `${P}timein_ptr(${v})` : `${P}timein(${v})`;
|
|
1652
1644
|
case "map":
|
|
1653
1645
|
return `${P}mapin_${desc.key}(${v})`;
|
|
1654
1646
|
case "ptr_box":
|
|
@@ -1686,6 +1678,10 @@ function outExpr(desc, v) {
|
|
|
1686
1678
|
case "i32":
|
|
1687
1679
|
return desc.unsigned ? `(${v} >>> 0)` : v;
|
|
1688
1680
|
case "i64":
|
|
1681
|
+
if (desc.is64)
|
|
1682
|
+
return desc.unsigned
|
|
1683
|
+
? `BigInt.asUintN(64, ${v})`
|
|
1684
|
+
: `BigInt.asIntN(64, ${v})`;
|
|
1689
1685
|
return desc.unsigned ? `${P}u64out(${v})` : `${P}i64out(${v})`;
|
|
1690
1686
|
case "string":
|
|
1691
1687
|
return `(${v} ?? "")`;
|
|
@@ -1695,8 +1691,6 @@ function outExpr(desc, v) {
|
|
|
1695
1691
|
return `${P}f32x4out(${v})`;
|
|
1696
1692
|
case "mask4":
|
|
1697
1693
|
return `${P}mask4out(${v})`;
|
|
1698
|
-
case "time":
|
|
1699
|
-
return desc.ptr ? `${P}timeout_ptr(${v})` : `${P}timeout(${v})`;
|
|
1700
1694
|
case "map":
|
|
1701
1695
|
return `${P}mapout_${desc.key}(${v})`;
|
|
1702
1696
|
case "ptr_box":
|
|
@@ -1729,10 +1723,11 @@ function zeroExpr(desc) {
|
|
|
1729
1723
|
case "bool":
|
|
1730
1724
|
return "false";
|
|
1731
1725
|
case "i32":
|
|
1732
|
-
case "i64":
|
|
1733
1726
|
case "f32":
|
|
1734
1727
|
case "f64":
|
|
1735
1728
|
return "0";
|
|
1729
|
+
case "i64":
|
|
1730
|
+
return desc.is64 ? "0n" : "0";
|
|
1736
1731
|
case "string":
|
|
1737
1732
|
return '""';
|
|
1738
1733
|
case "f32x4":
|
|
@@ -1740,7 +1735,6 @@ function zeroExpr(desc) {
|
|
|
1740
1735
|
case "mask4":
|
|
1741
1736
|
return "[false, false, false, false]";
|
|
1742
1737
|
case "error":
|
|
1743
|
-
case "time":
|
|
1744
1738
|
case "map":
|
|
1745
1739
|
case "ptr_box":
|
|
1746
1740
|
return "null";
|
|
@@ -1855,14 +1849,11 @@ function indent(text, prefix) {
|
|
|
1855
1849
|
// survive the built-in mangler: no shorthand destructuring, import keys
|
|
1856
1850
|
// quoted, helpers prefixed with `__`.
|
|
1857
1851
|
export const WASM_IMPORTS_JS = `const ${P}MAX = 9007199254740991n;
|
|
1858
|
-
function ${P}imports(stringTable, extraEnv, tag, write) {
|
|
1852
|
+
function ${P}imports(stringTable, extraEnv, tag, write, toStderr) {
|
|
1853
|
+
// Each instance numbers the references fmt_ptr_id is asked about from 1
|
|
1854
|
+
// (the table the JS body of that intrinsic uses).
|
|
1855
|
+
globalThis.__fmtptr = { m: new WeakMap(), n: 1 };
|
|
1859
1856
|
let lineBuf = "";
|
|
1860
|
-
let targs = [];
|
|
1861
|
-
let fmtStructMap = new WeakMap();
|
|
1862
|
-
// A value whose type has String()/Error(): the method already ran in WASM.
|
|
1863
|
-
// __gfUnbox hands fmt the raw value for the other verbs.
|
|
1864
|
-
class FmtStr { constructor(r, s) { this.r = r; this.s = s; } __gfUnbox() { return this.r; } String() { return this.s; } }
|
|
1865
|
-
class FmtErr { constructor(r, s) { this.r = r; this.s = s; } __gfUnbox() { return this.r; } Error() { return this.s; } }
|
|
1866
1857
|
const late = { exports: null };
|
|
1867
1858
|
// Go separates operands with a space unconditionally, so track whether the
|
|
1868
1859
|
// current line already holds an operand (an empty string leaves lineBuf empty).
|
|
@@ -1878,7 +1869,6 @@ function ${P}imports(stringTable, extraEnv, tag, write) {
|
|
|
1878
1869
|
print(v);
|
|
1879
1870
|
flush();
|
|
1880
1871
|
};
|
|
1881
|
-
const targ = (v) => { targs.push(v); };
|
|
1882
1872
|
let utf8Encoded = null;
|
|
1883
1873
|
let convBytes = null, convPos = 0;
|
|
1884
1874
|
const env = {
|
|
@@ -1890,7 +1880,9 @@ function ${P}imports(stringTable, extraEnv, tag, write) {
|
|
|
1890
1880
|
} catch {
|
|
1891
1881
|
str = "[panic object]";
|
|
1892
1882
|
}
|
|
1893
|
-
|
|
1883
|
+
const err = new Error(str);
|
|
1884
|
+
err.__gfp = true;
|
|
1885
|
+
throw err;
|
|
1894
1886
|
},
|
|
1895
1887
|
"str": (i) => stringTable[i] ?? "",
|
|
1896
1888
|
"str_len": (s) => (s ? s.length : 0),
|
|
@@ -1903,7 +1895,7 @@ function ${P}imports(stringTable, extraEnv, tag, write) {
|
|
|
1903
1895
|
"str_ge": (a, b) => ((a ?? "") >= (b ?? "") ? 1 : 0),
|
|
1904
1896
|
"str_get": (s, i) => (s ? s.charCodeAt(i) : 0),
|
|
1905
1897
|
"str_slice": (s, a, b) => (s ? s.slice(a, b) : ""),
|
|
1906
|
-
"str_from_code_point": (c) => String.fromCodePoint(c),
|
|
1898
|
+
"str_from_code_point": (c) => String.fromCodePoint(c >= 0 && c <= 0x10ffff && !(c >= 0xd800 && c <= 0xdfff) ? c : 0xfffd),
|
|
1907
1899
|
"str_code_point_at": (s, i) => (s ? s.codePointAt(i) : 0),
|
|
1908
1900
|
"str_hash": (s) => {
|
|
1909
1901
|
if (!s) return 0;
|
|
@@ -1913,29 +1905,109 @@ function ${P}imports(stringTable, extraEnv, tag, write) {
|
|
|
1913
1905
|
}
|
|
1914
1906
|
return h;
|
|
1915
1907
|
},
|
|
1916
|
-
"str_to_upper": (s) => (s
|
|
1917
|
-
"str_to_lower": (s) => (s
|
|
1918
|
-
"
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
"
|
|
1927
|
-
"
|
|
1928
|
-
"
|
|
1929
|
-
|
|
1930
|
-
if (
|
|
1931
|
-
|
|
1908
|
+
"str_to_upper": (s) => ${P}mapCase(s ?? "", "toUpperCase"),
|
|
1909
|
+
"str_to_lower": (s) => ${P}mapCase(s ?? "", "toLowerCase"),
|
|
1910
|
+
"str_trim_space": (s) => {
|
|
1911
|
+
s = s ?? "";
|
|
1912
|
+
const sp = /${GO_SPACE}/;
|
|
1913
|
+
let i = 0, j = s.length;
|
|
1914
|
+
while (i < j && sp.test(s[i])) i++;
|
|
1915
|
+
while (j > i && sp.test(s[j - 1])) j--;
|
|
1916
|
+
return s.slice(i, j);
|
|
1917
|
+
},
|
|
1918
|
+
"str_contains": (s, sub) => ((s ?? "").includes(sub ?? "") ? 1 : 0),
|
|
1919
|
+
"str_has_prefix": (s, pre) => ((s ?? "").startsWith(pre ?? "") ? 1 : 0),
|
|
1920
|
+
"str_has_suffix": (s, suf) => ((s ?? "").endsWith(suf ?? "") ? 1 : 0),
|
|
1921
|
+
"os_write": (fd, s) => {
|
|
1922
|
+
if (fd === 2 && toStderr && typeof process !== "undefined" && process.stderr?.write) { process.stderr.write(s ?? ""); return; }
|
|
1923
|
+
lineBuf += s ?? "";
|
|
1924
|
+
const nl = lineBuf.lastIndexOf("\\n");
|
|
1925
|
+
if (nl >= 0) { write(lineBuf.slice(0, nl)); lineBuf = lineBuf.slice(nl + 1); }
|
|
1932
1926
|
},
|
|
1927
|
+
"time_now_ms": () => (typeof globalThis.__GOFRONT_CLOCK === "function" ? globalThis.__GOFRONT_CLOCK() : Date.now()),
|
|
1928
|
+
"time_timezone_offset": (ms) => (-new Date(ms).getTimezoneOffset() * 60) | 0,
|
|
1929
|
+
"os_exit": (code) => {
|
|
1930
|
+
if (lineBuf !== "") { write(lineBuf); lineBuf = ""; }
|
|
1931
|
+
if (typeof process !== "undefined" && process.exit) process.exit(code);
|
|
1932
|
+
throw new Error("os.Exit(" + code + ")");
|
|
1933
|
+
},
|
|
1934
|
+
"os_getenv": (k) => (typeof process !== "undefined" && process.env ? process.env : (globalThis.__os_env ??= {}))[k ?? ""] ?? "",
|
|
1935
|
+
"os_setenv": (k, v) => { (typeof process !== "undefined" && process.env ? process.env : (globalThis.__os_env ??= {}))[k ?? ""] = v ?? ""; },
|
|
1936
|
+
"unicode_is": (r, k) => { ${unicodeIsJs("r", "k")} },
|
|
1937
|
+
"unicode_to_upper": (r) => { ${unicodeToUpperJs("r")} },
|
|
1938
|
+
"unicode_to_lower": (r) => { ${unicodeToLowerJs("r")} },
|
|
1939
|
+
"testing_nanotime": () => performance.now() * 1e6,
|
|
1940
|
+
"testing_match": (p, s) => new RegExp(p ?? "").test(s ?? "") ? 1 : 0,
|
|
1941
|
+
"fmt_ptr_id": (o) => {
|
|
1942
|
+
if (o === null || o === undefined || (typeof o !== "object" && typeof o !== "function")) return 0;
|
|
1943
|
+
const t = globalThis.__fmtptr;
|
|
1944
|
+
let id = t.m.get(o);
|
|
1945
|
+
if (!id) { id = t.n++; t.m.set(o, id); }
|
|
1946
|
+
return id;
|
|
1947
|
+
},
|
|
1948
|
+
"crypto_rand_u32": () => {
|
|
1949
|
+
const c = typeof crypto !== "undefined" ? crypto : globalThis.crypto;
|
|
1950
|
+
return c?.getRandomValues ? c.getRandomValues(new Uint32Array(1))[0] | 0 : (Math.random() * 4294967296) | 0;
|
|
1951
|
+
},
|
|
1952
|
+
"strconv_shortest": (f) => f.toExponential(),
|
|
1953
|
+
"strconv_fixed": ${FIXED_FLOAT_JS},
|
|
1954
|
+
"strconv_parse_decimal": (s) => Number((s ?? "").replaceAll("_", "")),
|
|
1955
|
+
"str_index": (s, sub) => (s ?? "").indexOf(sub ?? ""),
|
|
1956
|
+
"str_last_index": (s, sub) => (s ?? "").lastIndexOf(sub ?? ""),
|
|
1957
|
+
"str_index_byte": (s, b) => (s ?? "").indexOf(String.fromCharCode(b)),
|
|
1958
|
+
"str_last_index_byte": (s, b) => (s ?? "").lastIndexOf(String.fromCharCode(b)),
|
|
1959
|
+
"str_index_rune": (s, r) => (${BAD_RUNE} ? -1 : (s ?? "").indexOf(String.fromCodePoint(r))),
|
|
1960
|
+
"str_contains_rune": (s, r) => (!(${BAD_RUNE}) && (s ?? "").includes(String.fromCodePoint(r)) ? 1 : 0),
|
|
1961
|
+
"str_index_any": (s, cs) => {
|
|
1962
|
+
s = s ?? "";
|
|
1963
|
+
let m = -1;
|
|
1964
|
+
for (const c of (cs ?? "")) {
|
|
1965
|
+
const v = c.codePointAt(0);
|
|
1966
|
+
if (${SURROGATE}) continue;
|
|
1967
|
+
const i = s.indexOf(c);
|
|
1968
|
+
if (i >= 0 && (m < 0 || i < m)) m = i;
|
|
1969
|
+
}
|
|
1970
|
+
return m;
|
|
1971
|
+
},
|
|
1972
|
+
"str_last_index_any": (s, cs) => {
|
|
1973
|
+
s = s ?? "";
|
|
1974
|
+
let m = -1;
|
|
1975
|
+
for (const c of (cs ?? "")) {
|
|
1976
|
+
const v = c.codePointAt(0);
|
|
1977
|
+
if (${SURROGATE}) continue;
|
|
1978
|
+
const i = s.lastIndexOf(c);
|
|
1979
|
+
if (i > m) m = i;
|
|
1980
|
+
}
|
|
1981
|
+
return m;
|
|
1982
|
+
},
|
|
1983
|
+
"str_contains_any": (s, cs) => {
|
|
1984
|
+
s = s ?? "";
|
|
1985
|
+
for (const c of (cs ?? "")) {
|
|
1986
|
+
const v = c.codePointAt(0);
|
|
1987
|
+
if (!${SURROGATE} && s.includes(c)) return 1;
|
|
1988
|
+
}
|
|
1989
|
+
return 0;
|
|
1990
|
+
},
|
|
1991
|
+
"str_count": (s, t) => {
|
|
1992
|
+
s = s ?? ""; t = t ?? "";
|
|
1993
|
+
if (t === "") return [...s].length + 1;
|
|
1994
|
+
let n = 0;
|
|
1995
|
+
for (let i = s.indexOf(t); i !== -1; i = s.indexOf(t, i + t.length)) n++;
|
|
1996
|
+
return n;
|
|
1997
|
+
},
|
|
1998
|
+
"str_replace": (s, o, w, n) => ${P}replace(s ?? "", o ?? "", w ?? "", n),
|
|
1999
|
+
"str_replace_all": (s, o, w) => ${P}replace(s ?? "", o ?? "", w ?? "", -1),
|
|
2000
|
+
"str_trim": (s, c) => ${P}trim(s ?? "", c ?? "", true, true),
|
|
2001
|
+
"str_trim_left": (s, c) => ${P}trim(s ?? "", c ?? "", true, false),
|
|
2002
|
+
"str_trim_right": (s, c) => ${P}trim(s ?? "", c ?? "", false, true),
|
|
2003
|
+
"str_trim_prefix": (s, p) => ((s ?? "").startsWith(p ?? "") ? (s ?? "").slice((p ?? "").length) : (s ?? "")),
|
|
2004
|
+
"str_trim_suffix": (s, p) => ((s ?? "").endsWith(p ?? "") ? (s ?? "").slice(0, (s ?? "").length - (p ?? "").length) : (s ?? "")),
|
|
1933
2005
|
"str_from_i64": (n) => String(n),
|
|
1934
2006
|
"str_from_i32": (n) => String(n),
|
|
1935
2007
|
"str_from_f64": (f) => (Object.is(f, -0) ? "-0" : String(f)),
|
|
1936
2008
|
"is_string": (v) => (typeof v === "string" ? 1 : 0),
|
|
1937
2009
|
"str_to_bytes": (s) => {
|
|
1938
|
-
utf8Encoded =
|
|
2010
|
+
utf8Encoded = ${P}u8enc(s ?? "");
|
|
1939
2011
|
return utf8Encoded.length;
|
|
1940
2012
|
},
|
|
1941
2013
|
"str_byte_at": (i) => (utf8Encoded ? (utf8Encoded[i] ?? 0) : 0),
|
|
@@ -1955,767 +2027,127 @@ function ${P}imports(stringTable, extraEnv, tag, write) {
|
|
|
1955
2027
|
},
|
|
1956
2028
|
"print_i32": print, "print_i64": print, "print_f32": print, "print_f64": print,
|
|
1957
2029
|
"print_str": print, "print_any": print,
|
|
2030
|
+
"print_u64": (v) => print(BigInt.asUintN(64, v)),
|
|
2031
|
+
"println_u64": (v) => println(BigInt.asUintN(64, v)),
|
|
2032
|
+
"print_reset": () => { started = false; },
|
|
1958
2033
|
"print_bool": (b) => print(b !== 0 ? "true" : "false"),
|
|
1959
2034
|
"println_i32": println, "println_i64": println, "println_f32": println, "println_f64": println,
|
|
1960
2035
|
"println_str": println, "println_any": println,
|
|
1961
2036
|
"println_bool": (b) => println(b !== 0 ? "true" : "false"),
|
|
1962
2037
|
"println_empty": flush,
|
|
1963
|
-
"fmt_new_array": () => [],
|
|
1964
|
-
"fmt_array_push": (arr, v) => { arr.push(v); },
|
|
1965
|
-
"fmt_new_map": () => new Map(),
|
|
1966
|
-
"fmt_map_set": (m, k, v) => { m.set(k, v); },
|
|
1967
|
-
"fmt_new_struct": (ref, isPtr) => {
|
|
1968
|
-
// One object per struct and per kind: a value and a pointer to it
|
|
1969
|
-
// in the same call (fmt.Println(&s, s)) must stay distinct.
|
|
1970
|
-
const slot = isPtr;
|
|
1971
|
-
if (isPtr === 2) {
|
|
1972
|
-
const seenBox = ref !== null && ref !== undefined && typeof ref === "object" ? fmtStructMap.get(ref) : undefined;
|
|
1973
|
-
if (seenBox?.[2]) return seenBox[2];
|
|
1974
|
-
const b = { value: null, __p: true, __box: true };
|
|
1975
|
-
if (ref !== null && ref !== undefined && typeof ref === "object") {
|
|
1976
|
-
if (seenBox) seenBox[2] = b;
|
|
1977
|
-
else fmtStructMap.set(ref, [undefined, undefined, b]);
|
|
1978
|
-
}
|
|
1979
|
-
return b;
|
|
1980
|
-
}
|
|
1981
|
-
const isRef = ref !== null && ref !== undefined && typeof ref === "object";
|
|
1982
|
-
const seen = isRef ? fmtStructMap.get(ref) : undefined;
|
|
1983
|
-
if (seen?.[slot]) return seen[slot];
|
|
1984
|
-
const o = {};
|
|
1985
|
-
Object.defineProperty(o, "__struct", { value: true, configurable: true });
|
|
1986
|
-
if (isPtr !== 0) Object.defineProperty(o, "__p", { value: true, configurable: true });
|
|
1987
|
-
if (isRef) {
|
|
1988
|
-
if (seen) seen[slot] = o;
|
|
1989
|
-
else fmtStructMap.set(ref, slot ? [undefined, o] : [o, undefined]);
|
|
1990
|
-
}
|
|
1991
|
-
return o;
|
|
1992
|
-
},
|
|
1993
|
-
"fmt_struct_type": (o, i) => { Object.defineProperty(o, "__tn", { value: stringTable[i], configurable: true }); },
|
|
1994
|
-
"fmt_struct_set": (o, k, v) => { o[typeof k === "number" ? stringTable[k] : k] = v; },
|
|
1995
|
-
"fmt_box_i32": (v) => v,
|
|
1996
|
-
"fmt_box_i64": (v) => (v > ${P}MAX || v < -${P}MAX ? v : Number(v)),
|
|
1997
|
-
"fmt_box_u64": (v) => { v = BigInt.asUintN(64, v); return v > ${P}MAX ? v : Number(v); },
|
|
1998
|
-
"fmt_box_f64": (v) => v,
|
|
1999
|
-
"fmt_box_bool": (v) => v !== 0,
|
|
2000
|
-
"fmt_new_stringer": (r, s, isErr) => (isErr !== 0 ? new FmtErr(r, s) : new FmtStr(r, s)),
|
|
2001
|
-
"fmt_new_box": () => ({ value: null, __p: true, __box: true }),
|
|
2002
|
-
"testing_arg_i32": targ, "testing_arg_f32": targ, "testing_arg_f64": targ,
|
|
2003
|
-
"testing_arg_str": targ, "testing_arg_any": targ,
|
|
2004
|
-
"testing_arg_i64": (v) => targ(v > ${P}MAX || v < -${P}MAX ? v : Number(v)),
|
|
2005
|
-
"testing_arg_bool": (v) => targ(v !== 0),
|
|
2006
|
-
"testing_arg_u64": (v) => { v = BigInt.asUintN(64, v); targ(v > ${P}MAX ? v : Number(v)); },
|
|
2007
|
-
"fmt_arg_type": (i) => { if (targs.length > 0) targs[targs.length - 1] = __ft(targs[targs.length - 1], JSON.parse(stringTable[i])); },
|
|
2008
|
-
"testing_arg_spread": (a) => { if (a) for (const v of a) targs.push(v); },
|
|
2009
|
-
"testing_arg_err": (s) => targ({ Error() { return s; } }),
|
|
2010
|
-
"testing_call": (t, i) => { const a = targs; targs = []; fmtStructMap = new WeakMap(); t[stringTable[i]](...a); },
|
|
2011
|
-
"testing_name": (t) => t.Name(),
|
|
2012
|
-
"testing_flag": (t, i) => Number(t[stringTable[i]]()),
|
|
2013
|
-
"testing_n": (t) => BigInt(t.N ?? 0),
|
|
2014
|
-
"testing_elapsed": (t) => BigInt(t.Elapsed()),
|
|
2015
|
-
"testing_context": (t) => t.Context(),
|
|
2016
|
-
"testing_output": (t) => t.Output(),
|
|
2017
2038
|
};
|
|
2018
|
-
// Stdlib imports (strings/strconv/utf8/fmt/t.Run) are a separate block so
|
|
2019
|
-
// modules that never call them do not ship it (see WASM_STDLIB_JS).
|
|
2020
|
-
if (typeof ${P}stdlib === "function") {
|
|
2021
|
-
Object.assign(env, ${P}stdlib(stringTable, {
|
|
2022
|
-
"take": () => { const a = targs; targs = []; fmtStructMap = new WeakMap(); return a; },
|
|
2023
|
-
"printf": (s) => {
|
|
2024
|
-
lineBuf += s;
|
|
2025
|
-
const nl = lineBuf.lastIndexOf("\\n");
|
|
2026
|
-
if (nl >= 0) { write(lineBuf.slice(0, nl)); lineBuf = lineBuf.slice(nl + 1); }
|
|
2027
|
-
},
|
|
2028
|
-
"late": late,
|
|
2029
|
-
}));
|
|
2030
|
-
}
|
|
2031
2039
|
Object.assign(env, extraEnv);
|
|
2040
|
+
// A host import that throws raises a Go panic: the module's panic stack
|
|
2041
|
+
// gets the message (as env.panic does through __push_panic) before the
|
|
2042
|
+
// error unwinds, so recover() in a calling frame sees it. Errors already
|
|
2043
|
+
// pushed (env.panic, nested calls into the module) are marked and pass
|
|
2044
|
+
// through; traps and wasm exceptions are not host panics.
|
|
2045
|
+
const hostPanic = (e) => {
|
|
2046
|
+
if (e !== null && typeof e === "object") {
|
|
2047
|
+
if (e.__gfp === true) return;
|
|
2048
|
+
if (typeof WebAssembly !== "undefined" && (e instanceof WebAssembly.Exception || e instanceof WebAssembly.RuntimeError)) return;
|
|
2049
|
+
try { e.__gfp = true; } catch {}
|
|
2050
|
+
}
|
|
2051
|
+
const push = late.exports && late.exports.__push_panic;
|
|
2052
|
+
if (push) push(String(e !== null && typeof e === "object" && e.message !== undefined ? e.message : e));
|
|
2053
|
+
};
|
|
2054
|
+
for (const k of Object.keys(env)) {
|
|
2055
|
+
const fn = env[k];
|
|
2056
|
+
if (typeof fn !== "function" || k === "panic" || k === "panicTag") continue;
|
|
2057
|
+
env[k] = function () {
|
|
2058
|
+
try { return fn.apply(this, arguments); } catch (e) { hostPanic(e); throw e; }
|
|
2059
|
+
};
|
|
2060
|
+
}
|
|
2032
2061
|
const m = {};
|
|
2033
2062
|
for (const k of ["sin", "cos", "tan", "asin", "acos", "atan", "atan2", "pow", "exp", "log", "log2", "log10", "cbrt", "hypot", "random", "sinh", "cosh", "tanh", "log1p", "expm1"]) m[k] = Math[k];
|
|
2034
2063
|
m.mod = (x, y) => x % y;
|
|
2035
2064
|
// Go rounds half away from zero; Math.round rounds half toward +Infinity.
|
|
2036
2065
|
m.round = (x) => Math.sign(x) * Math.round(Math.abs(x));
|
|
2037
2066
|
// Exports are needed by imports that call back into the module (t.Run).
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
${HELPER_PATH_CLEAN}
|
|
2048
|
-
${HELPER_DURATION}
|
|
2049
|
-
${HELPER_SHA256}
|
|
2050
|
-
${HELPER_HEX}
|
|
2051
|
-
${HELPER_BASE64}
|
|
2052
|
-
function ${P}stdlib_fmt(stringTable, io) {
|
|
2053
|
-
let sscanTokens = [];
|
|
2054
|
-
let sscanHasErr = 0, sscanErrMsg = "";
|
|
2055
|
-
return {
|
|
2056
|
-
"fmt_sscan_init": (s, mode) => {
|
|
2057
|
-
sscanHasErr = 0;
|
|
2058
|
-
sscanErrMsg = "";
|
|
2059
|
-
const str = s ?? "";
|
|
2060
|
-
sscanTokens = (mode === 1 ? str.split("\\n")[0] : str).trim().split(/\\s+/).filter(Boolean);
|
|
2061
|
-
return sscanTokens.length;
|
|
2062
|
-
},
|
|
2063
|
-
"fmt_sscanf_init": (s, fmt) => {
|
|
2064
|
-
sscanHasErr = 0;
|
|
2065
|
-
sscanErrMsg = "";
|
|
2066
|
-
const str = s ?? "";
|
|
2067
|
-
const fmtStr = fmt ?? "";
|
|
2068
|
-
let si = 0, fi = 0;
|
|
2069
|
-
sscanTokens = [];
|
|
2070
|
-
while (fi < fmtStr.length) {
|
|
2071
|
-
if (/\\s/.test(fmtStr[fi])) {
|
|
2072
|
-
while (fi < fmtStr.length && /\\s/.test(fmtStr[fi])) fi++;
|
|
2073
|
-
while (si < str.length && /\\s/.test(str[si])) si++;
|
|
2074
|
-
continue;
|
|
2075
|
-
}
|
|
2076
|
-
if (fmtStr[fi] === "%") {
|
|
2077
|
-
if (fi + 1 < fmtStr.length && fmtStr[fi + 1] === "%") {
|
|
2078
|
-
if (str[si] !== "%") {
|
|
2079
|
-
sscanHasErr = 1;
|
|
2080
|
-
sscanErrMsg = "input does not match format";
|
|
2081
|
-
break;
|
|
2082
|
-
}
|
|
2083
|
-
si++;
|
|
2084
|
-
fi += 2;
|
|
2085
|
-
continue;
|
|
2086
|
-
}
|
|
2087
|
-
const vm = fmtStr.slice(fi).match(/^%[vdsfqtxXbcoeEfFgG]/);
|
|
2088
|
-
if (vm) {
|
|
2089
|
-
const verb = vm[0];
|
|
2090
|
-
fi += verb.length;
|
|
2091
|
-
if (verb !== "%c") {
|
|
2092
|
-
while (si < str.length && /\\s/.test(str[si])) si++;
|
|
2093
|
-
}
|
|
2094
|
-
if (si >= str.length) break;
|
|
2095
|
-
let tokRe = /^\\S+/;
|
|
2096
|
-
if (verb === "%d" || verb === "%i") tokRe = /^[+-]?\\d+/;
|
|
2097
|
-
else if (verb === "%f" || verb === "%F" || verb === "%e" || verb === "%E" || verb === "%g" || verb === "%G") tokRe = /^[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[eE][+-]?\\d+)?/;
|
|
2098
|
-
else if (verb === "%t") tokRe = /^(?:true|false|1|0|t|f|T|F|TRUE|FALSE)/;
|
|
2099
|
-
else if (verb === "%x" || verb === "%X") tokRe = /^[+-]?(?:0x)?[0-9a-fA-F]+/;
|
|
2100
|
-
else if (verb === "%c") tokRe = /^[\\s\\S]/;
|
|
2101
|
-
const m = str.slice(si).match(tokRe);
|
|
2102
|
-
if (!m) {
|
|
2103
|
-
sscanHasErr = 1;
|
|
2104
|
-
sscanErrMsg = "input does not match format";
|
|
2105
|
-
break;
|
|
2106
|
-
}
|
|
2107
|
-
sscanTokens.push(m[0]);
|
|
2108
|
-
si += m[0].length;
|
|
2109
|
-
continue;
|
|
2110
|
-
}
|
|
2111
|
-
}
|
|
2112
|
-
if (si >= str.length) break;
|
|
2113
|
-
if (str[si] !== fmtStr[fi]) {
|
|
2114
|
-
sscanHasErr = 1;
|
|
2115
|
-
sscanErrMsg = "input does not match format";
|
|
2116
|
-
break;
|
|
2117
|
-
}
|
|
2118
|
-
si++;
|
|
2119
|
-
fi++;
|
|
2120
|
-
}
|
|
2121
|
-
return sscanTokens.length;
|
|
2122
|
-
},
|
|
2123
|
-
"fmt_sscan_has_err": () => sscanHasErr,
|
|
2124
|
-
"fmt_sscan_err_msg": () => sscanErrMsg || "syntax error",
|
|
2125
|
-
"fmt_sscan_token_str": (i) => sscanTokens[i] ?? "",
|
|
2126
|
-
"fmt_sscan_token_i64": (i) => {
|
|
2127
|
-
if (i >= sscanTokens.length) { sscanHasErr = 1; sscanErrMsg = "unexpected EOF"; return 0n; }
|
|
2128
|
-
const t = sscanTokens[i];
|
|
2129
|
-
if (/^[+-]?(?:0[xX])?[0-9a-fA-F]+$/.test(t)) {
|
|
2130
|
-
try {
|
|
2131
|
-
if (/^[+-]?[0-9a-fA-F]+$/.test(t) && /[a-fA-F]/.test(t)) {
|
|
2132
|
-
return BigInt("0x" + t);
|
|
2133
|
-
}
|
|
2134
|
-
return BigInt(t);
|
|
2135
|
-
} catch {}
|
|
2136
|
-
}
|
|
2137
|
-
if (t.length === 1) {
|
|
2138
|
-
return BigInt(t.charCodeAt(0));
|
|
2139
|
-
}
|
|
2140
|
-
sscanHasErr = 1;
|
|
2141
|
-
sscanErrMsg = "expected integer";
|
|
2142
|
-
return 0n;
|
|
2143
|
-
},
|
|
2144
|
-
"fmt_sscan_token_f64": (i) => {
|
|
2145
|
-
if (i >= sscanTokens.length) { sscanHasErr = 1; sscanErrMsg = "unexpected EOF"; return 0; }
|
|
2146
|
-
const t = sscanTokens[i];
|
|
2147
|
-
const n = Number(t);
|
|
2148
|
-
if (Number.isNaN(n) || !/^[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[eE][+-]?\\d+)?$/.test(t)) {
|
|
2149
|
-
sscanHasErr = 1;
|
|
2150
|
-
sscanErrMsg = "expected float";
|
|
2151
|
-
return 0;
|
|
2152
|
-
}
|
|
2153
|
-
return n;
|
|
2154
|
-
},
|
|
2155
|
-
"fmt_sscan_token_bool": (i) => {
|
|
2156
|
-
if (i >= sscanTokens.length) { sscanHasErr = 1; sscanErrMsg = "unexpected EOF"; return 0; }
|
|
2157
|
-
const t = sscanTokens[i]?.toLowerCase();
|
|
2158
|
-
if (t === "true" || t === "1" || t === "t") return 1;
|
|
2159
|
-
if (t === "false" || t === "0" || t === "f") return 0;
|
|
2160
|
-
sscanHasErr = 1;
|
|
2161
|
-
sscanErrMsg = "expected boolean";
|
|
2162
|
-
return 0;
|
|
2163
|
-
},
|
|
2164
|
-
"testing_run": (t, name, fn) => (t.Run(name, (sub) => { io.late.exports.__testing_run_cb(fn, sub); }) ? 1 : 0),
|
|
2165
|
-
"testing_cleanup": (t, fn) => { t.Cleanup(() => { io.late.exports.__testing_cleanup_cb(fn); }); },
|
|
2166
|
-
"testing_n": (t) => BigInt(t.N ?? 0),
|
|
2167
|
-
"testing_elapsed": (t) => BigInt(t.Elapsed()),
|
|
2168
|
-
"testing_context": (t) => t.Context(),
|
|
2169
|
-
"testing_output": (t) => t.Output(),
|
|
2170
|
-
"fmt_sprintf": (f) => __sprintf(f ?? "", ...io.take()),
|
|
2171
|
-
"fmt_sprint": (ln) => __sprint(ln !== 0, ...io.take()),
|
|
2172
|
-
"fmt_print": (ln) => { io.printf(__sprint(ln !== 0, ...io.take())); },
|
|
2173
|
-
"fmt_print_raw": (s) => { io.printf(s ?? ""); },
|
|
2174
|
-
"fmt_printf": (f) => { io.printf(__sprintf(f ?? "", ...io.take())); },
|
|
2175
|
-
"fmt_format_v": (v) => { const res = __sprintf("%v", v); io.take(); return res; },
|
|
2176
|
-
};
|
|
2177
|
-
}
|
|
2178
|
-
function ${P}stdlib_str(stringTable, io) {
|
|
2179
|
-
let parts = [];
|
|
2180
|
-
let cutBefore = "", cutAfter = "";
|
|
2181
|
-
let replacerTarget = "", replacerPairs = [];
|
|
2182
|
-
let strconvErr = null, strconvErrKind = 0;
|
|
2183
|
-
let decodeSize = 0;
|
|
2184
|
-
return {
|
|
2185
|
-
"str_trim": (s, c) => ${P}trim(s ?? "", c ?? "", true, true),
|
|
2186
|
-
"str_trim_left": (s, c) => ${P}trim(s ?? "", c ?? "", true, false),
|
|
2187
|
-
"str_trim_right": (s, c) => ${P}trim(s ?? "", c ?? "", false, true),
|
|
2188
|
-
"str_trim_prefix": (s, p) => (s && p && s.startsWith(p) ? s.slice(p.length) : (s ?? "")),
|
|
2189
|
-
"str_trim_suffix": (s, p) => (s && p && s.endsWith(p) ? s.slice(0, s.length - p.length) : (s ?? "")),
|
|
2190
|
-
"str_cut": (s, sep) => {
|
|
2191
|
-
const i = (s ?? "").indexOf(sep ?? "");
|
|
2192
|
-
if (i < 0) { cutBefore = s ?? ""; cutAfter = ""; return 0; }
|
|
2193
|
-
cutBefore = (s ?? "").slice(0, i);
|
|
2194
|
-
cutAfter = (s ?? "").slice(i + (sep ?? "").length);
|
|
2195
|
-
return 1;
|
|
2196
|
-
},
|
|
2197
|
-
"str_cut_before": () => cutBefore,
|
|
2198
|
-
"str_cut_after": () => cutAfter,
|
|
2199
|
-
"str_cut_prefix": (s, p) => {
|
|
2200
|
-
s = s ?? ""; p = p ?? "";
|
|
2201
|
-
if (s.startsWith(p)) { cutAfter = s.slice(p.length); return 1; }
|
|
2202
|
-
cutAfter = s; return 0;
|
|
2203
|
-
},
|
|
2204
|
-
"str_cut_suffix": (s, suf) => {
|
|
2205
|
-
s = s ?? ""; suf = suf ?? "";
|
|
2206
|
-
if (s.endsWith(suf)) { cutBefore = s.slice(0, s.length - suf.length); return 1; }
|
|
2207
|
-
cutBefore = s; return 0;
|
|
2208
|
-
},
|
|
2209
|
-
"str_replace": (s, o, n, cnt) => {
|
|
2210
|
-
s = s ?? ""; o = o ?? ""; n = n ?? "";
|
|
2211
|
-
if (cnt < 0) return s.replaceAll(o, n);
|
|
2212
|
-
let out = "", from = 0;
|
|
2213
|
-
for (let k = 0; k < cnt; k++) {
|
|
2214
|
-
const at = s.indexOf(o, from);
|
|
2215
|
-
if (at < 0) break;
|
|
2216
|
-
out += s.slice(from, at) + n;
|
|
2217
|
-
from = at + o.length;
|
|
2218
|
-
if (o === "") { if (from >= s.length) break; out += s[from]; from++; }
|
|
2219
|
-
}
|
|
2220
|
-
return out + s.slice(from);
|
|
2221
|
-
},
|
|
2222
|
-
"str_contains_rune": (s, r) => ((s ?? "").includes(String.fromCodePoint(r)) ? 1 : 0),
|
|
2223
|
-
"str_contains_any": (s, cs) => { for (const c of (cs ?? "")) if ((s ?? "").includes(c)) return 1; return 0; },
|
|
2224
|
-
"str_index_byte": (s, b) => (s ?? "").indexOf(String.fromCharCode(b)),
|
|
2225
|
-
"str_index_rune": (s, r) => (s ?? "").indexOf(String.fromCodePoint(r)),
|
|
2226
|
-
"str_index_any": (s, cs) => { s = s ?? ""; let best = -1; for (const c of (cs ?? "")) { const i = s.indexOf(c); if (i >= 0 && (best < 0 || i < best)) best = i; } return best; },
|
|
2227
|
-
"str_last_index_byte": (s, b) => (s ?? "").lastIndexOf(String.fromCharCode(b)),
|
|
2228
|
-
"str_last_index_any": (s, cs) => {
|
|
2229
|
-
s = s ?? ""; let best = -1;
|
|
2230
|
-
for (const c of (cs ?? "")) {
|
|
2231
|
-
const i = s.lastIndexOf(c);
|
|
2232
|
-
if (i > best) best = i;
|
|
2233
|
-
}
|
|
2234
|
-
return best;
|
|
2235
|
-
},
|
|
2236
|
-
"str_title": (s) => (s ?? "").replace(/(^|[^\\p{L}\\p{N}_'])(\\p{Ll})/gu, (m, a, b) => a + b.toUpperCase()),
|
|
2237
|
-
"str_split": (s, sep) => { parts = (s ?? "").split(sep ?? ""); return parts.length; },
|
|
2238
|
-
"str_split_n": (s, sep, n) => {
|
|
2239
|
-
s = s ?? ""; sep = sep ?? "";
|
|
2240
|
-
if (n === 0) return -1;
|
|
2241
|
-
if (n < 0) { parts = sep === "" ? [...s] : s.split(sep); return parts.length; }
|
|
2242
|
-
if (sep === "") {
|
|
2243
|
-
const chars = [...s];
|
|
2244
|
-
if (chars.length <= n) { parts = chars; return parts.length; }
|
|
2245
|
-
const r = chars.slice(0, n - 1);
|
|
2246
|
-
r.push(chars.slice(n - 1).join(""));
|
|
2247
|
-
parts = r;
|
|
2248
|
-
return parts.length;
|
|
2249
|
-
}
|
|
2250
|
-
const r = [];
|
|
2251
|
-
let cur = s;
|
|
2252
|
-
for (let i = 1; i < n && cur.length; i++) {
|
|
2253
|
-
const j = cur.indexOf(sep);
|
|
2254
|
-
if (j < 0) break;
|
|
2255
|
-
r.push(cur.slice(0, j));
|
|
2256
|
-
cur = cur.slice(j + sep.length);
|
|
2257
|
-
}
|
|
2258
|
-
r.push(cur);
|
|
2259
|
-
parts = r;
|
|
2260
|
-
return parts.length;
|
|
2261
|
-
},
|
|
2262
|
-
"str_split_after": (s, sep) => {
|
|
2263
|
-
s = s ?? ""; sep = sep ?? "";
|
|
2264
|
-
if (sep === "") { parts = [...s]; return parts.length; }
|
|
2265
|
-
const r = [];
|
|
2266
|
-
let cur = s;
|
|
2267
|
-
while (true) {
|
|
2268
|
-
const j = cur.indexOf(sep);
|
|
2269
|
-
if (j < 0) { r.push(cur); break; }
|
|
2270
|
-
r.push(cur.slice(0, j + sep.length));
|
|
2271
|
-
cur = cur.slice(j + sep.length);
|
|
2272
|
-
}
|
|
2273
|
-
parts = r;
|
|
2274
|
-
return parts.length;
|
|
2275
|
-
},
|
|
2276
|
-
"str_split_after_n": (s, sep, n) => {
|
|
2277
|
-
s = s ?? ""; sep = sep ?? "";
|
|
2278
|
-
if (n === 0) return -1;
|
|
2279
|
-
if (sep === "") {
|
|
2280
|
-
const chars = [...s];
|
|
2281
|
-
if (n < 0 || chars.length <= n) parts = chars;
|
|
2282
|
-
else {
|
|
2283
|
-
const r = chars.slice(0, n - 1);
|
|
2284
|
-
r.push(chars.slice(n - 1).join(""));
|
|
2285
|
-
parts = r;
|
|
2286
|
-
}
|
|
2287
|
-
return parts.length;
|
|
2288
|
-
}
|
|
2289
|
-
const r = [];
|
|
2290
|
-
let cur = s;
|
|
2291
|
-
for (let i = 1; (n < 0 || i < n) && cur.length; i++) {
|
|
2292
|
-
const j = cur.indexOf(sep);
|
|
2293
|
-
if (j < 0) break;
|
|
2294
|
-
r.push(cur.slice(0, j + sep.length));
|
|
2295
|
-
cur = cur.slice(j + sep.length);
|
|
2296
|
-
}
|
|
2297
|
-
r.push(cur);
|
|
2298
|
-
parts = r;
|
|
2299
|
-
return parts.length;
|
|
2300
|
-
},
|
|
2301
|
-
"str_fields": (s) => { parts = (s ?? "").split(/[ \\t\\n\\v\\f\\r\\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+/).filter((p) => p !== ""); return parts.length; },
|
|
2302
|
-
"str_part": (i) => parts[i] ?? "",
|
|
2303
|
-
"str_replacer_init": (s) => {
|
|
2304
|
-
replacerTarget = s ?? "";
|
|
2305
|
-
replacerPairs = [];
|
|
2306
|
-
},
|
|
2307
|
-
"str_replacer_add": (o, n) => {
|
|
2308
|
-
replacerPairs.push([o ?? "", n ?? ""]);
|
|
2309
|
-
},
|
|
2310
|
-
"str_replacer_run": () => {
|
|
2311
|
-
let s = replacerTarget;
|
|
2312
|
-
if (!replacerPairs.length || s === "") return s;
|
|
2313
|
-
let out = "";
|
|
2314
|
-
let i = 0;
|
|
2315
|
-
while (i < s.length) {
|
|
2316
|
-
let matched = false;
|
|
2317
|
-
for (let k = 0; k < replacerPairs.length; k++) {
|
|
2318
|
-
const [oldStr, newStr] = replacerPairs[k];
|
|
2319
|
-
if (oldStr.length > 0 && s.startsWith(oldStr, i)) {
|
|
2320
|
-
out += newStr;
|
|
2321
|
-
i += oldStr.length;
|
|
2322
|
-
matched = true;
|
|
2323
|
-
break;
|
|
2324
|
-
}
|
|
2325
|
-
}
|
|
2326
|
-
if (!matched) {
|
|
2327
|
-
out += s[i];
|
|
2328
|
-
i++;
|
|
2329
|
-
}
|
|
2330
|
-
}
|
|
2331
|
-
return out;
|
|
2332
|
-
},
|
|
2333
|
-
"strconv_atoi": (s) => {
|
|
2334
|
-
const r = __strconv_atoi(s ?? "");
|
|
2335
|
-
strconvErr = r[1];
|
|
2336
|
-
strconvErrKind = r[1] ? (r[1].includes("invalid syntax") ? 1 : r[1].includes("value out of range") ? 2 : 0) : 0;
|
|
2337
|
-
return r[0];
|
|
2338
|
-
},
|
|
2339
|
-
"strconv_parse_int": (s, base, bits) => {
|
|
2340
|
-
const r = __strconv_parse_int(s ?? "", base, bits);
|
|
2341
|
-
strconvErr = r[1];
|
|
2342
|
-
strconvErrKind = r[1] ? (r[1].includes("invalid syntax") ? 1 : r[1].includes("value out of range") ? 2 : 0) : 0;
|
|
2343
|
-
return r[0];
|
|
2344
|
-
},
|
|
2345
|
-
"strconv_parse_float": (s) => {
|
|
2346
|
-
const r = __strconv_parse_float(s ?? "");
|
|
2347
|
-
strconvErr = r[1];
|
|
2348
|
-
strconvErrKind = r[1] ? (r[1].includes("invalid syntax") ? 1 : r[1].includes("value out of range") ? 2 : 0) : 0;
|
|
2349
|
-
return r[0];
|
|
2350
|
-
},
|
|
2351
|
-
"strconv_parse_bool": (s) => {
|
|
2352
|
-
const r = __strconv_parse_bool(s ?? "");
|
|
2353
|
-
strconvErr = r[1];
|
|
2354
|
-
strconvErrKind = r[1] ? (r[1].includes("invalid syntax") ? 1 : r[1].includes("value out of range") ? 2 : 0) : 0;
|
|
2355
|
-
return r[0] ? 1 : 0;
|
|
2356
|
-
},
|
|
2357
|
-
"strconv_err": () => strconvErr,
|
|
2358
|
-
"strconv_err_kind": () => strconvErrKind,
|
|
2359
|
-
"strconv_format_float": (f, fmtc, prec, _bits) => __strconv_format_float(f, fmtc, prec),
|
|
2360
|
-
"strconv_format_int": (n, base) => n.toString(base),
|
|
2361
|
-
"strconv_format_uint": (n, base) => BigInt.asUintN(64, BigInt(n)).toString(base),
|
|
2362
|
-
"strconv_parse_uint": (s, base, bits) => {
|
|
2363
|
-
const r = __strconv_parse_uint(s ?? "", base, bits);
|
|
2364
|
-
strconvErr = r[1];
|
|
2365
|
-
strconvErrKind = r[1] ? (r[1].includes("invalid syntax") ? 1 : r[1].includes("value out of range") ? 2 : 0) : 0;
|
|
2366
|
-
return r[0];
|
|
2367
|
-
},
|
|
2368
|
-
"strconv_quote": (s) => JSON.stringify(s ?? ""),
|
|
2369
|
-
"strconv_unquote": (s) => {
|
|
2370
|
-
s = s ?? "";
|
|
2371
|
-
if (s.startsWith("\`") && s.endsWith("\`") && s.length >= 2) {
|
|
2372
|
-
if (s.slice(1, -1).includes("\`")) {
|
|
2373
|
-
strconvErr = "invalid syntax";
|
|
2374
|
-
strconvErrKind = 1;
|
|
2375
|
-
return "";
|
|
2376
|
-
}
|
|
2377
|
-
strconvErr = null;
|
|
2378
|
-
strconvErrKind = 0;
|
|
2379
|
-
return s.slice(1, -1);
|
|
2380
|
-
}
|
|
2381
|
-
try {
|
|
2382
|
-
const v = JSON.parse(s);
|
|
2383
|
-
if (typeof v !== "string") {
|
|
2384
|
-
strconvErr = "invalid syntax";
|
|
2385
|
-
strconvErrKind = 1;
|
|
2386
|
-
return "";
|
|
2387
|
-
}
|
|
2388
|
-
strconvErr = null;
|
|
2389
|
-
strconvErrKind = 0;
|
|
2390
|
-
return v;
|
|
2391
|
-
} catch (e) {
|
|
2392
|
-
strconvErr = "invalid syntax";
|
|
2393
|
-
strconvErrKind = 1;
|
|
2394
|
-
return "";
|
|
2395
|
-
}
|
|
2396
|
-
},
|
|
2397
|
-
"utf8_rune_count": (s) => { let n = 0; for (const _ of (s ?? "")) n++; return n; },
|
|
2398
|
-
"utf8_rune_len": (r) => (r < 0 || r > 0x10ffff || (r >= 0xd800 && r <= 0xdfff) ? -1 : r < 0x80 ? 1 : r < 0x800 ? 2 : r < 0x10000 ? 3 : 4),
|
|
2399
|
-
"utf8_valid_string": (s) => (s ?? "").isWellFormed ? ((s ?? "").isWellFormed() ? 1 : 0) : (/[\\uD800-\\uDFFF]/.test((s ?? "").replace(/[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]/g, "")) ? 0 : 1),
|
|
2400
|
-
"utf8_decode_rune": (s, last) => {
|
|
2401
|
-
s = s ?? "";
|
|
2402
|
-
if (s.length === 0) { decodeSize = 0; return 0xfffd; }
|
|
2403
|
-
let cp;
|
|
2404
|
-
if (last) { const tail = s.codePointAt(s.length - 1); cp = (tail >= 0xdc00 && tail <= 0xdfff && s.length >= 2) ? s.codePointAt(s.length - 2) : tail; }
|
|
2405
|
-
else cp = s.codePointAt(0);
|
|
2406
|
-
if (cp >= 0xd800 && cp <= 0xdfff) { decodeSize = 1; return 0xfffd; }
|
|
2407
|
-
// Size is in UTF-16 code units, matching the JS backend (strings are JS strings).
|
|
2408
|
-
decodeSize = cp > 0xffff ? 2 : 1;
|
|
2409
|
-
return cp;
|
|
2410
|
-
},
|
|
2411
|
-
"utf8_decode_size": () => decodeSize,
|
|
2412
|
-
"utf8_full_rune": (s) => { s = s ?? ""; if (s.length === 0) return 0; const c = s.charCodeAt(0); return (c >= 0xd800 && c <= 0xdbff && s.length < 2) ? 0 : 1; },
|
|
2413
|
-
// unicode
|
|
2414
|
-
"unicode_is_letter": (r) => { const c = (r >= 0 && r <= 0x10ffff) ? String.fromCodePoint(r) : null; return (c && /\\p{L}/u.test(c)) ? 1 : 0; },
|
|
2415
|
-
"unicode_is_digit": (r) => { const c = (r >= 0 && r <= 0x10ffff) ? String.fromCodePoint(r) : null; return (c && /\\p{Nd}/u.test(c)) ? 1 : 0; },
|
|
2416
|
-
"unicode_is_space": (r) => { const c = (r >= 0 && r <= 0x10ffff) ? String.fromCodePoint(r) : null; return (c && /[ \\t\\n\\v\\f\\r\\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]/.test(c)) ? 1 : 0; },
|
|
2417
|
-
"unicode_is_upper": (r) => { const c = (r >= 0 && r <= 0x10ffff) ? String.fromCodePoint(r) : null; return (c && /\\p{Lu}/u.test(c)) ? 1 : 0; },
|
|
2418
|
-
"unicode_is_lower": (r) => { const c = (r >= 0 && r <= 0x10ffff) ? String.fromCodePoint(r) : null; return (c && /\\p{Ll}/u.test(c)) ? 1 : 0; },
|
|
2419
|
-
"unicode_is_punct": (r) => { const c = (r >= 0 && r <= 0x10ffff) ? String.fromCodePoint(r) : null; return (c && /\\p{P}/u.test(c)) ? 1 : 0; },
|
|
2420
|
-
"unicode_is_control": (r) => { const c = (r >= 0 && r <= 0x10ffff) ? String.fromCodePoint(r) : null; return (c && /\\p{Cc}/u.test(c)) ? 1 : 0; },
|
|
2421
|
-
"unicode_is_print": (r) => { const c = (r >= 0 && r <= 0x10ffff) ? String.fromCodePoint(r) : null; return (c && !/\\p{Cc}/u.test(c)) ? 1 : 0; },
|
|
2422
|
-
"unicode_is_graphic": (r) => { const c = (r >= 0 && r <= 0x10ffff) ? String.fromCodePoint(r) : null; return (c && !/\\p{Cc}/u.test(c)) ? 1 : 0; },
|
|
2423
|
-
"unicode_to_upper": (r) => { const c = (r >= 0 && r <= 0x10ffff) ? String.fromCodePoint(r) : null; return c ? (c.toUpperCase().codePointAt(0) ?? r) : r; },
|
|
2424
|
-
"unicode_to_lower": (r) => { const c = (r >= 0 && r <= 0x10ffff) ? String.fromCodePoint(r) : null; return c ? (c.toLowerCase().codePointAt(0) ?? r) : r; },
|
|
2067
|
+
// A partial last line (print / fmt.Print without a newline) is written when
|
|
2068
|
+
// the program ends; Node gets it without the newline console.log adds.
|
|
2069
|
+
const flushPartial = () => {
|
|
2070
|
+
if (lineBuf === "") return;
|
|
2071
|
+
const s = lineBuf;
|
|
2072
|
+
lineBuf = "";
|
|
2073
|
+
started = false;
|
|
2074
|
+
if (typeof process !== "undefined" && process?.stdout?.write) process.stdout.write(s);
|
|
2075
|
+
else write(s);
|
|
2425
2076
|
};
|
|
2077
|
+
return { "env": env, "Math": m, "__bind": (ex) => { late.exports = ex; }, "__flush": flushPartial };
|
|
2426
2078
|
}
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
let
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
return
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
return (cp >= 0 && cp <= 0x10FFFF && !(cp >= 0xD800 && cp <= 0xDFFF)) ? String.fromCodePoint(cp) : "\\uFFFD";
|
|
2455
|
-
}
|
|
2456
|
-
return m;
|
|
2457
|
-
}
|
|
2458
|
-
}
|
|
2459
|
-
}),
|
|
2460
|
-
// path
|
|
2461
|
-
"path_base": (p) => { if (!p) return "."; const stripped = p.replace(/\\/+$/, ""); if (!stripped) return "/"; const i = stripped.lastIndexOf("/"); return i < 0 ? stripped : stripped.slice(i + 1) || "/"; },
|
|
2462
|
-
"path_dir": (p) => { const s = p ?? ""; const i = s.lastIndexOf("/"); if (i < 0) return "."; const res = s.slice(0, i); return res === "" ? "/" : __pathClean(res); },
|
|
2463
|
-
"path_ext": (p) => { const s = p ?? ""; const b = s.slice(s.lastIndexOf("/") + 1); const i = b.lastIndexOf("."); return i <= 0 ? "" : b.slice(i); },
|
|
2464
|
-
"path_is_abs": (p) => (p ?? "").startsWith("/") ? 1 : 0,
|
|
2465
|
-
"path_clean": (p) => __pathClean(p ?? ""),
|
|
2466
|
-
"path_split": (p) => {
|
|
2467
|
-
const s = p ?? "";
|
|
2468
|
-
const i = s.lastIndexOf("/");
|
|
2469
|
-
if (i < 0) { splitDir = ""; splitFile = s; }
|
|
2470
|
-
else { splitDir = s.slice(0, i + 1); splitFile = s.slice(i + 1); }
|
|
2471
|
-
},
|
|
2472
|
-
"path_split_dir": () => splitDir,
|
|
2473
|
-
"path_split_file": () => splitFile,
|
|
2474
|
-
"path_join_init": () => { joinParts = []; },
|
|
2475
|
-
"path_join_push": (s) => { if (s) joinParts.push(s); },
|
|
2476
|
-
"path_join_run": () => {
|
|
2477
|
-
if (joinParts.length === 0) return "";
|
|
2478
|
-
const res = __pathClean(joinParts.join("/"));
|
|
2479
|
-
joinParts = [];
|
|
2480
|
-
return res;
|
|
2481
|
-
},
|
|
2482
|
-
"path_match": (pat, name) => {
|
|
2483
|
-
const r = __pathMatch(pat ?? "", name ?? "");
|
|
2484
|
-
matchHasErr = r[1] ? 1 : 0;
|
|
2485
|
-
return r[0] ? 1 : 0;
|
|
2486
|
-
},
|
|
2487
|
-
"path_match_has_err": () => matchHasErr,
|
|
2488
|
-
// bytes trim
|
|
2489
|
-
"bytes_trim": (s, cutset, left, right) => {
|
|
2490
|
-
const cs = new Set(Array.from(cutset ?? ""));
|
|
2491
|
-
const chars = Array.from(s ?? "");
|
|
2492
|
-
let a = 0, b = chars.length;
|
|
2493
|
-
if (left) while (a < b && cs.has(chars[a])) a++;
|
|
2494
|
-
if (right) while (b > a && cs.has(chars[b - 1])) b--;
|
|
2495
|
-
const enc = new TextEncoder();
|
|
2496
|
-
trimStart = a === 0 ? 0 : enc.encode(chars.slice(0, a).join("")).length;
|
|
2497
|
-
trimEnd = b === chars.length ? enc.encode(s ?? "").length : enc.encode(chars.slice(0, b).join("")).length;
|
|
2498
|
-
},
|
|
2499
|
-
"bytes_trim_start": () => trimStart,
|
|
2500
|
-
"bytes_trim_end": () => trimEnd,
|
|
2501
|
-
// time
|
|
2502
|
-
"time_now_ms": () => (typeof globalThis.__GOFRONT_CLOCK === "function" ? globalThis.__GOFRONT_CLOCK() : Date.now()),
|
|
2503
|
-
"time_timezone_offset": (ms) => -new Date(ms).getTimezoneOffset() * 60,
|
|
2504
|
-
"time_duration_string": (d) => __durationString(d),
|
|
2505
|
-
"time_parse_duration": (s) => {
|
|
2506
|
-
const res = __timeParseDuration(s);
|
|
2507
|
-
if (res[1]) {
|
|
2508
|
-
timeParseDurationErr = res[1].message || String(res[1]);
|
|
2509
|
-
return 0n;
|
|
2510
|
-
}
|
|
2511
|
-
timeParseDurationErr = null;
|
|
2512
|
-
return BigInt(res[0]);
|
|
2513
|
-
},
|
|
2514
|
-
"time_parse_duration_err": () => timeParseDurationErr,
|
|
2515
|
-
"time_month_string": (m) => __monthString(m),
|
|
2516
|
-
"time_weekday_string": (w) => __weekdayString(w),
|
|
2517
|
-
"time_parse": (layout, val) => {
|
|
2518
|
-
try {
|
|
2519
|
-
let s = String(val ?? "");
|
|
2520
|
-
if (s.length >= 2 && s.startsWith('"') && s.endsWith('"')) {
|
|
2521
|
-
s = s.slice(1, -1);
|
|
2522
|
-
}
|
|
2523
|
-
const d = new Date(s);
|
|
2524
|
-
if (isNaN(d.getTime())) throw 0;
|
|
2525
|
-
let subNs = 0;
|
|
2526
|
-
const m = /\\.([0-9]{1,9})/.exec(s);
|
|
2527
|
-
if (m) {
|
|
2528
|
-
subNs = Number(m[1].padEnd(9, "0")) % 1000000;
|
|
2529
|
-
}
|
|
2530
|
-
timeParseErr = null;
|
|
2531
|
-
if (s.endsWith("Z") || s.endsWith("z")) {
|
|
2532
|
-
timeParseOffset = 0;
|
|
2533
|
-
} else {
|
|
2534
|
-
const tzMatch = /([+-])(\\d{2}):?(\\d{2})$/.exec(s);
|
|
2535
|
-
if (tzMatch) {
|
|
2536
|
-
const sign = tzMatch[1] === "+" ? 1 : -1;
|
|
2537
|
-
timeParseOffset = sign * (Number(tzMatch[2]) * 3600 + Number(tzMatch[3]) * 60);
|
|
2538
|
-
} else {
|
|
2539
|
-
timeParseOffset = -d.getTimezoneOffset() * 60;
|
|
2540
|
-
}
|
|
2541
|
-
}
|
|
2542
|
-
timeParseSubNs = subNs;
|
|
2543
|
-
return d.getTime();
|
|
2544
|
-
} catch {
|
|
2545
|
-
timeParseErr = "parsing time: cannot parse";
|
|
2546
|
-
timeParseOffset = 0;
|
|
2547
|
-
timeParseSubNs = 0;
|
|
2548
|
-
return 0;
|
|
2549
|
-
}
|
|
2550
|
-
},
|
|
2551
|
-
"time_parse_err": () => timeParseErr,
|
|
2552
|
-
"time_parse_offset": () => timeParseOffset,
|
|
2553
|
-
"time_parse_sub_ns": () => timeParseSubNs,
|
|
2554
|
-
"time_format": (y, m, d, hr, min, sec, wd, ms, offsetSec, layout) => {
|
|
2555
|
-
const DAYS = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
|
|
2556
|
-
const MONTHS = ["January","February","March","April","May","June","July","August","September","October","November","December"];
|
|
2557
|
-
const pad = (n, w = 2) => String(n).padStart(w, "0");
|
|
2558
|
-
return (layout ?? "").replace(/2006|06|Monday|Mon|January|Jan|01|02|15|PM|pm|03|04|05|Z07:00|-07:00|-0700|MST|\\.(?:0+|9+)|1|2|3|4|5/g, t => {
|
|
2559
|
-
if (t.startsWith(".")) {
|
|
2560
|
-
const isZeroPad = t.includes("0");
|
|
2561
|
-
const maxLen = t.length - 1;
|
|
2562
|
-
let frac = pad(ms % 1000000000, 9);
|
|
2563
|
-
if (maxLen <= 9) frac = frac.slice(0, maxLen);
|
|
2564
|
-
else frac = frac.padEnd(maxLen, "0");
|
|
2565
|
-
if (!isZeroPad) {
|
|
2566
|
-
frac = frac.replace(/0+$/, "");
|
|
2567
|
-
return frac.length > 0 ? "." + frac : "";
|
|
2568
|
-
}
|
|
2569
|
-
return "." + frac;
|
|
2570
|
-
}
|
|
2571
|
-
switch (t) {
|
|
2572
|
-
case "2006": return String(y);
|
|
2573
|
-
case "06": return String(y).slice(-2);
|
|
2574
|
-
case "Monday": return DAYS[wd];
|
|
2575
|
-
case "Mon": return DAYS[wd].slice(0, 3);
|
|
2576
|
-
case "January": return MONTHS[m - 1];
|
|
2577
|
-
case "Jan": return MONTHS[m - 1].slice(0, 3);
|
|
2578
|
-
case "01": return pad(m);
|
|
2579
|
-
case "1": return String(m);
|
|
2580
|
-
case "02": return pad(d);
|
|
2581
|
-
case "2": return String(d);
|
|
2582
|
-
case "15": return pad(hr);
|
|
2583
|
-
case "PM": return hr < 12 ? "AM" : "PM";
|
|
2584
|
-
case "pm": return hr < 12 ? "am" : "pm";
|
|
2585
|
-
case "03": return pad(hr % 12 || 12);
|
|
2586
|
-
case "3": return String(hr % 12 || 12);
|
|
2587
|
-
case "04": return pad(min);
|
|
2588
|
-
case "4": return String(min);
|
|
2589
|
-
case "05": return pad(sec);
|
|
2590
|
-
case "5": return String(sec);
|
|
2591
|
-
case "Z07:00": {
|
|
2592
|
-
const o = Math.floor(offsetSec / 60);
|
|
2593
|
-
return o === 0 ? "Z" : (o > 0 ? "+" : "-") + pad(Math.floor(Math.abs(o) / 60)) + ":" + pad(Math.abs(o) % 60);
|
|
2594
|
-
}
|
|
2595
|
-
case "-07:00": {
|
|
2596
|
-
const o = Math.floor(offsetSec / 60);
|
|
2597
|
-
return (o >= 0 ? "+" : "-") + pad(Math.floor(Math.abs(o) / 60)) + ":" + pad(Math.abs(o) % 60);
|
|
2598
|
-
}
|
|
2599
|
-
case "-0700": {
|
|
2600
|
-
const o = Math.floor(offsetSec / 60);
|
|
2601
|
-
return (o >= 0 ? "+" : "-") + pad(Math.floor(Math.abs(o) / 60)) + pad(Math.abs(o) % 60);
|
|
2602
|
-
}
|
|
2603
|
-
case "MST": return offsetSec === 0 ? "UTC" : "LOCAL";
|
|
2604
|
-
default: return t;
|
|
2605
|
-
}
|
|
2606
|
-
});
|
|
2607
|
-
},
|
|
2608
|
-
"raw_bytes_init": (len) => {
|
|
2609
|
-
rawBytes = new Uint8Array(len);
|
|
2610
|
-
rawPos = 0;
|
|
2611
|
-
},
|
|
2612
|
-
"raw_bytes_push": (b) => {
|
|
2613
|
-
if (rawPos < rawBytes.length) {
|
|
2614
|
-
rawBytes[rawPos++] = b & 0xff;
|
|
2615
|
-
}
|
|
2616
|
-
},
|
|
2617
|
-
"raw_bytes_len": () => rawBytes.length,
|
|
2618
|
-
"raw_bytes_get": (i) => rawBytes[i] ?? 0,
|
|
2619
|
-
"crypto_rand_fill": (len) => {
|
|
2620
|
-
rawBytes = new Uint8Array(len);
|
|
2621
|
-
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
2622
|
-
const CHUNK = 65536;
|
|
2623
|
-
for (let offset = 0; offset < len; offset += CHUNK) {
|
|
2624
|
-
crypto.getRandomValues(rawBytes.subarray(offset, Math.min(offset + CHUNK, len)));
|
|
2625
|
-
}
|
|
2626
|
-
} else {
|
|
2627
|
-
for (let i = 0; i < len; i++) rawBytes[i] = Math.floor(Math.random() * 256);
|
|
2628
|
-
}
|
|
2629
|
-
return len;
|
|
2630
|
-
},
|
|
2631
|
-
"crypto_sha256_sum": () => {
|
|
2632
|
-
const d = __sha256.Sum256(rawBytes);
|
|
2633
|
-
rawBytes = new Uint8Array(d);
|
|
2634
|
-
return 32;
|
|
2635
|
-
},
|
|
2636
|
-
"hex_encode_to_string": () => {
|
|
2637
|
-
return __hex_encode_to_string(rawBytes);
|
|
2638
|
-
},
|
|
2639
|
-
"hex_decode_string": (s) => {
|
|
2640
|
-
const [res, err] = __hex_decode_string(s ?? "");
|
|
2641
|
-
hexErr = err ? (err.message ?? String(err)) : null;
|
|
2642
|
-
rawBytes = new Uint8Array(res);
|
|
2643
|
-
return rawBytes.length;
|
|
2644
|
-
},
|
|
2645
|
-
"hex_get_err": () => hexErr,
|
|
2646
|
-
"base64_new_encoding": (alphabet) => {
|
|
2647
|
-
const id = customBase64Encodings.length + 4;
|
|
2648
|
-
customBase64Encodings.push(__base64_make(alphabet ?? "", "="));
|
|
2649
|
-
return id;
|
|
2650
|
-
},
|
|
2651
|
-
"base64_encode_to_string": (mode) => {
|
|
2652
|
-
const enc = mode === 1 ? __base64_url : mode === 2 ? __base64_raw_std : mode === 3 ? __base64_raw_url : mode >= 4 ? customBase64Encodings[mode - 4] : __base64_std;
|
|
2653
|
-
return (enc ?? __base64_std).EncodeToString(rawBytes);
|
|
2654
|
-
},
|
|
2655
|
-
"base64_decode_string": (mode, s) => {
|
|
2656
|
-
const enc = mode === 1 ? __base64_url : mode === 2 ? __base64_raw_std : mode === 3 ? __base64_raw_url : mode >= 4 ? customBase64Encodings[mode - 4] : __base64_std;
|
|
2657
|
-
const [res, err] = (enc ?? __base64_std).DecodeString(s ?? "");
|
|
2658
|
-
base64Err = err ? (err.message ?? String(err)) : null;
|
|
2659
|
-
rawBytes = new Uint8Array(res);
|
|
2660
|
-
return rawBytes.length;
|
|
2661
|
-
},
|
|
2662
|
-
"base64_get_err": () => base64Err,
|
|
2663
|
-
"bits_div32": (hi, lo, y) => {
|
|
2664
|
-
const yu = y >>> 0;
|
|
2665
|
-
if (yu === 0) throw new Error("runtime error: integer divide by zero");
|
|
2666
|
-
const hiu = hi >>> 0;
|
|
2667
|
-
if (hiu >= yu) throw new Error("runtime error: integer overflow");
|
|
2668
|
-
const z = (BigInt(hiu) << 32n) | BigInt(lo >>> 0);
|
|
2669
|
-
const yB = BigInt(yu);
|
|
2670
|
-
bitsRem32 = Number(z % yB);
|
|
2671
|
-
return Number(z / yB);
|
|
2672
|
-
},
|
|
2673
|
-
"bits_div32_rem": () => bitsRem32,
|
|
2674
|
-
"bits_rem32": (hi, lo, y) => {
|
|
2675
|
-
const yu = y >>> 0;
|
|
2676
|
-
if (yu === 0) throw new Error("runtime error: integer divide by zero");
|
|
2677
|
-
const z = (BigInt(hi >>> 0) << 32n) | BigInt(lo >>> 0);
|
|
2678
|
-
return Number(z % BigInt(yu));
|
|
2679
|
-
},
|
|
2680
|
-
"bits_div64": (hi, lo, y) => {
|
|
2681
|
-
const yB = BigInt.asUintN(64, BigInt(y));
|
|
2682
|
-
if (yB === 0n) throw new Error("runtime error: integer divide by zero");
|
|
2683
|
-
const hiB = BigInt.asUintN(64, BigInt(hi));
|
|
2684
|
-
if (hiB >= yB) throw new Error("runtime error: integer overflow");
|
|
2685
|
-
const loB = BigInt.asUintN(64, BigInt(lo));
|
|
2686
|
-
const z = (hiB << 64n) | loB;
|
|
2687
|
-
bitsRem64 = z % yB;
|
|
2688
|
-
return z / yB;
|
|
2689
|
-
},
|
|
2690
|
-
"bits_div64_rem": () => bitsRem64,
|
|
2691
|
-
"bits_rem64": (hi, lo, y) => {
|
|
2692
|
-
const yB = BigInt.asUintN(64, BigInt(y));
|
|
2693
|
-
if (yB === 0n) throw new Error("runtime error: integer divide by zero");
|
|
2694
|
-
const z = ((BigInt.asUintN(64, BigInt(hi)) % yB) << 64n) | BigInt.asUintN(64, BigInt(lo));
|
|
2695
|
-
return z % yB;
|
|
2696
|
-
},
|
|
2697
|
-
};
|
|
2698
|
-
}
|
|
2699
|
-
function ${P}stdlib(stringTable, io) {
|
|
2700
|
-
return Object.assign(
|
|
2701
|
-
{},
|
|
2702
|
-
${P}stdlib_fmt(stringTable, io),
|
|
2703
|
-
${P}stdlib_str(stringTable, io),
|
|
2704
|
-
${P}stdlib_sys(stringTable, io),
|
|
2705
|
-
);
|
|
2706
|
-
}
|
|
2079
|
+
// string -> bytes: UTF-8, except that a lone surrogate U+DC80-U+DCFF (a raw
|
|
2080
|
+
// byte from a \\xNN escape in the source) encodes as that single byte.
|
|
2081
|
+
function ${P}u8enc(s) {
|
|
2082
|
+
const e = new TextEncoder();
|
|
2083
|
+
if (s.isWellFormed()) return e.encode(s);
|
|
2084
|
+
const out = [];
|
|
2085
|
+
for (let i = 0; i < s.length; i++) {
|
|
2086
|
+
const c = s.charCodeAt(i);
|
|
2087
|
+
if (c >= 0xdc80 && c <= 0xdcff && !(i > 0 && (s.charCodeAt(i - 1) & 0xfc00) === 0xd800)) { out.push(c - 0xdc00); continue; }
|
|
2088
|
+
const cp = s.codePointAt(i);
|
|
2089
|
+
if (cp > 0xffff) i++;
|
|
2090
|
+
for (const b of e.encode(String.fromCodePoint(cp))) out.push(b);
|
|
2091
|
+
}
|
|
2092
|
+
return Uint8Array.from(out);
|
|
2093
|
+
}
|
|
2094
|
+
// strings.ToUpper/ToLower: letter by letter through the first code point of
|
|
2095
|
+
// the host's mapping, as unicode.ToUpper/ToLower do; ASCII text maps whole.
|
|
2096
|
+
function ${P}mapCase(s, method) {
|
|
2097
|
+
if (/^[\\x00-\\x7f]*$/.test(s)) return s[method]();
|
|
2098
|
+
return Array.from(s, (c) => {
|
|
2099
|
+
const m = c[method]();
|
|
2100
|
+
const r = String.fromCodePoint(m.codePointAt(0));
|
|
2101
|
+
// A letter whose upper case spans several code points (ß) stays as is.
|
|
2102
|
+
return method === "toUpperCase" && m.length > r.length ? c : r;
|
|
2103
|
+
}).join("");
|
|
2104
|
+
}
|
|
2105
|
+
// Code-point-aware Trim/TrimLeft/TrimRight of strings.
|
|
2707
2106
|
function ${P}trim(s, cutset, left, right) {
|
|
2708
|
-
|
|
2709
|
-
const
|
|
2710
|
-
let
|
|
2711
|
-
if (left) while (
|
|
2712
|
-
|
|
2713
|
-
|
|
2107
|
+
if (s === "" || cutset === "") return s;
|
|
2108
|
+
const set = new Set(cutset);
|
|
2109
|
+
let i = 0, j = s.length;
|
|
2110
|
+
if (left) while (i < j) {
|
|
2111
|
+
const c = s.codePointAt(i);
|
|
2112
|
+
if (!set.has(String.fromCodePoint(c))) break;
|
|
2113
|
+
i += c > 0xFFFF ? 2 : 1;
|
|
2114
|
+
}
|
|
2115
|
+
if (right) while (j > i) {
|
|
2116
|
+
let k = j - 1;
|
|
2117
|
+
const lo = s.charCodeAt(k);
|
|
2118
|
+
if (lo >= 0xDC00 && lo <= 0xDFFF && k > i) {
|
|
2119
|
+
const hi = s.charCodeAt(k - 1);
|
|
2120
|
+
if (hi >= 0xD800 && hi <= 0xDBFF) k--;
|
|
2121
|
+
}
|
|
2122
|
+
if (!set.has(s.slice(k, j))) break;
|
|
2123
|
+
j = k;
|
|
2124
|
+
}
|
|
2125
|
+
return s.slice(i, j);
|
|
2126
|
+
}
|
|
2127
|
+
// strings.Replace: an empty old string matches before every code point and at
|
|
2128
|
+
// the end; the replacement is literal.
|
|
2129
|
+
function ${P}replace(s, o, w, n) {
|
|
2130
|
+
if (o === w || n === 0) return s;
|
|
2131
|
+
if (o !== "") {
|
|
2132
|
+
if (n < 0) return s.replaceAll(o, () => w);
|
|
2133
|
+
let r = "", i = 0;
|
|
2134
|
+
for (let k = n; k > 0; k--) {
|
|
2135
|
+
const j = s.indexOf(o, i);
|
|
2136
|
+
if (j < 0) break;
|
|
2137
|
+
r += s.slice(i, j) + w;
|
|
2138
|
+
i = j + o.length;
|
|
2139
|
+
}
|
|
2140
|
+
return r + s.slice(i);
|
|
2141
|
+
}
|
|
2142
|
+
const cs = [...s];
|
|
2143
|
+
const m = n < 0 || n > cs.length + 1 ? cs.length + 1 : n;
|
|
2144
|
+
let r = "";
|
|
2145
|
+
for (let k = 0; k < m; k++) r += (k > 0 ? cs[k - 1] : "") + w;
|
|
2146
|
+
return r + cs.slice(m - 1).join("");
|
|
2714
2147
|
}`;
|
|
2715
2148
|
|
|
2716
2149
|
// Runtime loader emitted at the top of the facade.
|
|
2717
|
-
const wasmLoaderJs =
|
|
2718
|
-
${stdlibEnv ? WASM_STDLIB_JS : ""}
|
|
2150
|
+
const wasmLoaderJs = `${WASM_IMPORTS_JS}
|
|
2719
2151
|
async function ${P}fetch(url) {
|
|
2720
2152
|
const res = await fetch(url);
|
|
2721
2153
|
if (!res.ok) throw new Error("GoFront: failed to fetch " + url + " (" + res.status + ")");
|
|
@@ -2732,17 +2164,19 @@ async function ${P}instantiate(imports) {
|
|
|
2732
2164
|
}
|
|
2733
2165
|
return WebAssembly.instantiate(await ${P}fetch(url), imports);
|
|
2734
2166
|
}
|
|
2167
|
+
let ${P}flushOut = () => {};
|
|
2735
2168
|
async function ${P}load(stringTable, extraEnv) {
|
|
2736
2169
|
if (typeof WebAssembly === "undefined" || typeof WebAssembly.Tag !== "function") {
|
|
2737
2170
|
throw new Error("GoFront: this runtime lacks the WebAssembly GC / exception support required by app.wasm");
|
|
2738
2171
|
}
|
|
2739
2172
|
const tag = new WebAssembly.Tag({ "parameters": ["externref"] });
|
|
2740
|
-
const imports = ${P}imports(stringTable, extraEnv, tag, (s) => console.log(s));
|
|
2173
|
+
const imports = ${P}imports(stringTable, extraEnv, tag, (s) => console.log(s), true);
|
|
2741
2174
|
// Panics arrive as plain JS Errors thrown by env.panic (also from the
|
|
2742
2175
|
// start function while package-level initializers run), so exports are
|
|
2743
2176
|
// returned raw: no try/catch wrapper, which keeps JS→wasm calls inlinable.
|
|
2744
2177
|
const result = await ${P}instantiate(imports);
|
|
2745
2178
|
imports.__bind(result.instance.exports);
|
|
2179
|
+
${P}flushOut = imports.__flush;
|
|
2746
2180
|
return result.instance.exports;
|
|
2747
2181
|
}
|
|
2748
2182
|
// Go int/int64 cross the boundary as f64 (exact within the safe-integer range).
|
|
@@ -2805,10 +2239,10 @@ function facadeName(name) {
|
|
|
2805
2239
|
|
|
2806
2240
|
export function generateFacade(
|
|
2807
2241
|
meta,
|
|
2808
|
-
{ stringTable = [], callMain = false
|
|
2242
|
+
{ stringTable = [], callMain = false } = {},
|
|
2809
2243
|
) {
|
|
2810
2244
|
const needs = meta._needs ?? collectNeeds(meta);
|
|
2811
|
-
const out = [wasmLoaderJs
|
|
2245
|
+
const out = [wasmLoaderJs];
|
|
2812
2246
|
|
|
2813
2247
|
// JS callback imports (registered before instantiation; bodies run after).
|
|
2814
2248
|
out.push(`const ${P}env = {};`);
|
|
@@ -2852,7 +2286,7 @@ export function generateFacade(
|
|
|
2852
2286
|
}
|
|
2853
2287
|
const sig = ["fn", ...names].join(", ");
|
|
2854
2288
|
out.push(
|
|
2855
|
-
`${P}env["__invoke$${key}"] = (${sig}) => { try { ${body} } catch (__e) { if (__w && __w.__push_panic) __w.__push_panic(__e.message ?? String(__e)); throw __e; } };`,
|
|
2289
|
+
`${P}env["__invoke$${key}"] = (${sig}) => { try { ${body} } catch (__e) { if (__w && __w.__push_panic && !(__e && __e.__gfp === true)) { __w.__push_panic(__e.message ?? String(__e)); try { __e.__gfp = true; } catch {} } throw __e; } };`,
|
|
2856
2290
|
);
|
|
2857
2291
|
}
|
|
2858
2292
|
out.push(
|
|
@@ -2863,9 +2297,11 @@ export function generateFacade(
|
|
|
2863
2297
|
if (info.pkgTarget === "both") genBothStruct(out, name, fields);
|
|
2864
2298
|
else {
|
|
2865
2299
|
const methods = meta.structByName.get(name)?.methods ?? [];
|
|
2866
|
-
|
|
2300
|
+
const promoted = promotedMethods(info, fields, methods, meta);
|
|
2301
|
+
genHandleStruct(out, name, fields, methods, promoted);
|
|
2867
2302
|
}
|
|
2868
2303
|
}
|
|
2304
|
+
genGenericClasses(out, needs, meta._mod);
|
|
2869
2305
|
|
|
2870
2306
|
for (const [name, desc] of needs.anonStructs) {
|
|
2871
2307
|
out.push(`function ${P}to_${name}(o) {
|
|
@@ -2947,6 +2383,15 @@ function ${P}slview_${key}(s) {
|
|
|
2947
2383
|
} `);
|
|
2948
2384
|
}
|
|
2949
2385
|
|
|
2386
|
+
if (needs.maps.size > 0) {
|
|
2387
|
+
// GoFront JS code reads a map as a plain object (`m["a"]`, `len(m)`), so
|
|
2388
|
+
// each entry is also an own property of the returned Map unless that name
|
|
2389
|
+
// is one the Map already has.
|
|
2390
|
+
out.push(`function ${P}mapprop(m, k, v) {
|
|
2391
|
+
const p = String(k);
|
|
2392
|
+
if (!(p in m)) m[p] = v;
|
|
2393
|
+
}`);
|
|
2394
|
+
}
|
|
2950
2395
|
for (const [key, desc] of needs.maps) {
|
|
2951
2396
|
out.push(`function ${P}mapin_${key}(m) {
|
|
2952
2397
|
if (m == null) return null;
|
|
@@ -2966,6 +2411,7 @@ function ${P}mapout_${key}(m) {
|
|
|
2966
2411
|
if (ks) {
|
|
2967
2412
|
for (let i = 0; i < ks.length; i++) {
|
|
2968
2413
|
out.set(ks[i], vs[i]);
|
|
2414
|
+
${P}mapprop(out, ks[i], vs[i]);
|
|
2969
2415
|
}
|
|
2970
2416
|
}
|
|
2971
2417
|
return out;
|
|
@@ -3093,28 +2539,6 @@ function ${P}errin(e) {
|
|
|
3093
2539
|
}`);
|
|
3094
2540
|
}
|
|
3095
2541
|
|
|
3096
|
-
if (needs.time) {
|
|
3097
|
-
out.push(`function ${P}timeout(r) {
|
|
3098
|
-
if (r == null) return null;
|
|
3099
|
-
const ms = __w.__time_unix_milli ? __w.__time_unix_milli(r) : 0;
|
|
3100
|
-
const off = __w.__time_offset ? __w.__time_offset(r) : 0;
|
|
3101
|
-
return { _d: new Date(ms), _offset: off };
|
|
3102
|
-
}
|
|
3103
|
-
function ${P}timeout_ptr(r) {
|
|
3104
|
-
return ${P}timeout(r);
|
|
3105
|
-
}
|
|
3106
|
-
function ${P}timein(v) {
|
|
3107
|
-
if (v == null) return null;
|
|
3108
|
-
const d = v._d ? v._d : (v instanceof Date ? v : new Date(v));
|
|
3109
|
-
const ms = d.getTime();
|
|
3110
|
-
const off = typeof v?._offset === "number" ? v._offset : -d.getTimezoneOffset() * 60;
|
|
3111
|
-
return __w.__time_make ? __w.__time_make(ms, off) : null;
|
|
3112
|
-
}
|
|
3113
|
-
function ${P}timein_ptr(v) {
|
|
3114
|
-
return ${P}timein(v);
|
|
3115
|
-
}`);
|
|
3116
|
-
}
|
|
3117
|
-
|
|
3118
2542
|
if (needs.shared) {
|
|
3119
2543
|
// Zero-copy TypedArray views over the exported memory. Memory never
|
|
3120
2544
|
// grows after the start function (allocation is startup-only), but the
|
|
@@ -3163,7 +2587,7 @@ function ${P}shin(v, Ctor) {
|
|
|
3163
2587
|
);
|
|
3164
2588
|
}
|
|
3165
2589
|
|
|
3166
|
-
if (callMain) out.push(
|
|
2590
|
+
if (callMain) out.push(`try { __w.main(); } finally { ${P}flushOut(); }`);
|
|
3167
2591
|
return bindExports(out.join("\n"));
|
|
3168
2592
|
}
|
|
3169
2593
|
|
|
@@ -3214,8 +2638,26 @@ function genBothStruct(out, name, fields) {
|
|
|
3214
2638
|
const got = `__w.__get_${name}_${f.name}(this.__ref)`;
|
|
3215
2639
|
return `"${f.name}": { "enumerable": true, "get"() { return ${viewExpr(f.desc, got)}; }, "set"(v) { __w.__set_${name}_${f.name}(this.__ref, ${inExpr(f.desc, "v")}); } }`;
|
|
3216
2640
|
});
|
|
2641
|
+
// The one conversion `time.Time` has beyond the ordinary struct rules: JS
|
|
2642
|
+
// code may pass a Date (or an object holding one in `_d`), and a Time
|
|
2643
|
+
// handed to JS also reads as a Date through `_d`.
|
|
2644
|
+
const isTime = name === "Time$$time";
|
|
2645
|
+
if (isTime)
|
|
2646
|
+
out.push(`function ${P}time_in(o) {
|
|
2647
|
+
const d = o instanceof Date ? o : o?._d instanceof Date ? o._d : null;
|
|
2648
|
+
if (d === null) return o;
|
|
2649
|
+
const ms = d.getTime();
|
|
2650
|
+
const off = typeof o._offset === "number" ? o._offset : -d.getTimezoneOffset() * 60;
|
|
2651
|
+
const sec = Math.floor(ms / 1000);
|
|
2652
|
+
return new Time$$time(BigInt(sec) + 62135596800n, (ms - sec * 1000) * 1000000, new Location$$time("", off, 0));
|
|
2653
|
+
}
|
|
2654
|
+
function ${P}time_out(t) {
|
|
2655
|
+
Object.defineProperty(t, "_d", { configurable: true, get() { return new Date(Number(this.sec - 62135596800n) * 1000 + Math.floor(this.nsec / 1000000)); } });
|
|
2656
|
+
Object.defineProperty(t, "_offset", { configurable: true, get() { return this.loc ? this.loc.offset : 0; } });
|
|
2657
|
+
return t;
|
|
2658
|
+
}`);
|
|
3217
2659
|
out.push(`function ${P}to_${name}(o, isValue, m) {
|
|
3218
|
-
if (o == null) return isValue ? __w.__zero_${name}() : null;
|
|
2660
|
+
${isTime ? `\to = ${P}time_in(o);\n` : ""} if (o == null) return isValue ? __w.__zero_${name}() : null;
|
|
3219
2661
|
if (m) { const hit = m.get(o); if (hit) return hit; }
|
|
3220
2662
|
const r = __w.__new_${name}(${toArgs.join(", ")});
|
|
3221
2663
|
if (m) m.set(o, r);
|
|
@@ -3223,7 +2665,7 @@ function genBothStruct(out, name, fields) {
|
|
|
3223
2665
|
}
|
|
3224
2666
|
function ${P}from_${name}(r) {
|
|
3225
2667
|
if (r == null) return null;
|
|
3226
|
-
return new ${name}(${fromArgs.join(", ")});
|
|
2668
|
+
return ${isTime ? `${P}time_out(new ${name}(${fromArgs.join(", ")}))` : `new ${name}(${fromArgs.join(", ")})`};
|
|
3227
2669
|
}
|
|
3228
2670
|
// Live views share one prototype and are cached per wasm object so hot paths
|
|
3229
2671
|
// (\`h.Pos.X = 1\` in a frame loop) do not allocate a wrapper per access. The
|
|
@@ -3282,7 +2724,84 @@ function ${P}ifin_${key}(v) {
|
|
|
3282
2724
|
}`);
|
|
3283
2725
|
}
|
|
3284
2726
|
|
|
3285
|
-
|
|
2727
|
+
// Methods a struct gets from its embedded structs, shallowest first (a name
|
|
2728
|
+
// found twice at one depth is ambiguous and left out). Each is forwarded
|
|
2729
|
+
// through the embedded field's getter: `{ name, via, params, variadic }`.
|
|
2730
|
+
function promotedMethods(info, fields, methods, meta) {
|
|
2731
|
+
const taken = new Set([
|
|
2732
|
+
...methods.map((m) => m.name),
|
|
2733
|
+
...fields.map((f) => f.name),
|
|
2734
|
+
]);
|
|
2735
|
+
const promoted = [];
|
|
2736
|
+
const seen = new Set([info]);
|
|
2737
|
+
let level = [{ info, via: "" }];
|
|
2738
|
+
while (level.length > 0) {
|
|
2739
|
+
const next = [];
|
|
2740
|
+
const found = new Map();
|
|
2741
|
+
for (const { info: owner, via } of level) {
|
|
2742
|
+
for (const e of owner.embeds ?? []) {
|
|
2743
|
+
const typeName = e.typeName ?? e.name;
|
|
2744
|
+
const path = `${via}.${e.name}`;
|
|
2745
|
+
const inner = meta._mod.getStructType(typeName);
|
|
2746
|
+
const innerMethods =
|
|
2747
|
+
meta.structByName.get(typeName.replaceAll(".", "$"))?.methods ?? [];
|
|
2748
|
+
for (const m of innerMethods) {
|
|
2749
|
+
if (!found.has(m.name)) found.set(m.name, []);
|
|
2750
|
+
found.get(m.name).push({
|
|
2751
|
+
name: m.name,
|
|
2752
|
+
via: path,
|
|
2753
|
+
params: m.params,
|
|
2754
|
+
variadic: m.variadic,
|
|
2755
|
+
});
|
|
2756
|
+
}
|
|
2757
|
+
if (inner && !seen.has(inner)) {
|
|
2758
|
+
seen.add(inner);
|
|
2759
|
+
next.push({ info: inner, via: path });
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
for (const [n, c] of found) {
|
|
2764
|
+
if (!taken.has(n) && c.length === 1) promoted.push(c[0]);
|
|
2765
|
+
taken.add(n);
|
|
2766
|
+
}
|
|
2767
|
+
level = next;
|
|
2768
|
+
}
|
|
2769
|
+
return promoted;
|
|
2770
|
+
}
|
|
2771
|
+
|
|
2772
|
+
// A generic struct is built in a js main as `new Box(V, [...zeroFactories,
|
|
2773
|
+
// "int"])`; the facade only has the instances (`Box$int`). `Box` picks the
|
|
2774
|
+
// instance named by the last type-argument entry (the printed type arguments).
|
|
2775
|
+
function genGenericClasses(out, needs, mod) {
|
|
2776
|
+
const groups = new Map();
|
|
2777
|
+
for (const [name, { info }] of needs.structs) {
|
|
2778
|
+
if (info.pkgTarget === "both") continue;
|
|
2779
|
+
const goName = mod?.checker?.types?.get(info.name)?._goName;
|
|
2780
|
+
const m = goName ? /^([^[]+)\[(.*)\]$/s.exec(goName) : null;
|
|
2781
|
+
if (!m) continue;
|
|
2782
|
+
if (!groups.has(m[1])) groups.set(m[1], new Map());
|
|
2783
|
+
// The js caller keys instances by the unqualified printed arguments.
|
|
2784
|
+
groups
|
|
2785
|
+
.get(m[1])
|
|
2786
|
+
.set(m[2].replaceAll(" ", "").replace(/(?<![\w.])main\./g, ""), name);
|
|
2787
|
+
}
|
|
2788
|
+
for (const [base, instances] of groups) {
|
|
2789
|
+
const table = [...instances]
|
|
2790
|
+
.map(([id, cls]) => `${JSON.stringify(id)}: ${cls}`)
|
|
2791
|
+
.join(", ");
|
|
2792
|
+
out.push(`class ${facadeName(base)} {
|
|
2793
|
+
constructor(...a) {
|
|
2794
|
+
const tz = a.at(-1);
|
|
2795
|
+
const id = Array.isArray(tz) && typeof tz.at(-1) === "string" ? tz.at(-1).replaceAll(" ", "") : undefined;
|
|
2796
|
+
const C = id === undefined ? ${instances.size === 1 ? `${[...instances.values()][0]}` : "undefined"} : { ${table} }[id];
|
|
2797
|
+
if (!C) throw new TypeError("GoFront: no ${base} instance for the type arguments " + id + " in the wasm package");
|
|
2798
|
+
return new C(...(Array.isArray(tz) ? a.slice(0, -1) : a));
|
|
2799
|
+
}
|
|
2800
|
+
}`);
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
|
|
2804
|
+
function genHandleStruct(out, name, fields, methods, promoted = []) {
|
|
3286
2805
|
// `$`-suffixed params keep the mangler from renaming the matching getters.
|
|
3287
2806
|
const ctorParams = fields.map((f) => `${f.name}$ = ${zeroExpr(f.desc)}`);
|
|
3288
2807
|
const ctorArgs = fields.map((f) => inExpr(f.desc, `${f.name}$`));
|
|
@@ -3333,6 +2852,12 @@ class ${name} {
|
|
|
3333
2852
|
`\t${m.name}(${restParams(names, m.variadic)}) {\n${indent(body, "\t")}\n\t}`,
|
|
3334
2853
|
);
|
|
3335
2854
|
}
|
|
2855
|
+
for (const m of promoted) {
|
|
2856
|
+
const names = m.params.map((_, i) => `a${i}`);
|
|
2857
|
+
lines.push(
|
|
2858
|
+
`\t${m.name}(${restParams(names, m.variadic)}) { return this${m.via}.${m.name}(${restParams(names, m.variadic)}); }`,
|
|
2859
|
+
);
|
|
2860
|
+
}
|
|
3336
2861
|
lines.push("}");
|
|
3337
2862
|
out.push(lines.join("\n"));
|
|
3338
2863
|
}
|