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.
Files changed (91) hide show
  1. package/README.md +174 -466
  2. package/package.json +16 -20
  3. package/src/backend/js/expressions.js +288 -128
  4. package/src/backend/js/index.js +138 -56
  5. package/src/backend/js/runtime.js +1055 -53
  6. package/src/backend/js/source-map.js +32 -0
  7. package/src/backend/js/statements.js +151 -83
  8. package/src/backend/js/stdlib/base64.js +12 -0
  9. package/src/backend/js/stdlib/binary.js +102 -0
  10. package/src/backend/js/stdlib/bits.js +15 -1
  11. package/src/backend/js/stdlib/builder.js +28 -9
  12. package/src/backend/js/stdlib/bytes.js +75 -18
  13. package/src/backend/js/stdlib/errors.js +22 -3
  14. package/src/backend/js/stdlib/fmt.js +95 -20
  15. package/src/backend/js/stdlib/hex.js +17 -0
  16. package/src/backend/js/stdlib/html.js +1 -1
  17. package/src/backend/js/stdlib/index.js +19 -0
  18. package/src/backend/js/stdlib/io.js +105 -3
  19. package/src/backend/js/stdlib/maps.js +1 -1
  20. package/src/backend/js/stdlib/math.js +13 -1
  21. package/src/backend/js/stdlib/path.js +20 -6
  22. package/src/backend/js/stdlib/rand.js +10 -5
  23. package/src/backend/js/stdlib/sha256.js +12 -0
  24. package/src/backend/js/stdlib/shared.js +17 -0
  25. package/src/backend/js/stdlib/slices.js +53 -27
  26. package/src/backend/js/stdlib/sort.js +1 -1
  27. package/src/backend/js/stdlib/strconv.js +52 -11
  28. package/src/backend/js/stdlib/strings.js +152 -16
  29. package/src/backend/js/stdlib/sync.js +13 -0
  30. package/src/backend/js/stdlib/testing.js +2 -2
  31. package/src/backend/js/stdlib/time.js +93 -22
  32. package/src/backend/js/stdlib/unicode.js +2 -2
  33. package/src/backend/js/templ.js +1 -1
  34. package/src/backend/wasm/boundary.js +1677 -58
  35. package/src/backend/wasm/const-fold.js +205 -0
  36. package/src/backend/wasm/emit-builtins.js +1230 -0
  37. package/src/backend/wasm/emit-exprs.js +2096 -0
  38. package/src/backend/wasm/emit-maps.js +1999 -0
  39. package/src/backend/wasm/emit-shared.js +519 -0
  40. package/src/backend/wasm/emit-stdlib.js +13 -0
  41. package/src/backend/wasm/emit-stmts.js +2466 -0
  42. package/src/backend/wasm/emit.js +656 -5031
  43. package/src/backend/wasm/encode.js +259 -85
  44. package/src/backend/wasm/glue.js +19 -5
  45. package/src/backend/wasm/index.js +2432 -86
  46. package/src/backend/wasm/monomorph.js +711 -0
  47. package/src/backend/wasm/optimize.js +236 -0
  48. package/src/backend/wasm/stdlib/bytes.js +5039 -0
  49. package/src/backend/wasm/stdlib/core.js +8903 -0
  50. package/src/backend/wasm/stdlib/index.js +40 -0
  51. package/src/backend/wasm/stdlib/io.js +2161 -0
  52. package/src/backend/wasm/stdlib/packages.js +2400 -0
  53. package/src/backend/wasm/stdlib/pure.js +720 -0
  54. package/src/backend/wasm/stdlib/time.js +1200 -0
  55. package/src/backend/wasm/types.js +312 -36
  56. package/src/backend/wasm/wat.js +49 -2
  57. package/src/cli-core.js +276 -73
  58. package/src/compiler.js +162 -25
  59. package/src/dts-parser.js +79 -126
  60. package/src/index.js +88 -121
  61. package/src/lexer.js +80 -29
  62. package/src/lower/boxing.js +4 -6
  63. package/src/lower/captures.js +12 -23
  64. package/src/lower/escape.js +4 -9
  65. package/src/lower/functions.js +277 -5
  66. package/src/lower/globals.js +7 -15
  67. package/src/lower/index.js +5 -2
  68. package/src/lower/ownership.js +35 -19
  69. package/src/lower/range.js +2 -5
  70. package/src/lower/walk.js +25 -0
  71. package/src/minifier.js +20 -68
  72. package/src/parser/declarations.js +3 -6
  73. package/src/parser/expressions.js +3 -8
  74. package/src/parser/index.js +18 -3
  75. package/src/parser/statements.js +25 -38
  76. package/src/parser/types.js +1 -2
  77. package/src/resolver.js +3 -27
  78. package/src/templ-lexer.js +29 -63
  79. package/src/templ-parser.js +22 -45
  80. package/src/test-runner.js +20 -0
  81. package/src/typechecker/assignability.js +123 -14
  82. package/src/typechecker/expressions.js +244 -4
  83. package/src/typechecker/index.js +27 -1
  84. package/src/typechecker/resolve.js +71 -12
  85. package/src/typechecker/statements.js +0 -7
  86. package/src/typechecker/stdlib/core.js +292 -103
  87. package/src/typechecker/stdlib/extended.js +471 -4
  88. package/src/typechecker/stdlib/shared.js +53 -0
  89. package/src/typechecker/stdlib.js +2 -0
  90. package/src/typechecker/types.js +545 -8
  91. package/src/vendor.js +2 -2
@@ -4,6 +4,7 @@
4
4
  import {
5
5
  ANY,
6
6
  BASIC_TYPES,
7
+ COMPARABLE,
7
8
  defaultType,
8
9
  isAny,
9
10
  isTypedArraySlice,
@@ -12,6 +13,7 @@ import {
12
13
  typedArrayConstructorForElem,
13
14
  typeStr,
14
15
  VOID,
16
+ WASM_STDLIB_MEMBERS,
15
17
  } from "./types.js";
16
18
 
17
19
  /** @typedef {import('./index.js').TypeChecker} TypeChecker */
@@ -81,8 +83,7 @@ export const resolveMethods = {
81
83
  switch (node.kind) {
82
84
  case "TypeName": {
83
85
  if (BASIC_TYPES[node.name]) return BASIC_TYPES[node.name];
84
- if (node.name === "comparable")
85
- return { kind: "basic", name: "comparable" };
86
+ if (node.name === "comparable") return COMPARABLE;
86
87
  if (scope) {
87
88
  const fromScope = scope.lookup(node.name);
88
89
  if (fromScope?.kind === "typeParam") return fromScope;
@@ -96,16 +97,29 @@ export const resolveMethods = {
96
97
  }
97
98
  return this.err(`Unknown type '${node.name}'`, node);
98
99
  }
99
- case "GenericTypeName": {
100
- const base = this.types.get(node.name);
101
- if (!base) return this.err(`Unknown type '${node.name}'`, node);
102
- if (base.kind === "named" && base._generic)
103
- return this.instantiateGenericType(
100
+ case "GenericTypeName":
101
+ case "InstantiationExpr":
102
+ case "IndexExpr": {
103
+ const name =
104
+ node.name ?? (node.expr?.kind === "Ident" ? node.expr.name : null);
105
+ const typeArgs = node.typeArgs ?? (node.index ? [node.index] : []);
106
+ const base = name
107
+ ? this.types.get(name)
108
+ : node.expr
109
+ ? this.resolveTypeNode(node.expr, scope)
110
+ : null;
111
+ if (!base) return this.err(`Unknown type '${name ?? "?"}'`, node);
112
+ if (base.kind === "named" && base._generic) {
113
+ const res = this.instantiateGenericType(
104
114
  base._generic,
105
- node.typeArgs,
115
+ typeArgs,
106
116
  scope,
107
117
  );
108
- return this.err(`Type '${node.name}' is not generic`, node);
118
+ node._typeArgs = res.typeArgs;
119
+ node._genericType = base;
120
+ return res;
121
+ }
122
+ return this.err(`Type '${name ?? "?"}' is not generic`, node);
109
123
  }
110
124
  case "TypeParam": {
111
125
  const constraint = node.constraint
@@ -266,12 +280,15 @@ export const resolveMethods = {
266
280
  const typeArgs = typeArgNodes.map((n) => this.resolveTypeNode(n, scope));
267
281
  for (let i = 0; i < generic.typeParams.length; i++)
268
282
  map.set(generic.typeParams[i].name, typeArgs[i] ?? ANY);
283
+ // Resolve the declaration with its type params in scope (as typeParams,
284
+ // never as value symbols), then substitute the concrete arguments.
269
285
  const typeScope = new Scope(this.globals);
270
- for (const [name, type] of map) typeScope.define(name, type);
286
+ for (const tp of generic.typeParams) typeScope.define(tp.name, tp);
271
287
  const underlying = this.resolveTypeNode(generic.declNode.type, typeScope);
272
288
  const instantiated = this.substituteType(underlying, map);
273
289
  if (instantiated.kind === "struct") {
274
290
  instantiated.name = generic.declNode.name;
291
+ instantiated.typeArgs = typeArgs;
275
292
  if (!instantiated.methods) instantiated.methods = new Map();
276
293
  if (generic.methods) {
277
294
  for (const [mName, mType] of generic.methods)
@@ -281,7 +298,9 @@ export const resolveMethods = {
281
298
  return {
282
299
  kind: "named",
283
300
  name: generic.declNode.name,
301
+ typeArgs,
284
302
  underlying: instantiated,
303
+ methods: instantiated.methods,
285
304
  };
286
305
  },
287
306
 
@@ -372,6 +391,14 @@ export const resolveMethods = {
372
391
  const found = this.types.get(t.alias);
373
392
  if (found) return found;
374
393
  }
394
+ if (
395
+ t.kind === "named" &&
396
+ (!t.typeArgs || t.typeArgs.length === 0) &&
397
+ (!t.underlying || !t.methods)
398
+ ) {
399
+ const found = this.types.get(t.name);
400
+ if (found) return found;
401
+ }
375
402
  return t;
376
403
  },
377
404
 
@@ -406,6 +433,9 @@ export const resolveMethods = {
406
433
  return this._fieldTypeInterface(base, baseType, field, node);
407
434
  case "namespace":
408
435
  return this._fieldTypeNamespace(base, field, node);
436
+ case "shared":
437
+ if (base.methods?.has(field)) return base.methods.get(field);
438
+ return this.err(`No method '${field}' on ${typeStr(baseType)}`, node);
409
439
  case "slice":
410
440
  if (isTypedArraySlice(base)) {
411
441
  return this._fieldTypeTypedArraySlice(base, baseType, field, node);
@@ -420,7 +450,19 @@ export const resolveMethods = {
420
450
  },
421
451
 
422
452
  _fieldTypeStruct(base, baseType, field, node) {
423
- if (base.fields?.has(field)) return base.fields.get(field);
453
+ if (base.fields?.has(field)) {
454
+ if (
455
+ field.startsWith("_") &&
456
+ (baseType?.name?.startsWith("strings.") ||
457
+ baseType?.name?.startsWith("bytes."))
458
+ ) {
459
+ return this.err(
460
+ `Cannot refer to unexported field '${field}' on ${typeStr(baseType)}`,
461
+ node,
462
+ );
463
+ }
464
+ return base.fields.get(field);
465
+ }
424
466
  if (base.methods?.has(field)) return base.methods.get(field);
425
467
  return this.err(`No field '${field}' on ${typeStr(baseType)}`, node);
426
468
  },
@@ -475,7 +517,24 @@ export const resolveMethods = {
475
517
  `cannot refer to unexported name ${base.name}.${field}`,
476
518
  node,
477
519
  );
478
- if (field in base.members) return base.members[field];
520
+ if (field in base.members) {
521
+ if (
522
+ (this.target === "wasm" || this.target === "both") &&
523
+ WASM_STDLIB_MEMBERS.has(base.name)
524
+ ) {
525
+ const allowed = WASM_STDLIB_MEMBERS.get(base.name);
526
+ if (allowed && !allowed.has(field)) {
527
+ const name = `${base.name}.${field}`;
528
+ this.recordBlocker("unsupported stdlib member", name);
529
+ return this.err(
530
+ `'${name}' is not yet available in wasm packages`,
531
+ node,
532
+ "move this call to a JS package, or use a supported alternative",
533
+ );
534
+ }
535
+ }
536
+ return base.members[field];
537
+ }
479
538
  return this.err(`No member '${field}' in namespace ${base.name}`, node);
480
539
  },
481
540
  };
@@ -43,13 +43,6 @@ export const statementCheckMethods = {
43
43
  this.checkExpr(stmt.expr, scope);
44
44
  break;
45
45
  case "DeferStmt":
46
- if (this.target === "wasm" || this.target === "both") {
47
- this.recordBlocker("defer statement");
48
- this.err(
49
- "'defer' is not yet supported in wasm packages (planned)",
50
- stmt,
51
- );
52
- }
53
46
  if (stmt.call.kind !== "CallExpr")
54
47
  this.err("defer requires a function call", stmt.call);
55
48
  this.checkExpr(stmt.call, scope);