gofront 1.8.0 → 1.9.0
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 +5 -4
- package/src/backend/js/expressions.js +849 -371
- package/src/backend/js/index.js +241 -147
- package/src/backend/js/natives.js +383 -0
- package/src/backend/js/runtime.js +512 -2547
- package/src/backend/js/statements.js +506 -103
- package/src/backend/js/stdlib/index.js +45 -93
- package/src/backend/js/templ.js +32 -45
- package/src/backend/js/type-info.js +177 -13
- package/src/backend/shared/fixed-float.js +20 -0
- package/src/backend/shared/fmt-types.js +63 -171
- package/src/backend/shared/host-unicode.js +36 -0
- package/src/backend/wasm/boundary.js +490 -965
- package/src/backend/wasm/emit-builtins.js +643 -256
- package/src/backend/wasm/emit-exprs.js +124 -57
- package/src/backend/wasm/emit-maps.js +17 -367
- package/src/backend/wasm/emit-stmts.js +325 -75
- package/src/backend/wasm/emit.js +104 -13
- package/src/backend/wasm/globals.js +47 -8
- package/src/backend/wasm/glue.js +2 -4
- package/src/backend/wasm/index.js +36 -530
- package/src/backend/wasm/method-expr.js +12 -1
- package/src/backend/wasm/module-emitter.js +92 -717
- package/src/backend/wasm/monomorph.js +103 -6
- package/src/backend/wasm/natives.js +596 -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 +68 -20
- package/src/backend/wasm/variadic.js +3 -3
- package/src/cli/cli-core.js +5 -1
- package/src/cli/test-runner.js +115 -342
- package/src/compiler.js +108 -130
- package/src/lexer/lexer.js +105 -11
- package/src/lexer/templ-lexer.js +61 -18
- package/src/lexer/tokens.js +1 -0
- package/src/link/stdlib.js +354 -132
- package/src/link/type-names.js +148 -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 +32 -3
- package/src/lower/errors-as.js +196 -0
- package/src/lower/fmt-formatters.js +905 -0
- package/src/lower/functions.js +2 -0
- package/src/lower/gen-types.js +274 -0
- package/src/lower/index.js +7 -1
- package/src/lower/json-codecs.js +228 -247
- 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 +28 -5
- package/src/parser/expressions.js +86 -16
- package/src/parser/statements.js +1 -0
- package/src/parser/templ.js +44 -5
- package/src/parser/types.js +1 -0
- package/src/resolver.js +1 -2
- package/src/typechecker/assignability.js +124 -11
- package/src/typechecker/const-fold.js +70 -27
- package/src/typechecker/constants.js +32 -6
- package/src/typechecker/expressions.js +326 -98
- package/src/typechecker/index.js +208 -33
- package/src/typechecker/init-order.js +136 -40
- package/src/typechecker/operand-text.js +40 -0
- package/src/typechecker/resolve.js +192 -36
- package/src/typechecker/statements.js +122 -11
- 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 +203 -573
- 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
|
@@ -2,28 +2,17 @@
|
|
|
2
2
|
// Pre-scan helpers: walk the lowered AST to decide which imports, runtime helpers
|
|
3
3
|
// and interface dispatchers a module needs before emission starts.
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { prepareWasmNative } from "./natives.js";
|
|
6
6
|
import {
|
|
7
7
|
anonIfaceName,
|
|
8
8
|
getInterfaceMethodList,
|
|
9
9
|
getReceiverTypeName,
|
|
10
|
-
isAnyType,
|
|
11
|
-
isBoolGoType,
|
|
12
10
|
isInterfaceType,
|
|
13
11
|
isNonEmptyInterface,
|
|
14
|
-
|
|
12
|
+
printOperandKind,
|
|
15
13
|
toWasmType,
|
|
16
14
|
} from "./types.js";
|
|
17
15
|
|
|
18
|
-
export function importsAnyOf(programs, pkgs) {
|
|
19
|
-
const has = (p) => (pkgs instanceof Set ? pkgs.has(p) : pkgs.includes(p));
|
|
20
|
-
return (programs ?? []).some((p) =>
|
|
21
|
-
(p.imports ?? []).some((decl) =>
|
|
22
|
-
(decl.imports ?? [decl]).some((imp) => has(imp.path)),
|
|
23
|
-
),
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
16
|
export function hasErrorUsage(programs) {
|
|
28
17
|
return (programs ?? []).some((p) => {
|
|
29
18
|
let found = false;
|
|
@@ -64,28 +53,6 @@ export function _someNode(node, pred) {
|
|
|
64
53
|
return false;
|
|
65
54
|
}
|
|
66
55
|
|
|
67
|
-
export function _usesTestingRun(node) {
|
|
68
|
-
return _someNode(
|
|
69
|
-
node,
|
|
70
|
-
(n) =>
|
|
71
|
-
n.kind === "CallExpr" &&
|
|
72
|
-
n.func?.kind === "SelectorExpr" &&
|
|
73
|
-
n.func.field === "Run" &&
|
|
74
|
-
isTestingT(n.func.expr?._type),
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export function _usesTestingCleanup(node) {
|
|
79
|
-
return _someNode(
|
|
80
|
-
node,
|
|
81
|
-
(n) =>
|
|
82
|
-
n.kind === "CallExpr" &&
|
|
83
|
-
n.func?.kind === "SelectorExpr" &&
|
|
84
|
-
n.func.field === "Cleanup" &&
|
|
85
|
-
isTestingT(n.func.expr?._type),
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
56
|
// `__any_eq` is only needed when some `==`/`!=` (or switch case) compares
|
|
90
57
|
// anyref operands, a struct with an anyref field is compared, or the error
|
|
91
58
|
// runtime (`errors.Is`) is present. `_emitAnyEq` throws if this misses a
|
|
@@ -110,68 +77,12 @@ export function _usesAnyEq(funcDecls, mod) {
|
|
|
110
77
|
);
|
|
111
78
|
}
|
|
112
79
|
|
|
113
|
-
// An `fmt` call with an `any`/interface operand or a `xs...` spread needs
|
|
114
|
-
// `__any_fmt`. `emitFmtCall` falls back to scalar-only dispatch without it.
|
|
115
|
-
export function _usesFmtAny(funcDecls, mod) {
|
|
116
|
-
return funcDecls.some((fn) =>
|
|
117
|
-
_someNode(
|
|
118
|
-
fn.body,
|
|
119
|
-
(n) =>
|
|
120
|
-
n.kind === "CallExpr" &&
|
|
121
|
-
n.func?.kind === "SelectorExpr" &&
|
|
122
|
-
n.func.expr?.kind === "Ident" &&
|
|
123
|
-
n.func.expr.name === "fmt" &&
|
|
124
|
-
n.args?.some(
|
|
125
|
-
(a) =>
|
|
126
|
-
a._spread ||
|
|
127
|
-
isAnyType(a._type, mod.checker) ||
|
|
128
|
-
isInterfaceType(a._type, mod.checker),
|
|
129
|
-
),
|
|
130
|
-
),
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Whether a value of this static type may print a 64-bit unsigned integer
|
|
135
|
-
// (directly, inside a container or struct, or behind `any`/an interface).
|
|
136
|
-
export function typeMayHoldU64(t, mod, seen = new Set(), depth = 0) {
|
|
137
|
-
if (!t || typeof t !== "object" || seen.has(t) || depth > 8) return false;
|
|
138
|
-
seen.add(t);
|
|
139
|
-
if (isAnyType(t, mod.checker) || isInterfaceType(t, mod.checker)) return true;
|
|
140
|
-
const sub = (x) => typeMayHoldU64(x, mod, seen, depth + 1);
|
|
141
|
-
switch (t.kind) {
|
|
142
|
-
case "basic":
|
|
143
|
-
return t.name === "uint64" || t.name === "uint" || t.name === "uintptr";
|
|
144
|
-
case "TypeName":
|
|
145
|
-
case "Ident":
|
|
146
|
-
return sub(
|
|
147
|
-
mod.checker?.resolveType?.(t) ?? { kind: "basic", name: t.name },
|
|
148
|
-
);
|
|
149
|
-
case "named":
|
|
150
|
-
return sub(t.underlying);
|
|
151
|
-
case "tuple":
|
|
152
|
-
return (t.types ?? []).some(sub);
|
|
153
|
-
case "pointer":
|
|
154
|
-
return sub(t.base);
|
|
155
|
-
case "slice":
|
|
156
|
-
case "array":
|
|
157
|
-
return sub(t.elem);
|
|
158
|
-
case "map":
|
|
159
|
-
return sub(t.key) || sub(t.value);
|
|
160
|
-
case "struct":
|
|
161
|
-
return [...(t.fields?.values?.() ?? [])].some(sub);
|
|
162
|
-
default:
|
|
163
|
-
return false;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
80
|
export function _scanImportsInBody(node, mod) {
|
|
168
81
|
if (!node || typeof node !== "object") return;
|
|
169
82
|
|
|
170
83
|
if (node.kind === "CallExpr") {
|
|
171
84
|
const { func, args } = node;
|
|
172
|
-
|
|
173
|
-
mod.getFmtBoxU64Index();
|
|
174
|
-
}
|
|
85
|
+
prepareWasmNative(mod, node);
|
|
175
86
|
if (
|
|
176
87
|
func.kind === "Ident" &&
|
|
177
88
|
(func.name === "print" || func.name === "println")
|
|
@@ -181,69 +92,10 @@ export function _scanImportsInBody(node, mod) {
|
|
|
181
92
|
mod.getPrintlnEmptyIndex();
|
|
182
93
|
}
|
|
183
94
|
for (let i = 0; i < args.length; i++) {
|
|
184
|
-
const arg = args[i];
|
|
185
95
|
const isLast = i === args.length - 1 && isPrintln;
|
|
186
|
-
const isBool =
|
|
187
|
-
isBoolGoType(arg._type) ||
|
|
188
|
-
(arg.kind === "BasicLit" && arg.litKind === "BOOL");
|
|
189
|
-
const wType = toWasmType(arg._type, mod.checker);
|
|
96
|
+
const { wType, isBool } = printOperandKind(args[i], mod.checker);
|
|
190
97
|
mod.getLogImportIndex(wType, isLast, isBool);
|
|
191
|
-
|
|
192
|
-
} else if (
|
|
193
|
-
func.kind === "SelectorExpr" &&
|
|
194
|
-
func.expr?.name === "math" &&
|
|
195
|
-
func.field
|
|
196
|
-
) {
|
|
197
|
-
const jsMathMap = {
|
|
198
|
-
Sin: "sin",
|
|
199
|
-
Cos: "cos",
|
|
200
|
-
Tan: "tan",
|
|
201
|
-
Asin: "asin",
|
|
202
|
-
Acos: "acos",
|
|
203
|
-
Atan: "atan",
|
|
204
|
-
Atan2: "atan2",
|
|
205
|
-
Pow: "pow",
|
|
206
|
-
Mod: "mod",
|
|
207
|
-
Hypot: "hypot",
|
|
208
|
-
Cbrt: "cbrt",
|
|
209
|
-
Exp: "exp",
|
|
210
|
-
Log: "log",
|
|
211
|
-
Log1p: "log1p",
|
|
212
|
-
Log2: "log2",
|
|
213
|
-
Log10: "log10",
|
|
214
|
-
Expm1: "expm1",
|
|
215
|
-
Round: "round",
|
|
216
|
-
Sinh: "sinh",
|
|
217
|
-
Cosh: "cosh",
|
|
218
|
-
Tanh: "tanh",
|
|
219
|
-
};
|
|
220
|
-
if (jsMathMap[func.field]) {
|
|
221
|
-
const isBinary = BINARY_MATH_IMPORTS.has(jsMathMap[func.field]);
|
|
222
|
-
mod.getMathImportIndex(jsMathMap[func.field], isBinary);
|
|
223
|
-
}
|
|
224
|
-
} else if (
|
|
225
|
-
func.kind === "SelectorExpr" &&
|
|
226
|
-
isTestingT(func.expr?._type) &&
|
|
227
|
-
func.field
|
|
228
|
-
) {
|
|
229
|
-
mod.internString(func.field);
|
|
230
|
-
if (func.field === "Name") mod.getTestingNameImportIndex();
|
|
231
|
-
else if (func.field === "Failed" || func.field === "Skipped")
|
|
232
|
-
mod.getTestingFlagImportIndex();
|
|
233
|
-
else if (func.field === "Run") {
|
|
234
|
-
// closure type for func(*testing.T) must exist before bodies are emitted
|
|
235
|
-
mod.getTestingRunClosureType();
|
|
236
|
-
} else if (func.field === "Cleanup") {
|
|
237
|
-
mod.getTestingCleanupClosureType();
|
|
238
|
-
} else {
|
|
239
|
-
mod.getTestingCallImportIndex();
|
|
240
|
-
for (const arg of args) {
|
|
241
|
-
mod.getTestingArgImportIndex(
|
|
242
|
-
toWasmType(arg._type, mod.checker),
|
|
243
|
-
isBoolGoType(arg._type) ||
|
|
244
|
-
(arg.kind === "BasicLit" && arg.litKind === "BOOL"),
|
|
245
|
-
);
|
|
246
|
-
}
|
|
98
|
+
if (!isPrintln) mod.getPrintResetIndex();
|
|
247
99
|
}
|
|
248
100
|
}
|
|
249
101
|
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// src/backend/was./prune-funcs.js
|
|
2
|
+
// Drops function imports and defined functions that no export, element
|
|
3
|
+
// segment, global initialiser or start function reaches, and renumbers the function index space to match. Imports
|
|
4
|
+
// are registered eagerly because the table is locked before bodies are
|
|
5
|
+
// emitted, so most modules declare far more than they call.
|
|
6
|
+
|
|
7
|
+
const FUNC_REF_OPS = new Set(["call", "return_call", "ref.func"]);
|
|
8
|
+
|
|
9
|
+
const funcRef = (inst) => inst.funcIndex ?? inst.index ?? 0;
|
|
10
|
+
|
|
11
|
+
function funcRefsOf(insts, visit) {
|
|
12
|
+
for (const inst of insts ?? []) {
|
|
13
|
+
if (FUNC_REF_OPS.has(inst.op)) visit(funcRef(inst));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Calls `visit` for every function the module reaches without a body: exports,
|
|
18
|
+
// element segments, global initialisers and the start function.
|
|
19
|
+
function forEachRoot(moduleIR, visit) {
|
|
20
|
+
for (const g of moduleIR.globals ?? []) funcRefsOf(g.init, visit);
|
|
21
|
+
for (const idx of moduleIR.elements ?? []) visit(idx);
|
|
22
|
+
for (const exp of moduleIR.exports ?? []) {
|
|
23
|
+
if (exp.kind === "func") visit(exp.index);
|
|
24
|
+
}
|
|
25
|
+
if (typeof moduleIR.start === "number") visit(moduleIR.start);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function remapInst(inst, remap) {
|
|
29
|
+
if (!FUNC_REF_OPS.has(inst.op)) return inst;
|
|
30
|
+
const next = remap[funcRef(inst)];
|
|
31
|
+
return "funcIndex" in inst
|
|
32
|
+
? { ...inst, funcIndex: next }
|
|
33
|
+
: { ...inst, index: next };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Marks every function index reachable from the roots through call bodies.
|
|
37
|
+
function reachableFuncs(moduleIR, count, total) {
|
|
38
|
+
const used = new Array(total).fill(false);
|
|
39
|
+
const work = [];
|
|
40
|
+
const mark = (idx) => {
|
|
41
|
+
if (idx < total && !used[idx]) {
|
|
42
|
+
used[idx] = true;
|
|
43
|
+
work.push(idx);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
forEachRoot(moduleIR, mark);
|
|
47
|
+
while (work.length > 0) {
|
|
48
|
+
const idx = work.pop();
|
|
49
|
+
if (idx >= count) funcRefsOf(moduleIR.funcs[idx - count].body, mark);
|
|
50
|
+
}
|
|
51
|
+
return used;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function applyRemap(moduleIR, remap) {
|
|
55
|
+
for (const fn of moduleIR.funcs) {
|
|
56
|
+
fn.body = fn.body.map((inst) => remapInst(inst, remap));
|
|
57
|
+
}
|
|
58
|
+
for (const g of moduleIR.globals ?? []) {
|
|
59
|
+
if (g.init) g.init = g.init.map((inst) => remapInst(inst, remap));
|
|
60
|
+
}
|
|
61
|
+
if (moduleIR.elements) {
|
|
62
|
+
moduleIR.elements = moduleIR.elements.map((idx) => remap[idx]);
|
|
63
|
+
}
|
|
64
|
+
for (const exp of moduleIR.exports ?? []) {
|
|
65
|
+
if (exp.kind === "func") exp.index = remap[exp.index];
|
|
66
|
+
}
|
|
67
|
+
if (typeof moduleIR.start === "number") {
|
|
68
|
+
moduleIR.start = remap[moduleIR.start];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function pruneUnusedFuncs(moduleIR) {
|
|
73
|
+
const imports = moduleIR.imports ?? [];
|
|
74
|
+
const funcImports = imports.filter((imp) => imp.kind === "func");
|
|
75
|
+
const count = funcImports.length;
|
|
76
|
+
const total = count + moduleIR.funcs.length;
|
|
77
|
+
|
|
78
|
+
const used = reachableFuncs(moduleIR, count, total);
|
|
79
|
+
if (used.every(Boolean)) return;
|
|
80
|
+
|
|
81
|
+
const remap = new Array(total);
|
|
82
|
+
let next = 0;
|
|
83
|
+
for (let i = 0; i < total; i++) if (used[i]) remap[i] = next++;
|
|
84
|
+
|
|
85
|
+
const dropped = new Set(funcImports.filter((_, i) => !used[i]));
|
|
86
|
+
moduleIR.imports = imports.filter((imp) => !dropped.has(imp));
|
|
87
|
+
moduleIR.funcs = moduleIR.funcs.filter((_, i) => used[count + i]);
|
|
88
|
+
applyRemap(moduleIR, remap);
|
|
89
|
+
}
|
|
@@ -1,38 +1,8 @@
|
|
|
1
1
|
// src/backend/wasm/stdlib/index.js
|
|
2
2
|
// Standard library emitters for the WebAssembly backend.
|
|
3
|
-
//
|
|
4
|
-
// Organized by domain:
|
|
5
|
-
// - core.js: math, math/bits, maps, slices, strings, strconv, fmt, errors, sort, unicode/utf8, testing
|
|
6
|
-
// - bytes.js: bytes package functions and bytes.Buffer methods
|
|
7
|
-
// - pure.js: stateless utilities (unicode, math/rand, html, path/filepath)
|
|
8
|
-
// - io.js: io constants/functions, readers/writers, fmt Fprint/Sscan, synthetic IO methods
|
|
9
|
-
// - time.js: time package (Duration, Time struct, components, Format/Parse, clock)
|
|
10
3
|
|
|
11
|
-
import { BytesEmitter } from "./bytes.js";
|
|
12
|
-
import { BINARY_MATH_IMPORTS, StdlibCoreEmitter } from "./core.js";
|
|
13
|
-
import { IoEmitter } from "./io.js";
|
|
14
|
-
import { ExtendedPackagesEmitter } from "./packages.js";
|
|
15
|
-
import { PurePackagesEmitter } from "./pure.js";
|
|
16
4
|
import { SimdEmitter } from "./simd.js";
|
|
17
|
-
import { TimeEmitter } from "./time.js";
|
|
18
5
|
|
|
19
|
-
export {
|
|
20
|
-
BINARY_MATH_IMPORTS,
|
|
21
|
-
BytesEmitter,
|
|
22
|
-
ExtendedPackagesEmitter,
|
|
23
|
-
IoEmitter,
|
|
24
|
-
PurePackagesEmitter,
|
|
25
|
-
SimdEmitter,
|
|
26
|
-
StdlibCoreEmitter,
|
|
27
|
-
TimeEmitter,
|
|
28
|
-
};
|
|
6
|
+
export { SimdEmitter };
|
|
29
7
|
|
|
30
|
-
export const stdlibEmitters = [
|
|
31
|
-
StdlibCoreEmitter,
|
|
32
|
-
BytesEmitter,
|
|
33
|
-
PurePackagesEmitter,
|
|
34
|
-
IoEmitter,
|
|
35
|
-
TimeEmitter,
|
|
36
|
-
ExtendedPackagesEmitter,
|
|
37
|
-
SimdEmitter,
|
|
38
|
-
];
|
|
8
|
+
export const stdlibEmitters = [SimdEmitter];
|
|
@@ -9,25 +9,6 @@ export { isComplex, isComplex64 };
|
|
|
9
9
|
// Name of the runtime's error struct (`errors.New`, `fmt.Errorf`, strconv).
|
|
10
10
|
export const ERROR_STRUCT = "__errorString";
|
|
11
11
|
|
|
12
|
-
// `*testing.T` is a JS-side object (the harness's __GoFront_T) passed through
|
|
13
|
-
// the boundary as an opaque externref.
|
|
14
|
-
export function isTestingT(goType) {
|
|
15
|
-
if (!goType) return false;
|
|
16
|
-
const base =
|
|
17
|
-
goType.kind === "pointer" || goType.kind === "PointerType"
|
|
18
|
-
? goType.base
|
|
19
|
-
: goType.kind === "StarExpr"
|
|
20
|
-
? (goType.expr ?? goType.operand)
|
|
21
|
-
: goType;
|
|
22
|
-
const name = base?.name ?? (typeof base === "string" ? base : null);
|
|
23
|
-
return (
|
|
24
|
-
name === "testing.T" ||
|
|
25
|
-
name === "testing.B" ||
|
|
26
|
-
name === "testing.M" ||
|
|
27
|
-
name === "testing.TB"
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
12
|
export function toWasmType(goType, checker = null, mod = null) {
|
|
32
13
|
if (!goType) return "i32";
|
|
33
14
|
if (typeof goType === "string") {
|
|
@@ -47,7 +28,6 @@ export function toWasmType(goType, checker = null, mod = null) {
|
|
|
47
28
|
if (typeof goType === "object" && goType.kind === "ref") {
|
|
48
29
|
return goType;
|
|
49
30
|
}
|
|
50
|
-
if (isTestingT(goType)) return "externref";
|
|
51
31
|
|
|
52
32
|
if (
|
|
53
33
|
goType.kind === "simd" ||
|
|
@@ -542,6 +522,47 @@ export function isSliceType(goType, checker = null) {
|
|
|
542
522
|
return goType.kind === "slice" || goType.kind === "SliceType";
|
|
543
523
|
}
|
|
544
524
|
|
|
525
|
+
// Element kinds whose slices share one WebAssembly representation (a slice of
|
|
526
|
+
// i32), so `[]bool`, `[]byte` and `[]rune` cannot be told apart by `ref.test`.
|
|
527
|
+
const TAGGED_SLICE_ELEMS = new Set([
|
|
528
|
+
"bool",
|
|
529
|
+
"int8",
|
|
530
|
+
"int16",
|
|
531
|
+
"int32",
|
|
532
|
+
"uint8",
|
|
533
|
+
"uint16",
|
|
534
|
+
"uint32",
|
|
535
|
+
"byte",
|
|
536
|
+
"rune",
|
|
537
|
+
]);
|
|
538
|
+
|
|
539
|
+
// True for a defined slice type or a slice of booleans or integers of at
|
|
540
|
+
// most 32 bits. In an
|
|
541
|
+
// interface such a value carries a per-Go-type tag (see getTaggedSliceType).
|
|
542
|
+
export function isTaggedSliceType(goType, checker = null) {
|
|
543
|
+
if (!isSliceType(goType, checker)) return false;
|
|
544
|
+
// A defined slice type (`type S []int`) is tagged whatever its element, so
|
|
545
|
+
// `case S` does not match an unnamed `[]int`.
|
|
546
|
+
const declared =
|
|
547
|
+
goType.kind === "TypeName" || goType.kind === "Ident"
|
|
548
|
+
? (checker?.types?.get(goType.name) ?? goType)
|
|
549
|
+
: goType;
|
|
550
|
+
if (declared?.kind === "named") return true;
|
|
551
|
+
let elem = getSliceElemType(goType, checker);
|
|
552
|
+
// A source-level element (`uint8` in a case list) is a TypeName node.
|
|
553
|
+
for (let i = 0; i < 16 && elem; i++) {
|
|
554
|
+
if (elem.kind === "named")
|
|
555
|
+
elem = elem.underlying ?? checker?.types?.get(elem.name);
|
|
556
|
+
else if (elem.kind === "TypeName" || elem.kind === "Ident")
|
|
557
|
+
elem = checker?.types?.get(elem.name) ?? {
|
|
558
|
+
kind: "basic",
|
|
559
|
+
name: elem.name,
|
|
560
|
+
};
|
|
561
|
+
else break;
|
|
562
|
+
}
|
|
563
|
+
return elem?.kind === "basic" && TAGGED_SLICE_ELEMS.has(elem.name);
|
|
564
|
+
}
|
|
565
|
+
|
|
545
566
|
export function getSliceElemType(t, checker = null) {
|
|
546
567
|
if (!t) return null;
|
|
547
568
|
if (t.elem) return t.elem;
|
|
@@ -765,6 +786,33 @@ export function isSigned(goType) {
|
|
|
765
786
|
return true;
|
|
766
787
|
}
|
|
767
788
|
|
|
789
|
+
// How a builtin `print`/`println` operand is handed to the host. The host
|
|
790
|
+
// prints an i32 or i64 as signed, so a uint32 widens to i64 and a uint64 uses
|
|
791
|
+
// its own unsigned import (`wType` "u64").
|
|
792
|
+
export function printOperandKind(arg, checker) {
|
|
793
|
+
const isBool =
|
|
794
|
+
isBoolGoType(arg._type) ||
|
|
795
|
+
_namedBasic(arg._type) === "bool" ||
|
|
796
|
+
(arg.kind === "BasicLit" && arg.litKind === "BOOL");
|
|
797
|
+
let wType = toWasmType(arg._type, checker);
|
|
798
|
+
let widen = false;
|
|
799
|
+
if (!isBool && (wType === "i32" || wType === "i64") && !isSigned(arg._type)) {
|
|
800
|
+
if (wType === "i64") wType = "u64";
|
|
801
|
+
else if (_namedBasic(arg._type) === "uint32") {
|
|
802
|
+
wType = "i64";
|
|
803
|
+
widen = true;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
return { wType, isBool, widen };
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
function _namedBasic(t) {
|
|
810
|
+
while (t && (t.kind === "named" || t.kind === "TypeName") && t.underlying) {
|
|
811
|
+
t = t.underlying;
|
|
812
|
+
}
|
|
813
|
+
return t?.name;
|
|
814
|
+
}
|
|
815
|
+
|
|
768
816
|
export function isFloat(goType) {
|
|
769
817
|
if (!goType) return false;
|
|
770
818
|
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
@@ -13,9 +13,9 @@ function variadicFuncType(t) {
|
|
|
13
13
|
return fn?.kind === "func" && fn.variadic ? fn : null;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
16
|
+
// A call of a package member or a method of an emitter-backed type: those
|
|
17
|
+
// emitters take the arguments unpacked. Emitter types are the dotted names;
|
|
18
|
+
// GoFront and Go-source types are not.
|
|
19
19
|
function isStdlibCall(call) {
|
|
20
20
|
const f = call.func;
|
|
21
21
|
if (f?.kind !== "SelectorExpr") return false;
|
package/src/cli/cli-core.js
CHANGED
|
@@ -45,11 +45,12 @@ export function runCompile(inputPath, isDir, options) {
|
|
|
45
45
|
dumpAst = false,
|
|
46
46
|
emitWat = false,
|
|
47
47
|
wasmOpt = false,
|
|
48
|
+
natives = true,
|
|
48
49
|
forceTarget = null,
|
|
49
50
|
targetOverrides = null,
|
|
50
51
|
rootDir = null,
|
|
51
52
|
} = options ?? {};
|
|
52
|
-
const targetOpts = {};
|
|
53
|
+
const targetOpts = { natives };
|
|
53
54
|
if (forceTarget) targetOpts.forceTarget = forceTarget;
|
|
54
55
|
if (targetOverrides) targetOpts.targetOverrides = targetOverrides;
|
|
55
56
|
if (rootDir) targetOpts.rootDir = rootDir;
|
|
@@ -632,6 +633,7 @@ export function parseBuildArgs(argv) {
|
|
|
632
633
|
const noWasmOpt = argv.includes("--no-wasm-opt");
|
|
633
634
|
const wasmOpt = !noWasmOpt && (argv.includes("--wasm-opt") || release);
|
|
634
635
|
const forceTarget = parseTargetFlag(argv);
|
|
636
|
+
const natives = !argv.includes("--no-natives");
|
|
635
637
|
|
|
636
638
|
for (let i = 0; i < argv.length; i++) {
|
|
637
639
|
const arg = argv[i];
|
|
@@ -656,6 +658,7 @@ export function parseBuildArgs(argv) {
|
|
|
656
658
|
mangle: !noMangle && !noMinify,
|
|
657
659
|
release,
|
|
658
660
|
wasmOpt,
|
|
661
|
+
natives,
|
|
659
662
|
forceTarget,
|
|
660
663
|
};
|
|
661
664
|
}
|
|
@@ -858,6 +861,7 @@ export async function handleBuild(targetDir = ".", options = {}) {
|
|
|
858
861
|
sourceMap: options.sourceMap ?? false,
|
|
859
862
|
emitWat: options.emitWat ?? false,
|
|
860
863
|
wasmOpt: options.wasmOpt ?? false,
|
|
864
|
+
natives: options.natives ?? true,
|
|
861
865
|
forceTarget: options.forceTarget ?? null,
|
|
862
866
|
...projectTargetOptions(project, options),
|
|
863
867
|
});
|