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.
Files changed (80) hide show
  1. package/README.md +35 -39
  2. package/package.json +37 -4
  3. package/src/backend/js/expressions.js +559 -144
  4. package/src/backend/js/index.js +174 -49
  5. package/src/backend/js/runtime.js +1518 -54
  6. package/src/backend/js/statements.js +91 -73
  7. package/src/backend/js/stdlib/base64.js +12 -0
  8. package/src/backend/js/stdlib/binary.js +102 -0
  9. package/src/backend/js/stdlib/bits.js +15 -1
  10. package/src/backend/js/stdlib/builder.js +28 -9
  11. package/src/backend/js/stdlib/bytes.js +75 -18
  12. package/src/backend/js/stdlib/errors.js +25 -1
  13. package/src/backend/js/stdlib/fmt.js +70 -13
  14. package/src/backend/js/stdlib/hex.js +17 -0
  15. package/src/backend/js/stdlib/html.js +1 -1
  16. package/src/backend/js/stdlib/index.js +28 -0
  17. package/src/backend/js/stdlib/io.js +105 -3
  18. package/src/backend/js/stdlib/json.js +972 -0
  19. package/src/backend/js/stdlib/math.js +13 -1
  20. package/src/backend/js/stdlib/path.js +18 -4
  21. package/src/backend/js/stdlib/rand.js +10 -5
  22. package/src/backend/js/stdlib/sha256.js +12 -0
  23. package/src/backend/js/stdlib/simd.js +24 -0
  24. package/src/backend/js/stdlib/slices.js +52 -26
  25. package/src/backend/js/stdlib/strconv.js +21 -5
  26. package/src/backend/js/stdlib/strings.js +148 -15
  27. package/src/backend/js/stdlib/sync.js +13 -0
  28. package/src/backend/js/stdlib/time.js +90 -19
  29. package/src/backend/js/stdlib/unicode.js +2 -2
  30. package/src/backend/wasm/boundary.js +1225 -41
  31. package/src/backend/wasm/const-fold.js +205 -0
  32. package/src/backend/wasm/emit-builtins.js +220 -76
  33. package/src/backend/wasm/emit-exprs.js +475 -276
  34. package/src/backend/wasm/emit-maps.js +144 -8
  35. package/src/backend/wasm/emit-stdlib.js +12 -3005
  36. package/src/backend/wasm/emit-stmts.js +264 -270
  37. package/src/backend/wasm/emit.js +124 -87
  38. package/src/backend/wasm/encode.js +140 -29
  39. package/src/backend/wasm/index.js +1001 -32
  40. package/src/backend/wasm/optimize.js +17 -6
  41. package/src/backend/wasm/stdlib/bytes.js +5039 -0
  42. package/src/backend/wasm/stdlib/core.js +8903 -0
  43. package/src/backend/wasm/stdlib/index.js +43 -0
  44. package/src/backend/wasm/stdlib/io.js +2161 -0
  45. package/src/backend/wasm/stdlib/packages.js +2400 -0
  46. package/src/backend/wasm/stdlib/pure.js +720 -0
  47. package/src/backend/wasm/stdlib/simd.js +234 -0
  48. package/src/backend/wasm/stdlib/time.js +1200 -0
  49. package/src/backend/wasm/types.js +174 -1
  50. package/src/backend/wasm/wat.js +37 -0
  51. package/src/cli-core.js +1 -1
  52. package/src/compiler.js +18 -4
  53. package/src/dts-parser.js +150 -140
  54. package/src/index.js +2 -6
  55. package/src/lexer.js +80 -29
  56. package/src/lower/boxing.js +1 -7
  57. package/src/lower/captures.js +2 -6
  58. package/src/lower/embedding.js +2 -1
  59. package/src/lower/ownership.js +30 -9
  60. package/src/minifier.js +20 -68
  61. package/src/parser/declarations.js +3 -6
  62. package/src/parser/expressions.js +3 -8
  63. package/src/parser/index.js +18 -3
  64. package/src/parser/statements.js +25 -38
  65. package/src/parser/struct-tag.js +144 -0
  66. package/src/parser/types.js +64 -8
  67. package/src/resolver.js +2 -27
  68. package/src/templ-lexer.js +29 -63
  69. package/src/templ-parser.js +22 -45
  70. package/src/typechecker/assignability.js +126 -13
  71. package/src/typechecker/expressions.js +168 -16
  72. package/src/typechecker/index.js +35 -8
  73. package/src/typechecker/resolve.js +187 -8
  74. package/src/typechecker/statements.js +68 -9
  75. package/src/typechecker/stdlib/core.js +280 -89
  76. package/src/typechecker/stdlib/extended.js +490 -1
  77. package/src/typechecker/stdlib/simd.js +73 -0
  78. package/src/typechecker/stdlib.js +2 -0
  79. package/src/typechecker/types.js +362 -9
  80. 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
+ }
@@ -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 = { types };
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: files.map((f) => resolve(f)),
813
- sourcesContent: files.map((f) => readFileSync(f, "utf8")),
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