gofront 1.6.0 → 1.7.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 +35 -39
- package/package.json +37 -4
- package/src/backend/js/expressions.js +559 -144
- package/src/backend/js/index.js +174 -49
- package/src/backend/js/runtime.js +1518 -54
- package/src/backend/js/statements.js +91 -73
- 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 +25 -1
- package/src/backend/js/stdlib/fmt.js +70 -13
- 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 +28 -0
- package/src/backend/js/stdlib/io.js +105 -3
- package/src/backend/js/stdlib/json.js +972 -0
- package/src/backend/js/stdlib/math.js +13 -1
- package/src/backend/js/stdlib/path.js +18 -4
- package/src/backend/js/stdlib/rand.js +10 -5
- package/src/backend/js/stdlib/sha256.js +12 -0
- package/src/backend/js/stdlib/simd.js +24 -0
- package/src/backend/js/stdlib/slices.js +52 -26
- package/src/backend/js/stdlib/strconv.js +21 -5
- package/src/backend/js/stdlib/strings.js +148 -15
- package/src/backend/js/stdlib/sync.js +13 -0
- package/src/backend/js/stdlib/time.js +90 -19
- package/src/backend/js/stdlib/unicode.js +2 -2
- package/src/backend/wasm/boundary.js +1225 -41
- package/src/backend/wasm/const-fold.js +205 -0
- package/src/backend/wasm/emit-builtins.js +220 -76
- package/src/backend/wasm/emit-exprs.js +475 -276
- package/src/backend/wasm/emit-maps.js +144 -8
- package/src/backend/wasm/emit-stdlib.js +12 -3005
- package/src/backend/wasm/emit-stmts.js +264 -270
- package/src/backend/wasm/emit.js +124 -87
- package/src/backend/wasm/encode.js +140 -29
- package/src/backend/wasm/index.js +1001 -32
- package/src/backend/wasm/optimize.js +17 -6
- 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 +43 -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/simd.js +234 -0
- package/src/backend/wasm/stdlib/time.js +1200 -0
- package/src/backend/wasm/types.js +174 -1
- package/src/backend/wasm/wat.js +37 -0
- package/src/cli-core.js +1 -1
- package/src/compiler.js +18 -4
- package/src/dts-parser.js +150 -140
- package/src/index.js +2 -6
- package/src/lexer.js +80 -29
- package/src/lower/boxing.js +1 -7
- package/src/lower/captures.js +2 -6
- package/src/lower/embedding.js +2 -1
- package/src/lower/ownership.js +30 -9
- 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/struct-tag.js +144 -0
- package/src/parser/types.js +64 -8
- package/src/resolver.js +2 -27
- package/src/templ-lexer.js +29 -63
- package/src/templ-parser.js +22 -45
- package/src/typechecker/assignability.js +126 -13
- package/src/typechecker/expressions.js +168 -16
- package/src/typechecker/index.js +35 -8
- package/src/typechecker/resolve.js +187 -8
- package/src/typechecker/statements.js +68 -9
- package/src/typechecker/stdlib/core.js +280 -89
- package/src/typechecker/stdlib/extended.js +490 -1
- package/src/typechecker/stdlib/simd.js +73 -0
- package/src/typechecker/stdlib.js +2 -0
- package/src/typechecker/types.js +362 -9
- package/src/vendor.js +86 -11
|
@@ -27,6 +27,7 @@ export function toWasmType(goType, checker = null, mod = null) {
|
|
|
27
27
|
goType === "i64" ||
|
|
28
28
|
goType === "f32" ||
|
|
29
29
|
goType === "f64" ||
|
|
30
|
+
goType === "v128" ||
|
|
30
31
|
goType === "anyref" ||
|
|
31
32
|
goType === "externref" ||
|
|
32
33
|
goType === "funcref"
|
|
@@ -39,6 +40,16 @@ export function toWasmType(goType, checker = null, mod = null) {
|
|
|
39
40
|
}
|
|
40
41
|
if (isTestingT(goType)) return "externref";
|
|
41
42
|
|
|
43
|
+
if (
|
|
44
|
+
goType.kind === "simd" ||
|
|
45
|
+
(goType.kind === "named" &&
|
|
46
|
+
(goType.name === "simd.F32x4" ||
|
|
47
|
+
goType.name === "F32x4" ||
|
|
48
|
+
goType.underlying?.kind === "simd"))
|
|
49
|
+
) {
|
|
50
|
+
return "v128";
|
|
51
|
+
}
|
|
52
|
+
|
|
42
53
|
// Pointer AST nodes
|
|
43
54
|
if (goType.kind === "PointerType") {
|
|
44
55
|
return toWasmType({ kind: "pointer", base: goType.base }, checker, mod);
|
|
@@ -68,6 +79,9 @@ export function toWasmType(goType, checker = null, mod = null) {
|
|
|
68
79
|
|
|
69
80
|
// TypeName AST node
|
|
70
81
|
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
82
|
+
if (goType.name === "simd.F32x4" || goType.name === "F32x4") {
|
|
83
|
+
return "v128";
|
|
84
|
+
}
|
|
71
85
|
if (mod?.getStructType(goType.name)) {
|
|
72
86
|
return {
|
|
73
87
|
kind: "ref",
|
|
@@ -84,6 +98,13 @@ export function toWasmType(goType, checker = null, mod = null) {
|
|
|
84
98
|
|
|
85
99
|
// Unwrap named types
|
|
86
100
|
if (goType.kind === "named") {
|
|
101
|
+
if (
|
|
102
|
+
goType.name === "simd.F32x4" ||
|
|
103
|
+
goType.name === "F32x4" ||
|
|
104
|
+
goType.underlying?.kind === "simd"
|
|
105
|
+
) {
|
|
106
|
+
return "v128";
|
|
107
|
+
}
|
|
87
108
|
if (mod?.getStructType(goType.name)) {
|
|
88
109
|
return {
|
|
89
110
|
kind: "ref",
|
|
@@ -142,6 +163,7 @@ export function toWasmType(goType, checker = null, mod = null) {
|
|
|
142
163
|
return "externref";
|
|
143
164
|
|
|
144
165
|
case "any":
|
|
166
|
+
case "error":
|
|
145
167
|
return "anyref";
|
|
146
168
|
|
|
147
169
|
case "void":
|
|
@@ -220,7 +242,7 @@ export function toWasmType(goType, checker = null, mod = null) {
|
|
|
220
242
|
return { kind: "ref", nullable: true, heapType: "struct" };
|
|
221
243
|
}
|
|
222
244
|
|
|
223
|
-
if (goType.kind === "struct") {
|
|
245
|
+
if (goType.kind === "struct" || goType.kind === "StructType") {
|
|
224
246
|
if (goType.name && mod?.getStructType(goType.name)) {
|
|
225
247
|
return {
|
|
226
248
|
kind: "ref",
|
|
@@ -228,6 +250,23 @@ export function toWasmType(goType, checker = null, mod = null) {
|
|
|
228
250
|
typeIndex: mod.getStructType(goType.name).typeIndex,
|
|
229
251
|
};
|
|
230
252
|
}
|
|
253
|
+
if (mod?.getAnonStructType && goType.fields) {
|
|
254
|
+
const rawFields = [];
|
|
255
|
+
if (goType.fields instanceof Map) {
|
|
256
|
+
for (const [k, v] of goType.fields.entries()) {
|
|
257
|
+
rawFields.push({ name: k, goType: v });
|
|
258
|
+
}
|
|
259
|
+
} else if (Array.isArray(goType.fields)) {
|
|
260
|
+
for (const f of goType.fields) {
|
|
261
|
+
const names = f.names ?? (f.name ? [f.name] : []);
|
|
262
|
+
for (const n of names) rawFields.push({ name: n, goType: f.type });
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
if (rawFields.length > 0) {
|
|
266
|
+
const info = mod.getAnonStructType(rawFields);
|
|
267
|
+
return { kind: "ref", nullable: true, typeIndex: info.typeIndex };
|
|
268
|
+
}
|
|
269
|
+
}
|
|
231
270
|
return { kind: "ref", nullable: true, heapType: "struct" };
|
|
232
271
|
}
|
|
233
272
|
|
|
@@ -250,6 +289,96 @@ export function toWasmType(goType, checker = null, mod = null) {
|
|
|
250
289
|
return "i32";
|
|
251
290
|
}
|
|
252
291
|
|
|
292
|
+
export function getInterfaceMethodList(iface) {
|
|
293
|
+
if (!iface) return [];
|
|
294
|
+
if (iface.methods instanceof Map) {
|
|
295
|
+
return Array.from(iface.methods.entries()).map(([name, sig]) => ({
|
|
296
|
+
name,
|
|
297
|
+
params: (sig.params ?? []).map((p) => p.type ?? p),
|
|
298
|
+
returns: (sig.returns ?? []).map((r) => r.type ?? r),
|
|
299
|
+
}));
|
|
300
|
+
}
|
|
301
|
+
if (Array.isArray(iface.methods)) {
|
|
302
|
+
return iface.methods.map((m) => ({
|
|
303
|
+
name: m.name?.value ?? m.name ?? m,
|
|
304
|
+
params: (m.params ?? []).map((p) => p.type ?? p),
|
|
305
|
+
returns: m.returnType
|
|
306
|
+
? m.returnType.kind === "TupleType" || m.returnType.kind === "tuple"
|
|
307
|
+
? m.returnType.types
|
|
308
|
+
: [m.returnType]
|
|
309
|
+
: [],
|
|
310
|
+
}));
|
|
311
|
+
}
|
|
312
|
+
return [];
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export function goTypeKey(t) {
|
|
316
|
+
if (!t) return "any";
|
|
317
|
+
if (typeof t === "string") {
|
|
318
|
+
if (t === "byte") return "uint8";
|
|
319
|
+
if (t === "rune") return "int32";
|
|
320
|
+
return t;
|
|
321
|
+
}
|
|
322
|
+
if (t.kind === "basic" || t.kind === "TypeName" || t.kind === "Ident") {
|
|
323
|
+
const name = t.name ?? "any";
|
|
324
|
+
if (name === "byte") return "uint8";
|
|
325
|
+
if (name === "rune") return "int32";
|
|
326
|
+
return name;
|
|
327
|
+
}
|
|
328
|
+
if (t.kind === "untyped") {
|
|
329
|
+
return t.base ?? "int";
|
|
330
|
+
}
|
|
331
|
+
if (t.kind === "pointer" || t.kind === "PointerType") {
|
|
332
|
+
return `ptr_${goTypeKey(t.base)}`;
|
|
333
|
+
}
|
|
334
|
+
if (t.kind === "StarExpr") {
|
|
335
|
+
return `ptr_${goTypeKey(t.expr ?? t.operand)}`;
|
|
336
|
+
}
|
|
337
|
+
if (t.kind === "slice" || t.kind === "SliceType") {
|
|
338
|
+
return `sl_${goTypeKey(t.elem)}`;
|
|
339
|
+
}
|
|
340
|
+
if (t.kind === "array" || t.kind === "ArrayType") {
|
|
341
|
+
const sz =
|
|
342
|
+
typeof t.size === "number" ? t.size : (t.size?.value ?? t.len ?? "");
|
|
343
|
+
return `arr_${sz}_${goTypeKey(t.elem)}`;
|
|
344
|
+
}
|
|
345
|
+
if (t.kind === "map" || t.kind === "MapType") {
|
|
346
|
+
return `map_${goTypeKey(t.key ?? t.keyType)}_${goTypeKey(t.value ?? t.val ?? t.elem ?? t.valueType ?? t.valType)}`;
|
|
347
|
+
}
|
|
348
|
+
if (t.kind === "struct" || t.kind === "StructType") {
|
|
349
|
+
if (t.name) return t.name;
|
|
350
|
+
const rawFields = [];
|
|
351
|
+
if (t.fields instanceof Map) {
|
|
352
|
+
for (const [k, v] of t.fields.entries())
|
|
353
|
+
rawFields.push(`${k}:${goTypeKey(v)}`);
|
|
354
|
+
} else if (Array.isArray(t.fields)) {
|
|
355
|
+
for (const f of t.fields) {
|
|
356
|
+
const names = f.names ?? (f.name ? [f.name] : []);
|
|
357
|
+
for (const n of names)
|
|
358
|
+
rawFields.push(`${n}:${goTypeKey(f.type ?? f.goType)}`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return `struct_${rawFields.join("_")}`;
|
|
362
|
+
}
|
|
363
|
+
if (t.kind === "named") {
|
|
364
|
+
return t.name ?? (t.underlying ? goTypeKey(t.underlying) : "any");
|
|
365
|
+
}
|
|
366
|
+
if (t.name) return t.name;
|
|
367
|
+
return t.kind ?? "any";
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export function anonIfaceName(iface, _checker = null, _mod = null) {
|
|
371
|
+
const methods = getInterfaceMethodList(iface);
|
|
372
|
+
methods.sort((a, b) => a.name.localeCompare(b.name));
|
|
373
|
+
const parts = methods.map((m) => {
|
|
374
|
+
const ps = m.params.map((p) => goTypeKey(p)).join("_");
|
|
375
|
+
const rs = m.returns.map((r) => goTypeKey(r)).join("_");
|
|
376
|
+
return `${m.name}_${ps}_${rs}`;
|
|
377
|
+
});
|
|
378
|
+
const key = parts.join("__").replace(/[^a-zA-Z0-9_]/g, "_");
|
|
379
|
+
return `anon_iface_${key}`;
|
|
380
|
+
}
|
|
381
|
+
|
|
253
382
|
export function isStructType(goType, checker = null, mod = null) {
|
|
254
383
|
if (!goType) return false;
|
|
255
384
|
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
@@ -378,6 +507,11 @@ export function isAnyType(goType, checker = null) {
|
|
|
378
507
|
|
|
379
508
|
export function isInterfaceType(goType, checker = null) {
|
|
380
509
|
if (!goType) return false;
|
|
510
|
+
if (
|
|
511
|
+
goType.kind === "basic" &&
|
|
512
|
+
(goType.name === "any" || goType.name === "interface{}")
|
|
513
|
+
)
|
|
514
|
+
return true;
|
|
381
515
|
if (goType.kind === "interface" || goType.kind === "InterfaceType")
|
|
382
516
|
return true;
|
|
383
517
|
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
@@ -542,3 +676,42 @@ export function getFuncSignature(goType, checker = null) {
|
|
|
542
676
|
}
|
|
543
677
|
return { params: [], returns: [] };
|
|
544
678
|
}
|
|
679
|
+
|
|
680
|
+
export function isUnhashableGoType(goType, checker = null, seen = new Set()) {
|
|
681
|
+
if (!goType) return false;
|
|
682
|
+
if (seen.has(goType)) return false;
|
|
683
|
+
seen.add(goType);
|
|
684
|
+
if (
|
|
685
|
+
isSliceType(goType, checker) ||
|
|
686
|
+
isMapType(goType, checker) ||
|
|
687
|
+
isFuncType(goType, checker)
|
|
688
|
+
) {
|
|
689
|
+
return true;
|
|
690
|
+
}
|
|
691
|
+
if (isArrayType(goType, checker)) {
|
|
692
|
+
const elem = goType.elem ?? goType.underlying?.elem;
|
|
693
|
+
return isUnhashableGoType(elem, checker, seen);
|
|
694
|
+
}
|
|
695
|
+
if (goType.kind === "struct" || goType.kind === "StructType") {
|
|
696
|
+
if (goType.fields instanceof Map) {
|
|
697
|
+
for (const f of goType.fields.values()) {
|
|
698
|
+
if (isUnhashableGoType(f, checker, seen)) return true;
|
|
699
|
+
}
|
|
700
|
+
} else if (Array.isArray(goType.fields)) {
|
|
701
|
+
for (const f of goType.fields) {
|
|
702
|
+
const fType = f.type ?? f.goType;
|
|
703
|
+
if (isUnhashableGoType(fType, checker, seen)) return true;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
if (goType.kind === "TypeName" || goType.kind === "Ident") {
|
|
708
|
+
const resolved = checker?.types?.get(goType.name);
|
|
709
|
+
if (resolved && resolved !== goType) {
|
|
710
|
+
return isUnhashableGoType(resolved, checker, seen);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
if (goType.kind === "named" && goType.underlying) {
|
|
714
|
+
return isUnhashableGoType(goType.underlying, checker, seen);
|
|
715
|
+
}
|
|
716
|
+
return false;
|
|
717
|
+
}
|
package/src/backend/wasm/wat.js
CHANGED
|
@@ -98,6 +98,43 @@ function formatInstruction(inst) {
|
|
|
98
98
|
case "i32.store8":
|
|
99
99
|
case "i32.store16":
|
|
100
100
|
return inst.offset ? `${op} offset=${inst.offset}` : op;
|
|
101
|
+
case "v128.load":
|
|
102
|
+
case "v128.store": {
|
|
103
|
+
const parts = [op];
|
|
104
|
+
if (inst.offset) parts.push(`offset=${inst.offset}`);
|
|
105
|
+
if (inst.align !== undefined) parts.push(`align=${1 << inst.align}`);
|
|
106
|
+
return parts.join(" ");
|
|
107
|
+
}
|
|
108
|
+
case "v128.const": {
|
|
109
|
+
if (inst.values && inst.values.length === 4) {
|
|
110
|
+
return `${op} f32x4 ${inst.values.join(" ")}`;
|
|
111
|
+
}
|
|
112
|
+
if (inst.bytes) {
|
|
113
|
+
const b = new Uint8Array(16);
|
|
114
|
+
b.set(inst.bytes.slice(0, 16));
|
|
115
|
+
const dv = new DataView(b.buffer);
|
|
116
|
+
return `${op} i32x4 ${dv.getInt32(0, true)} ${dv.getInt32(4, true)} ${dv.getInt32(8, true)} ${dv.getInt32(12, true)}`;
|
|
117
|
+
}
|
|
118
|
+
return `${op} i32x4 0 0 0 0`;
|
|
119
|
+
}
|
|
120
|
+
case "i8x16.shuffle": {
|
|
121
|
+
const lanes = (inst.lanes ?? inst.indices ?? []).slice(0, 16);
|
|
122
|
+
while (lanes.length < 16) lanes.push(0);
|
|
123
|
+
return `${op} ${lanes.join(" ")}`;
|
|
124
|
+
}
|
|
125
|
+
case "i8x16.extract_lane_s":
|
|
126
|
+
case "i8x16.extract_lane_u":
|
|
127
|
+
case "i8x16.replace_lane":
|
|
128
|
+
case "i16x8.extract_lane_s":
|
|
129
|
+
case "i16x8.extract_lane_u":
|
|
130
|
+
case "i16x8.replace_lane":
|
|
131
|
+
case "i32x4.extract_lane":
|
|
132
|
+
case "i32x4.replace_lane":
|
|
133
|
+
case "i64x2.extract_lane":
|
|
134
|
+
case "i64x2.replace_lane":
|
|
135
|
+
case "f32x4.extract_lane":
|
|
136
|
+
case "f32x4.replace_lane":
|
|
137
|
+
return `${op} ${inst.lane ?? inst.index ?? 0}`;
|
|
101
138
|
case "i32.const":
|
|
102
139
|
case "i64.const":
|
|
103
140
|
return `${op} ${inst.value ?? 0}`;
|
package/src/cli-core.js
CHANGED
|
@@ -33,7 +33,7 @@ import { generatePwa } from "./pwa.js";
|
|
|
33
33
|
import { runTests } from "./test-runner.js";
|
|
34
34
|
import { bundleVendor } from "./vendor.js";
|
|
35
35
|
|
|
36
|
-
const GOFRONT_VERSION = JSON.parse(
|
|
36
|
+
export const GOFRONT_VERSION = JSON.parse(
|
|
37
37
|
readFileSync(new URL("../package.json", import.meta.url), "utf8"),
|
|
38
38
|
).version;
|
|
39
39
|
|
package/src/compiler.js
CHANGED
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
} from "./resolver.js";
|
|
39
39
|
import { TemplLexer } from "./templ-lexer.js";
|
|
40
40
|
import { TemplParser } from "./templ-parser.js";
|
|
41
|
-
import { TypeChecker } from "./typechecker/index.js";
|
|
41
|
+
import { TypeCheckError, TypeChecker } from "./typechecker/index.js";
|
|
42
42
|
import { WASM_SUPPORTED_STDLIB } from "./typechecker/types.js";
|
|
43
43
|
|
|
44
44
|
// ── Parse cache ──────────────────────────────────────────────
|
|
@@ -203,6 +203,7 @@ function finishWasm(options, merged, pkgTarget, outputDir) {
|
|
|
203
203
|
inputSourceMap: wasmSourceMap,
|
|
204
204
|
sourceMapUrl: WASM_MAP_URL,
|
|
205
205
|
emitWat: Boolean(options.emitWat),
|
|
206
|
+
converge: Boolean(options.release),
|
|
206
207
|
});
|
|
207
208
|
wasm = opt.wasm;
|
|
208
209
|
if (opt.wat) wat = opt.wat;
|
|
@@ -269,7 +270,20 @@ function linkWasmUnits(
|
|
|
269
270
|
for (const b of u.bundledPackages) bundledPackages.add(b);
|
|
270
271
|
programs.push(...u.programs);
|
|
271
272
|
}
|
|
272
|
-
const checker = {
|
|
273
|
+
const checker = {
|
|
274
|
+
types,
|
|
275
|
+
errors: [],
|
|
276
|
+
err(msg, node) {
|
|
277
|
+
const e = new TypeCheckError(
|
|
278
|
+
msg,
|
|
279
|
+
node,
|
|
280
|
+
this._currentFile,
|
|
281
|
+
this._currentSource,
|
|
282
|
+
);
|
|
283
|
+
this.errors.push(e);
|
|
284
|
+
return e;
|
|
285
|
+
},
|
|
286
|
+
};
|
|
273
287
|
const lowerRes = lower(programs, checker);
|
|
274
288
|
return compileWasmModule(programs, checker, lowerRes, {
|
|
275
289
|
boundary: true,
|
|
@@ -809,8 +823,8 @@ export function compileFiles(files, options = {}) {
|
|
|
809
823
|
|
|
810
824
|
const mainChunk = {
|
|
811
825
|
js: mainJs,
|
|
812
|
-
sourceFiles:
|
|
813
|
-
sourcesContent:
|
|
826
|
+
sourceFiles: programs.map((p) => p._path),
|
|
827
|
+
sourcesContent: programs.map((p) => p._source),
|
|
814
828
|
mappings: emitTarget === "wasm" ? [] : codegen.getMappings(),
|
|
815
829
|
};
|
|
816
830
|
|