gofront 1.5.1 → 1.6.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 +174 -466
- package/package.json +16 -20
- package/src/backend/js/expressions.js +288 -128
- package/src/backend/js/index.js +138 -56
- package/src/backend/js/runtime.js +1055 -53
- package/src/backend/js/source-map.js +32 -0
- package/src/backend/js/statements.js +151 -83
- package/src/backend/js/stdlib/base64.js +12 -0
- package/src/backend/js/stdlib/binary.js +102 -0
- package/src/backend/js/stdlib/bits.js +15 -1
- package/src/backend/js/stdlib/builder.js +28 -9
- package/src/backend/js/stdlib/bytes.js +75 -18
- package/src/backend/js/stdlib/errors.js +22 -3
- package/src/backend/js/stdlib/fmt.js +95 -20
- package/src/backend/js/stdlib/hex.js +17 -0
- package/src/backend/js/stdlib/html.js +1 -1
- package/src/backend/js/stdlib/index.js +19 -0
- package/src/backend/js/stdlib/io.js +105 -3
- package/src/backend/js/stdlib/maps.js +1 -1
- package/src/backend/js/stdlib/math.js +13 -1
- package/src/backend/js/stdlib/path.js +20 -6
- package/src/backend/js/stdlib/rand.js +10 -5
- package/src/backend/js/stdlib/sha256.js +12 -0
- package/src/backend/js/stdlib/shared.js +17 -0
- package/src/backend/js/stdlib/slices.js +53 -27
- package/src/backend/js/stdlib/sort.js +1 -1
- package/src/backend/js/stdlib/strconv.js +52 -11
- package/src/backend/js/stdlib/strings.js +152 -16
- package/src/backend/js/stdlib/sync.js +13 -0
- package/src/backend/js/stdlib/testing.js +2 -2
- package/src/backend/js/stdlib/time.js +93 -22
- package/src/backend/js/stdlib/unicode.js +2 -2
- package/src/backend/js/templ.js +1 -1
- package/src/backend/wasm/boundary.js +1677 -58
- package/src/backend/wasm/const-fold.js +205 -0
- package/src/backend/wasm/emit-builtins.js +1230 -0
- package/src/backend/wasm/emit-exprs.js +2096 -0
- package/src/backend/wasm/emit-maps.js +1999 -0
- package/src/backend/wasm/emit-shared.js +519 -0
- package/src/backend/wasm/emit-stdlib.js +13 -0
- package/src/backend/wasm/emit-stmts.js +2466 -0
- package/src/backend/wasm/emit.js +656 -5031
- package/src/backend/wasm/encode.js +259 -85
- package/src/backend/wasm/glue.js +19 -5
- package/src/backend/wasm/index.js +2432 -86
- package/src/backend/wasm/monomorph.js +711 -0
- package/src/backend/wasm/optimize.js +236 -0
- package/src/backend/wasm/stdlib/bytes.js +5039 -0
- package/src/backend/wasm/stdlib/core.js +8903 -0
- package/src/backend/wasm/stdlib/index.js +40 -0
- package/src/backend/wasm/stdlib/io.js +2161 -0
- package/src/backend/wasm/stdlib/packages.js +2400 -0
- package/src/backend/wasm/stdlib/pure.js +720 -0
- package/src/backend/wasm/stdlib/time.js +1200 -0
- package/src/backend/wasm/types.js +312 -36
- package/src/backend/wasm/wat.js +49 -2
- package/src/cli-core.js +276 -73
- package/src/compiler.js +162 -25
- package/src/dts-parser.js +79 -126
- package/src/index.js +88 -121
- package/src/lexer.js +80 -29
- package/src/lower/boxing.js +4 -6
- package/src/lower/captures.js +12 -23
- package/src/lower/escape.js +4 -9
- package/src/lower/functions.js +277 -5
- package/src/lower/globals.js +7 -15
- package/src/lower/index.js +5 -2
- package/src/lower/ownership.js +35 -19
- package/src/lower/range.js +2 -5
- package/src/lower/walk.js +25 -0
- package/src/minifier.js +20 -68
- package/src/parser/declarations.js +3 -6
- package/src/parser/expressions.js +3 -8
- package/src/parser/index.js +18 -3
- package/src/parser/statements.js +25 -38
- package/src/parser/types.js +1 -2
- package/src/resolver.js +3 -27
- package/src/templ-lexer.js +29 -63
- package/src/templ-parser.js +22 -45
- package/src/test-runner.js +20 -0
- package/src/typechecker/assignability.js +123 -14
- package/src/typechecker/expressions.js +244 -4
- package/src/typechecker/index.js +27 -1
- package/src/typechecker/resolve.js +71 -12
- package/src/typechecker/statements.js +0 -7
- package/src/typechecker/stdlib/core.js +292 -103
- package/src/typechecker/stdlib/extended.js +471 -4
- package/src/typechecker/stdlib/shared.js +53 -0
- package/src/typechecker/stdlib.js +2 -0
- package/src/typechecker/types.js +545 -8
- package/src/vendor.js +2 -2
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
// src/backend/wasm/types.js
|
|
2
2
|
// Maps GoFront types to WasmGC types and manages type registry.
|
|
3
3
|
|
|
4
|
+
import { SHARED_KINDS } from "../../typechecker/stdlib/shared.js";
|
|
5
|
+
|
|
6
|
+
// Name of the runtime's error struct (`errors.New`, `fmt.Errorf`, strconv).
|
|
7
|
+
export const ERROR_STRUCT = "__errorString";
|
|
8
|
+
|
|
4
9
|
// `*testing.T` is a JS-side object (the harness's __GoFront_T) passed through
|
|
5
10
|
// the boundary as an opaque externref.
|
|
6
11
|
export function isTestingT(goType) {
|
|
@@ -16,6 +21,22 @@ export function isTestingT(goType) {
|
|
|
16
21
|
|
|
17
22
|
export function toWasmType(goType, checker = null, mod = null) {
|
|
18
23
|
if (!goType) return "i32";
|
|
24
|
+
if (typeof goType === "string") {
|
|
25
|
+
if (
|
|
26
|
+
goType === "i32" ||
|
|
27
|
+
goType === "i64" ||
|
|
28
|
+
goType === "f32" ||
|
|
29
|
+
goType === "f64" ||
|
|
30
|
+
goType === "anyref" ||
|
|
31
|
+
goType === "externref" ||
|
|
32
|
+
goType === "funcref"
|
|
33
|
+
) {
|
|
34
|
+
return goType;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (typeof goType === "object" && goType.kind === "ref") {
|
|
38
|
+
return goType;
|
|
39
|
+
}
|
|
19
40
|
if (isTestingT(goType)) return "externref";
|
|
20
41
|
|
|
21
42
|
// Pointer AST nodes
|
|
@@ -30,13 +51,20 @@ export function toWasmType(goType, checker = null, mod = null) {
|
|
|
30
51
|
);
|
|
31
52
|
}
|
|
32
53
|
|
|
33
|
-
// Slice and
|
|
54
|
+
// Slice, Array, and Map AST nodes
|
|
34
55
|
if (goType.kind === "SliceType") {
|
|
35
56
|
return toWasmType({ kind: "slice", elem: goType.elem }, checker, mod);
|
|
36
57
|
}
|
|
37
58
|
if (goType.kind === "ArrayType") {
|
|
38
59
|
return toWasmType({ kind: "array", elem: goType.elem }, checker, mod);
|
|
39
60
|
}
|
|
61
|
+
if (goType.kind === "MapType") {
|
|
62
|
+
return toWasmType(
|
|
63
|
+
{ kind: "map", key: goType.key, value: goType.value ?? goType.elem },
|
|
64
|
+
checker,
|
|
65
|
+
mod,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
40
68
|
|
|
41
69
|
// TypeName AST node
|
|
42
70
|
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
@@ -114,6 +142,7 @@ export function toWasmType(goType, checker = null, mod = null) {
|
|
|
114
142
|
return "externref";
|
|
115
143
|
|
|
116
144
|
case "any":
|
|
145
|
+
case "error":
|
|
117
146
|
return "anyref";
|
|
118
147
|
|
|
119
148
|
case "void":
|
|
@@ -144,6 +173,16 @@ export function toWasmType(goType, checker = null, mod = null) {
|
|
|
144
173
|
return { kind: "ref", nullable: true, heapType: "any" };
|
|
145
174
|
}
|
|
146
175
|
|
|
176
|
+
if (goType.kind === "shared") {
|
|
177
|
+
if (mod?.getSharedType)
|
|
178
|
+
return {
|
|
179
|
+
kind: "ref",
|
|
180
|
+
nullable: true,
|
|
181
|
+
typeIndex: mod.getSharedType().typeIndex,
|
|
182
|
+
};
|
|
183
|
+
return { kind: "ref", nullable: true, heapType: "struct" };
|
|
184
|
+
}
|
|
185
|
+
|
|
147
186
|
if (goType.kind === "slice") {
|
|
148
187
|
if (mod?.getSliceType && goType.elem) {
|
|
149
188
|
const sliceInfo = mod.getSliceType(goType.elem);
|
|
@@ -168,7 +207,21 @@ export function toWasmType(goType, checker = null, mod = null) {
|
|
|
168
207
|
return { kind: "ref", nullable: true, heapType: "array" };
|
|
169
208
|
}
|
|
170
209
|
|
|
171
|
-
if (goType.kind === "
|
|
210
|
+
if (goType.kind === "map") {
|
|
211
|
+
const key = goType.key;
|
|
212
|
+
const val = goType.value ?? goType.elem;
|
|
213
|
+
if (mod?.getMapType && key && val) {
|
|
214
|
+
const mapInfo = mod.getMapType(key, val);
|
|
215
|
+
return {
|
|
216
|
+
kind: "ref",
|
|
217
|
+
nullable: true,
|
|
218
|
+
typeIndex: mapInfo.typeIndex,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
return { kind: "ref", nullable: true, heapType: "struct" };
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (goType.kind === "struct" || goType.kind === "StructType") {
|
|
172
225
|
if (goType.name && mod?.getStructType(goType.name)) {
|
|
173
226
|
return {
|
|
174
227
|
kind: "ref",
|
|
@@ -176,6 +229,23 @@ export function toWasmType(goType, checker = null, mod = null) {
|
|
|
176
229
|
typeIndex: mod.getStructType(goType.name).typeIndex,
|
|
177
230
|
};
|
|
178
231
|
}
|
|
232
|
+
if (mod?.getAnonStructType && goType.fields) {
|
|
233
|
+
const rawFields = [];
|
|
234
|
+
if (goType.fields instanceof Map) {
|
|
235
|
+
for (const [k, v] of goType.fields.entries()) {
|
|
236
|
+
rawFields.push({ name: k, goType: v });
|
|
237
|
+
}
|
|
238
|
+
} else if (Array.isArray(goType.fields)) {
|
|
239
|
+
for (const f of goType.fields) {
|
|
240
|
+
const names = f.names ?? (f.name ? [f.name] : []);
|
|
241
|
+
for (const n of names) rawFields.push({ name: n, goType: f.type });
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (rawFields.length > 0) {
|
|
245
|
+
const info = mod.getAnonStructType(rawFields);
|
|
246
|
+
return { kind: "ref", nullable: true, typeIndex: info.typeIndex };
|
|
247
|
+
}
|
|
248
|
+
}
|
|
179
249
|
return { kind: "ref", nullable: true, heapType: "struct" };
|
|
180
250
|
}
|
|
181
251
|
|
|
@@ -198,6 +268,96 @@ export function toWasmType(goType, checker = null, mod = null) {
|
|
|
198
268
|
return "i32";
|
|
199
269
|
}
|
|
200
270
|
|
|
271
|
+
export function getInterfaceMethodList(iface) {
|
|
272
|
+
if (!iface) return [];
|
|
273
|
+
if (iface.methods instanceof Map) {
|
|
274
|
+
return Array.from(iface.methods.entries()).map(([name, sig]) => ({
|
|
275
|
+
name,
|
|
276
|
+
params: (sig.params ?? []).map((p) => p.type ?? p),
|
|
277
|
+
returns: (sig.returns ?? []).map((r) => r.type ?? r),
|
|
278
|
+
}));
|
|
279
|
+
}
|
|
280
|
+
if (Array.isArray(iface.methods)) {
|
|
281
|
+
return iface.methods.map((m) => ({
|
|
282
|
+
name: m.name?.value ?? m.name ?? m,
|
|
283
|
+
params: (m.params ?? []).map((p) => p.type ?? p),
|
|
284
|
+
returns: m.returnType
|
|
285
|
+
? m.returnType.kind === "TupleType" || m.returnType.kind === "tuple"
|
|
286
|
+
? m.returnType.types
|
|
287
|
+
: [m.returnType]
|
|
288
|
+
: [],
|
|
289
|
+
}));
|
|
290
|
+
}
|
|
291
|
+
return [];
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export function goTypeKey(t) {
|
|
295
|
+
if (!t) return "any";
|
|
296
|
+
if (typeof t === "string") {
|
|
297
|
+
if (t === "byte") return "uint8";
|
|
298
|
+
if (t === "rune") return "int32";
|
|
299
|
+
return t;
|
|
300
|
+
}
|
|
301
|
+
if (t.kind === "basic" || t.kind === "TypeName" || t.kind === "Ident") {
|
|
302
|
+
const name = t.name ?? "any";
|
|
303
|
+
if (name === "byte") return "uint8";
|
|
304
|
+
if (name === "rune") return "int32";
|
|
305
|
+
return name;
|
|
306
|
+
}
|
|
307
|
+
if (t.kind === "untyped") {
|
|
308
|
+
return t.base ?? "int";
|
|
309
|
+
}
|
|
310
|
+
if (t.kind === "pointer" || t.kind === "PointerType") {
|
|
311
|
+
return `ptr_${goTypeKey(t.base)}`;
|
|
312
|
+
}
|
|
313
|
+
if (t.kind === "StarExpr") {
|
|
314
|
+
return `ptr_${goTypeKey(t.expr ?? t.operand)}`;
|
|
315
|
+
}
|
|
316
|
+
if (t.kind === "slice" || t.kind === "SliceType") {
|
|
317
|
+
return `sl_${goTypeKey(t.elem)}`;
|
|
318
|
+
}
|
|
319
|
+
if (t.kind === "array" || t.kind === "ArrayType") {
|
|
320
|
+
const sz =
|
|
321
|
+
typeof t.size === "number" ? t.size : (t.size?.value ?? t.len ?? "");
|
|
322
|
+
return `arr_${sz}_${goTypeKey(t.elem)}`;
|
|
323
|
+
}
|
|
324
|
+
if (t.kind === "map" || t.kind === "MapType") {
|
|
325
|
+
return `map_${goTypeKey(t.key ?? t.keyType)}_${goTypeKey(t.value ?? t.val ?? t.elem ?? t.valueType ?? t.valType)}`;
|
|
326
|
+
}
|
|
327
|
+
if (t.kind === "struct" || t.kind === "StructType") {
|
|
328
|
+
if (t.name) return t.name;
|
|
329
|
+
const rawFields = [];
|
|
330
|
+
if (t.fields instanceof Map) {
|
|
331
|
+
for (const [k, v] of t.fields.entries())
|
|
332
|
+
rawFields.push(`${k}:${goTypeKey(v)}`);
|
|
333
|
+
} else if (Array.isArray(t.fields)) {
|
|
334
|
+
for (const f of t.fields) {
|
|
335
|
+
const names = f.names ?? (f.name ? [f.name] : []);
|
|
336
|
+
for (const n of names)
|
|
337
|
+
rawFields.push(`${n}:${goTypeKey(f.type ?? f.goType)}`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return `struct_${rawFields.join("_")}`;
|
|
341
|
+
}
|
|
342
|
+
if (t.kind === "named") {
|
|
343
|
+
return t.name ?? (t.underlying ? goTypeKey(t.underlying) : "any");
|
|
344
|
+
}
|
|
345
|
+
if (t.name) return t.name;
|
|
346
|
+
return t.kind ?? "any";
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export function anonIfaceName(iface, _checker = null, _mod = null) {
|
|
350
|
+
const methods = getInterfaceMethodList(iface);
|
|
351
|
+
methods.sort((a, b) => a.name.localeCompare(b.name));
|
|
352
|
+
const parts = methods.map((m) => {
|
|
353
|
+
const ps = m.params.map((p) => goTypeKey(p)).join("_");
|
|
354
|
+
const rs = m.returns.map((r) => goTypeKey(r)).join("_");
|
|
355
|
+
return `${m.name}_${ps}_${rs}`;
|
|
356
|
+
});
|
|
357
|
+
const key = parts.join("__").replace(/[^a-zA-Z0-9_]/g, "_");
|
|
358
|
+
return `anon_iface_${key}`;
|
|
359
|
+
}
|
|
360
|
+
|
|
201
361
|
export function isStructType(goType, checker = null, mod = null) {
|
|
202
362
|
if (!goType) return false;
|
|
203
363
|
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
@@ -235,6 +395,20 @@ export function isSliceType(goType, checker = null) {
|
|
|
235
395
|
return goType.kind === "slice" || goType.kind === "SliceType";
|
|
236
396
|
}
|
|
237
397
|
|
|
398
|
+
// `gofront/shared` linear-memory buffer: returns the SHARED_KINDS entry
|
|
399
|
+
// (elem, ctor, bytes, key) or null.
|
|
400
|
+
export function getSharedInfo(goType, checker = null) {
|
|
401
|
+
if (!goType) return null;
|
|
402
|
+
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
403
|
+
const resolved = checker?.types?.get(goType.name);
|
|
404
|
+
return resolved ? getSharedInfo(resolved, checker) : null;
|
|
405
|
+
}
|
|
406
|
+
if (goType.kind === "named" && goType.underlying)
|
|
407
|
+
return getSharedInfo(goType.underlying, checker);
|
|
408
|
+
if (goType.kind !== "shared") return null;
|
|
409
|
+
return { name: goType.shared, ...SHARED_KINDS[goType.shared] };
|
|
410
|
+
}
|
|
411
|
+
|
|
238
412
|
export function isArrayType(goType, checker = null) {
|
|
239
413
|
if (!goType) return false;
|
|
240
414
|
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
@@ -247,6 +421,37 @@ export function isArrayType(goType, checker = null) {
|
|
|
247
421
|
return goType.kind === "array" || goType.kind === "ArrayType";
|
|
248
422
|
}
|
|
249
423
|
|
|
424
|
+
export function isMapType(goType, checker = null) {
|
|
425
|
+
if (!goType) return false;
|
|
426
|
+
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
427
|
+
const resolved = checker?.types?.get(goType.name);
|
|
428
|
+
if (resolved) return isMapType(resolved, checker);
|
|
429
|
+
}
|
|
430
|
+
if (goType.kind === "named" && goType.underlying) {
|
|
431
|
+
return isMapType(goType.underlying, checker);
|
|
432
|
+
}
|
|
433
|
+
return goType.kind === "map" || goType.kind === "MapType";
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Returns `{ keyType, valType }` (Go types) for a map type, or nulls.
|
|
437
|
+
export function getMapKeyValTypes(goType, checker = null) {
|
|
438
|
+
if (!goType) return { keyType: null, valType: null };
|
|
439
|
+
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
440
|
+
const resolved = checker?.types?.get(goType.name);
|
|
441
|
+
if (resolved) return getMapKeyValTypes(resolved, checker);
|
|
442
|
+
}
|
|
443
|
+
if (goType.kind === "named" && goType.underlying) {
|
|
444
|
+
return getMapKeyValTypes(goType.underlying, checker);
|
|
445
|
+
}
|
|
446
|
+
if (goType.kind === "map" || goType.kind === "MapType") {
|
|
447
|
+
const key = goType.key ?? goType.keyType;
|
|
448
|
+
const val =
|
|
449
|
+
goType.value ?? goType.elem ?? goType.valueType ?? goType.valType;
|
|
450
|
+
return { keyType: key, valType: val };
|
|
451
|
+
}
|
|
452
|
+
return { keyType: null, valType: null };
|
|
453
|
+
}
|
|
454
|
+
|
|
250
455
|
export function isStringType(goType, checker = null) {
|
|
251
456
|
if (!goType) return false;
|
|
252
457
|
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
@@ -279,27 +484,80 @@ export function isAnyType(goType, checker = null) {
|
|
|
279
484
|
return false;
|
|
280
485
|
}
|
|
281
486
|
|
|
282
|
-
export function
|
|
487
|
+
export function isInterfaceType(goType, checker = null) {
|
|
283
488
|
if (!goType) return false;
|
|
489
|
+
if (
|
|
490
|
+
goType.kind === "basic" &&
|
|
491
|
+
(goType.name === "any" || goType.name === "interface{}")
|
|
492
|
+
)
|
|
493
|
+
return true;
|
|
494
|
+
if (goType.kind === "interface" || goType.kind === "InterfaceType")
|
|
495
|
+
return true;
|
|
284
496
|
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
285
|
-
|
|
497
|
+
if (goType.name === "any" || goType.name === "interface{}") return true;
|
|
498
|
+
const resolved = checker?.types?.get(goType.name);
|
|
499
|
+
if (resolved) return isInterfaceType(resolved, checker);
|
|
286
500
|
}
|
|
287
|
-
if (goType.kind === "named"
|
|
288
|
-
|
|
501
|
+
if (goType.kind === "named") {
|
|
502
|
+
if (goType.name === "any" || goType.name === "interface{}") return true;
|
|
503
|
+
if (goType.underlying) return isInterfaceType(goType.underlying, checker);
|
|
504
|
+
const resolved = checker?.types?.get(goType.name);
|
|
505
|
+
if (resolved) return isInterfaceType(resolved, checker);
|
|
289
506
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
507
|
+
return false;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// The built-in `error` interface (checker ERROR type or its name).
|
|
511
|
+
export function isErrorType(goType) {
|
|
512
|
+
if (!goType) return false;
|
|
513
|
+
if (goType.kind === "interface") return goType.name === "error";
|
|
514
|
+
if (
|
|
515
|
+
(goType.kind === "named" ||
|
|
516
|
+
goType.kind === "TypeName" ||
|
|
517
|
+
goType.kind === "Ident") &&
|
|
518
|
+
goType.name === "error"
|
|
519
|
+
) {
|
|
520
|
+
return true;
|
|
521
|
+
}
|
|
522
|
+
if (goType.kind === "named" && goType.underlying)
|
|
523
|
+
return isErrorType(goType.underlying);
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
export function isNonEmptyInterface(goType, checker = null) {
|
|
528
|
+
if (!goType) return false;
|
|
529
|
+
if (goType.name === "any" || goType.name === "interface{}") return false;
|
|
530
|
+
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
531
|
+
const resolved = checker?.types?.get(goType.name);
|
|
532
|
+
if (resolved) return isNonEmptyInterface(resolved, checker);
|
|
533
|
+
}
|
|
534
|
+
if (goType.kind === "named") {
|
|
535
|
+
if (goType.name === "any" || goType.name === "interface{}") return false;
|
|
536
|
+
if (goType.underlying)
|
|
537
|
+
return isNonEmptyInterface(goType.underlying, checker);
|
|
538
|
+
const resolved = checker?.types?.get(goType.name);
|
|
539
|
+
if (resolved) return isNonEmptyInterface(resolved, checker);
|
|
540
|
+
}
|
|
541
|
+
if (goType.kind === "interface" || goType.kind === "InterfaceType") {
|
|
542
|
+
if (goType.methods instanceof Map) return goType.methods.size > 0;
|
|
543
|
+
if (Array.isArray(goType.methods)) return goType.methods.length > 0;
|
|
544
|
+
if (goType.methods instanceof Set) return goType.methods.size > 0;
|
|
545
|
+
return false;
|
|
299
546
|
}
|
|
300
547
|
return false;
|
|
301
548
|
}
|
|
302
549
|
|
|
550
|
+
export function getReceiverTypeName(recvType, _node = null) {
|
|
551
|
+
if (recvType) {
|
|
552
|
+
let t = recvType;
|
|
553
|
+
while (t.kind === "pointer") t = t.base;
|
|
554
|
+
if (t.name) return t.name;
|
|
555
|
+
if (t.kind === "named") return t.name;
|
|
556
|
+
if (t.kind === "TypeName" || t.kind === "Ident") return t.name;
|
|
557
|
+
}
|
|
558
|
+
return null;
|
|
559
|
+
}
|
|
560
|
+
|
|
303
561
|
export function isSigned(goType) {
|
|
304
562
|
if (!goType) return true;
|
|
305
563
|
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
@@ -329,27 +587,6 @@ export function isFloat(goType) {
|
|
|
329
587
|
);
|
|
330
588
|
}
|
|
331
589
|
|
|
332
|
-
export function isInt(goType) {
|
|
333
|
-
if (!goType) return false;
|
|
334
|
-
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
335
|
-
return isInt({ kind: "basic", name: goType.name });
|
|
336
|
-
}
|
|
337
|
-
if (goType.kind === "named" && goType.underlying) {
|
|
338
|
-
return isInt(goType.underlying);
|
|
339
|
-
}
|
|
340
|
-
if (goType.kind === "untyped") return goType.base === "int";
|
|
341
|
-
if (goType.kind === "basic") {
|
|
342
|
-
return (
|
|
343
|
-
goType.name.startsWith("int") ||
|
|
344
|
-
goType.name.startsWith("uint") ||
|
|
345
|
-
goType.name === "byte" ||
|
|
346
|
-
goType.name === "rune" ||
|
|
347
|
-
goType.name === "uintptr"
|
|
348
|
-
);
|
|
349
|
-
}
|
|
350
|
-
return false;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
590
|
export function isFuncType(goType, checker = null) {
|
|
354
591
|
if (!goType) return false;
|
|
355
592
|
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
@@ -418,3 +655,42 @@ export function getFuncSignature(goType, checker = null) {
|
|
|
418
655
|
}
|
|
419
656
|
return { params: [], returns: [] };
|
|
420
657
|
}
|
|
658
|
+
|
|
659
|
+
export function isUnhashableGoType(goType, checker = null, seen = new Set()) {
|
|
660
|
+
if (!goType) return false;
|
|
661
|
+
if (seen.has(goType)) return false;
|
|
662
|
+
seen.add(goType);
|
|
663
|
+
if (
|
|
664
|
+
isSliceType(goType, checker) ||
|
|
665
|
+
isMapType(goType, checker) ||
|
|
666
|
+
isFuncType(goType, checker)
|
|
667
|
+
) {
|
|
668
|
+
return true;
|
|
669
|
+
}
|
|
670
|
+
if (isArrayType(goType, checker)) {
|
|
671
|
+
const elem = goType.elem ?? goType.underlying?.elem;
|
|
672
|
+
return isUnhashableGoType(elem, checker, seen);
|
|
673
|
+
}
|
|
674
|
+
if (goType.kind === "struct" || goType.kind === "StructType") {
|
|
675
|
+
if (goType.fields instanceof Map) {
|
|
676
|
+
for (const f of goType.fields.values()) {
|
|
677
|
+
if (isUnhashableGoType(f, checker, seen)) return true;
|
|
678
|
+
}
|
|
679
|
+
} else if (Array.isArray(goType.fields)) {
|
|
680
|
+
for (const f of goType.fields) {
|
|
681
|
+
const fType = f.type ?? f.goType;
|
|
682
|
+
if (isUnhashableGoType(fType, checker, seen)) return true;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
687
|
+
const resolved = checker?.types?.get(goType.name);
|
|
688
|
+
if (resolved && resolved !== goType) {
|
|
689
|
+
return isUnhashableGoType(resolved, checker, seen);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
if (goType.kind === "named" && goType.underlying) {
|
|
693
|
+
return isUnhashableGoType(goType.underlying, checker, seen);
|
|
694
|
+
}
|
|
695
|
+
return false;
|
|
696
|
+
}
|
package/src/backend/wasm/wat.js
CHANGED
|
@@ -83,6 +83,21 @@ function formatInstruction(inst) {
|
|
|
83
83
|
case "global.get":
|
|
84
84
|
case "global.set":
|
|
85
85
|
return `${op} ${inst.globalIndex ?? inst.index ?? 0}`;
|
|
86
|
+
case "i32.load":
|
|
87
|
+
case "i64.load":
|
|
88
|
+
case "f32.load":
|
|
89
|
+
case "f64.load":
|
|
90
|
+
case "i32.load8_s":
|
|
91
|
+
case "i32.load8_u":
|
|
92
|
+
case "i32.load16_s":
|
|
93
|
+
case "i32.load16_u":
|
|
94
|
+
case "i32.store":
|
|
95
|
+
case "i64.store":
|
|
96
|
+
case "f32.store":
|
|
97
|
+
case "f64.store":
|
|
98
|
+
case "i32.store8":
|
|
99
|
+
case "i32.store16":
|
|
100
|
+
return inst.offset ? `${op} offset=${inst.offset}` : op;
|
|
86
101
|
case "i32.const":
|
|
87
102
|
case "i64.const":
|
|
88
103
|
return `${op} ${inst.value ?? 0}`;
|
|
@@ -96,6 +111,26 @@ function formatInstruction(inst) {
|
|
|
96
111
|
}
|
|
97
112
|
case "throw":
|
|
98
113
|
return `${op} ${inst.tagIndex ?? inst.index ?? 0}`;
|
|
114
|
+
case "throw_ref":
|
|
115
|
+
return "throw_ref";
|
|
116
|
+
case "try_table": {
|
|
117
|
+
const bt = inst.blockType ?? inst.resultType;
|
|
118
|
+
const res = bt && bt !== "void" ? ` (result ${formatValType(bt)})` : "";
|
|
119
|
+
const catches = (inst.catches ?? [])
|
|
120
|
+
.map((c) => {
|
|
121
|
+
const k = c.kind ?? c.op;
|
|
122
|
+
if (k === "catch")
|
|
123
|
+
return `(catch ${c.tagIndex ?? 0} ${c.label ?? 0})`;
|
|
124
|
+
if (k === "catch_ref")
|
|
125
|
+
return `(catch_ref ${c.tagIndex ?? 0} ${c.label ?? 0})`;
|
|
126
|
+
if (k === "catch_all") return `(catch_all ${c.label ?? 0})`;
|
|
127
|
+
if (k === "catch_all_ref") return `(catch_all_ref ${c.label ?? 0})`;
|
|
128
|
+
return "";
|
|
129
|
+
})
|
|
130
|
+
.filter(Boolean)
|
|
131
|
+
.join(" ");
|
|
132
|
+
return `${op}${res}${catches ? ` ${catches}` : ""}`;
|
|
133
|
+
}
|
|
99
134
|
case "struct.new":
|
|
100
135
|
return `struct.new ${inst.typeIndex !== undefined ? `$t${inst.typeIndex}` : 0}`;
|
|
101
136
|
case "struct.get":
|
|
@@ -119,8 +154,15 @@ function formatInstruction(inst) {
|
|
|
119
154
|
case "ref.test":
|
|
120
155
|
case "ref.test_null":
|
|
121
156
|
case "ref.cast":
|
|
122
|
-
case "ref.cast_null":
|
|
123
|
-
|
|
157
|
+
case "ref.cast_null": {
|
|
158
|
+
const ht =
|
|
159
|
+
inst.typeIndex !== undefined
|
|
160
|
+
? `$t${inst.typeIndex}`
|
|
161
|
+
: inst.heapType !== undefined
|
|
162
|
+
? String(inst.heapType)
|
|
163
|
+
: 0;
|
|
164
|
+
return `${op} ${ht}`;
|
|
165
|
+
}
|
|
124
166
|
case "any.convert_extern":
|
|
125
167
|
case "extern.convert_any":
|
|
126
168
|
return op;
|
|
@@ -166,6 +208,11 @@ export function emitWat(mod) {
|
|
|
166
208
|
}
|
|
167
209
|
}
|
|
168
210
|
|
|
211
|
+
if (mod.memory) {
|
|
212
|
+
const max = mod.memory.max != null ? ` ${mod.memory.max}` : "";
|
|
213
|
+
lines.push(` (memory $mem ${mod.memory.min}${max})`);
|
|
214
|
+
}
|
|
215
|
+
|
|
169
216
|
// 4. Globals
|
|
170
217
|
if (mod.globals && mod.globals.length > 0) {
|
|
171
218
|
for (let i = 0; i < mod.globals.length; i++) {
|