gofront 1.7.0 → 1.8.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 (128) hide show
  1. package/README.md +13 -13
  2. package/package.json +8 -37
  3. package/src/backend/js/expressions.js +1341 -148
  4. package/src/backend/js/fmt-runtime.js +573 -0
  5. package/src/backend/js/index.js +375 -57
  6. package/src/backend/js/runtime.js +1460 -133
  7. package/src/backend/js/statements.js +900 -86
  8. package/src/backend/js/stdlib/bits.js +87 -14
  9. package/src/backend/js/stdlib/builder.js +41 -6
  10. package/src/backend/js/stdlib/bytes.js +253 -7
  11. package/src/backend/js/stdlib/errors.js +2 -1
  12. package/src/backend/js/stdlib/fmt.js +349 -10
  13. package/src/backend/js/stdlib/index.js +8 -3
  14. package/src/backend/js/stdlib/json.js +247 -52
  15. package/src/backend/js/stdlib/maps.js +0 -8
  16. package/src/backend/js/stdlib/math.js +17 -1
  17. package/src/backend/js/stdlib/simd.js +10 -0
  18. package/src/backend/js/stdlib/slices.js +36 -6
  19. package/src/backend/js/stdlib/strconv.js +10 -5
  20. package/src/backend/js/stdlib/strings.js +83 -4
  21. package/src/backend/js/stdlib/testing.js +7 -0
  22. package/src/backend/js/stdlib/time.js +79 -55
  23. package/src/backend/js/stdlib/unicode.js +1 -1
  24. package/src/backend/js/stdlib/utf8.js +1 -1
  25. package/src/backend/js/templ.js +38 -76
  26. package/src/backend/js/type-info.js +272 -0
  27. package/src/backend/shared/fmt-types.js +188 -0
  28. package/src/backend/wasm/boundary.js +436 -80
  29. package/src/backend/wasm/emit-builtins.js +303 -13
  30. package/src/backend/wasm/emit-exprs.js +1397 -203
  31. package/src/backend/wasm/emit-maps.js +61 -13
  32. package/src/backend/wasm/emit-stmts.js +1359 -164
  33. package/src/backend/wasm/emit.js +512 -77
  34. package/src/backend/wasm/encode.js +43 -13
  35. package/src/backend/wasm/globals.js +452 -0
  36. package/src/backend/wasm/index.js +194 -2489
  37. package/src/backend/wasm/method-expr.js +381 -0
  38. package/src/backend/wasm/module-emitter.js +2240 -0
  39. package/src/backend/wasm/monomorph.js +62 -4
  40. package/src/backend/wasm/prescan.js +397 -0
  41. package/src/backend/wasm/stdlib/bytes.js +1804 -127
  42. package/src/backend/wasm/stdlib/core.js +1574 -199
  43. package/src/backend/wasm/stdlib/index.js +0 -5
  44. package/src/backend/wasm/stdlib/io.js +1567 -150
  45. package/src/backend/wasm/stdlib/packages.js +2 -0
  46. package/src/backend/wasm/stdlib/simd.js +293 -28
  47. package/src/backend/wasm/stdlib/time.js +1041 -12
  48. package/src/backend/wasm/types.js +200 -15
  49. package/src/backend/wasm/variadic.js +93 -0
  50. package/src/backend/wasm/wat.js +47 -20
  51. package/src/{cli-core.js → cli/cli-core.js} +236 -10
  52. package/src/{test-runner.js → cli/test-runner.js} +332 -39
  53. package/src/{vendor.js → cli/vendor.js} +3 -4
  54. package/src/compiler.js +107 -269
  55. package/src/index.js +15 -169
  56. package/src/{lexer.js → lexer/lexer.js} +102 -55
  57. package/src/{tokens.js → lexer/tokens.js} +1 -0
  58. package/src/link/sourcemap.js +97 -0
  59. package/src/link/stdlib.js +515 -0
  60. package/src/link/wasm.js +294 -0
  61. package/src/lower/bounds.js +394 -0
  62. package/src/lower/boxing.js +1 -1
  63. package/src/lower/captures.js +176 -32
  64. package/src/lower/index.js +26 -18
  65. package/src/lower/json-codecs.js +1398 -0
  66. package/src/lower/ownership.js +22 -1
  67. package/src/lower/range.js +86 -1
  68. package/src/lower/reachability.js +132 -0
  69. package/src/parser/declarations.js +58 -13
  70. package/src/parser/expressions.js +29 -7
  71. package/src/parser/index.js +2 -1
  72. package/src/parser/statements.js +37 -22
  73. package/src/{templ-parser.js → parser/templ.js} +138 -15
  74. package/src/parser/types.js +69 -9
  75. package/src/resolver.js +22 -1
  76. package/src/typechecker/assignability.js +176 -17
  77. package/src/typechecker/const-fold.js +356 -0
  78. package/src/typechecker/constants.js +256 -0
  79. package/src/typechecker/expressions.js +931 -122
  80. package/src/typechecker/index.js +459 -67
  81. package/src/typechecker/init-order.js +330 -0
  82. package/src/typechecker/resolve.js +451 -56
  83. package/src/typechecker/statements.js +90 -9
  84. package/src/typechecker/stdlib/core.js +333 -55
  85. package/src/typechecker/stdlib/excluded.js +898 -0
  86. package/src/typechecker/stdlib/extended.js +322 -26
  87. package/src/typechecker/{stdlib.js → stdlib/index.js} +5 -5
  88. package/src/typechecker/stdlib/simd.js +65 -15
  89. package/src/typechecker/termination.js +1 -1
  90. package/src/typechecker/types.js +149 -25
  91. package/stdlib/bytes/iter.go +192 -0
  92. package/stdlib/bytes/search.go +240 -0
  93. package/stdlib/bytes/split.go +218 -0
  94. package/stdlib/cmp/cmp.go +65 -0
  95. package/stdlib/encoding/json/errors.go +31 -0
  96. package/stdlib/encoding/json/indent.go +71 -0
  97. package/stdlib/encoding/json/number.go +12 -0
  98. package/stdlib/encoding/json/stream.go +173 -0
  99. package/stdlib/errors/overlay.go +12 -0
  100. package/stdlib/hash/hash.go +53 -0
  101. package/stdlib/internal/jsonrt/dec.go +738 -0
  102. package/stdlib/internal/jsonrt/enc.go +366 -0
  103. package/stdlib/internal/jsonrt/indent.go +135 -0
  104. package/stdlib/internal/jsonrt/number.go +27 -0
  105. package/stdlib/internal/jsonrt/reader.go +73 -0
  106. package/stdlib/internal/jsonrt/scanner.go +649 -0
  107. package/stdlib/io/io.go +346 -0
  108. package/stdlib/iter/iter.go +18 -0
  109. package/stdlib/maps/iter.go +65 -0
  110. package/stdlib/math/extra.go +270 -0
  111. package/stdlib/slices/extra.go +73 -0
  112. package/stdlib/slices/iter.go +113 -0
  113. package/stdlib/sort/sort.go +561 -0
  114. package/stdlib/strconv/quote.go +341 -0
  115. package/stdlib/strings/extra.go +35 -0
  116. package/stdlib/strings/iter.go +122 -0
  117. package/stdlib/sync/extra.go +105 -0
  118. package/stdlib/unicode/unicode.go +112 -0
  119. package/stdlib/unicode/utf8/bytes.go +239 -0
  120. package/src/backend/wasm/const-fold.js +0 -205
  121. package/src/backend/wasm/emit-stdlib.js +0 -13
  122. /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
  123. /package/src/{colors.js → cli/colors.js} +0 -0
  124. /package/src/{dev-server.js → cli/dev-server.js} +0 -0
  125. /package/src/{minifier.js → cli/minifier.js} +0 -0
  126. /package/src/{project-config.js → cli/project-config.js} +0 -0
  127. /package/src/{pwa.js → cli/pwa.js} +0 -0
  128. /package/src/{templ-lexer.js → lexer/templ-lexer.js} +0 -0
@@ -79,6 +79,12 @@ export const statementCheckMethods = {
79
79
  const name = stmt.lhs[i].name ?? stmt.lhs[i];
80
80
  if (name === "_") continue;
81
81
  if (scope.symbols.has(name)) stmt.lhs[i]._redecl = true;
82
+ if (stmt.rhs.length === stmt.lhs.length)
83
+ this._checkConstDefault(
84
+ rhsFlat[i],
85
+ stmt.rhs[i],
86
+ "variable declaration",
87
+ );
82
88
  scope.defineLocal(name, defaultType(rhsFlat[i]) ?? ANY);
83
89
  }
84
90
  },
@@ -94,7 +100,8 @@ export const statementCheckMethods = {
94
100
  const resolvedBase =
95
101
  mapBaseType?.kind === "named" ? mapBaseType.underlying : mapBaseType;
96
102
  if (resolvedBase?.kind !== "map") return false;
97
- this.checkExpr(stmt.rhs[0].index, scope);
103
+ const keyType = this.checkExpr(stmt.rhs[0].index, scope);
104
+ this._markIfaceKey(resolvedBase, stmt.rhs[0].index, keyType);
98
105
  stmt._commaOkMap = true;
99
106
  stmt.rhs[0]._mapValueType = resolvedBase.value;
100
107
  this._declareDefineVars(stmt, [resolvedBase.value, BOOL], scope);
@@ -152,7 +159,8 @@ export const statementCheckMethods = {
152
159
  const resolvedBase =
153
160
  mapBaseType?.kind === "named" ? mapBaseType.underlying : mapBaseType;
154
161
  if (resolvedBase?.kind !== "map") return null;
155
- this.checkExpr(stmt.rhs[0].index, scope);
162
+ const keyType = this.checkExpr(stmt.rhs[0].index, scope);
163
+ this._markIfaceKey(resolvedBase, stmt.rhs[0].index, keyType);
156
164
  stmt._commaOkMap = true;
157
165
  stmt.rhs[0]._mapValueType = resolvedBase.value;
158
166
  return [resolvedBase.value, BOOL];
@@ -191,6 +199,16 @@ export const statementCheckMethods = {
191
199
  this.resolveType(r),
192
200
  stmt.rhs[i],
193
201
  );
202
+ // A shift count is not converted to the left operand's type.
203
+ if (stmt.op === "<<=" || stmt.op === ">>=") {
204
+ if (r && !isAny(r)) this.checkShiftCount(r, stmt.rhs[i]);
205
+ continue;
206
+ }
207
+ if (
208
+ stmt.rhs.length === lhsTypes.length &&
209
+ this._checkConstOverflow(lhsTypes[i], r, stmt.rhs[i], "assignment")
210
+ )
211
+ continue;
194
212
  if (!isAny(lhsTypes[i]) && !isAny(r)) {
195
213
  this._skipIfaceMark = true;
196
214
  this.assertAssignable(lhsTypes[i], r, stmt.lhs[i]);
@@ -246,9 +264,34 @@ export const statementCheckMethods = {
246
264
  if (!isVoid(returnType) && types.length > 0) {
247
265
  const expected =
248
266
  returnType.kind === "tuple" ? returnType.types : [returnType];
267
+ // `return f()` forwards every result of a multi-value call.
268
+ if (types.length === 1 && types[0]?.kind === "tuple") {
269
+ const forwarded = types[0].types;
270
+ if (forwarded.length !== expected.length) {
271
+ this.err(
272
+ `return count mismatch: have ${forwarded.length} values, want ${expected.length}`,
273
+ stmt,
274
+ );
275
+ return;
276
+ }
277
+ for (let i = 0; i < expected.length; i++) {
278
+ this.assertAssignable(
279
+ expected[i],
280
+ forwarded[i],
281
+ stmt.values[0],
282
+ "return statement",
283
+ );
284
+ }
285
+ return;
286
+ }
249
287
  for (let i = 0; i < expected.length; i++) {
250
288
  if (types[i])
251
- this.assertAssignable(expected[i], types[i], stmt.values[i] ?? stmt);
289
+ this.assertAssignable(
290
+ expected[i],
291
+ types[i],
292
+ stmt.values[i] ?? stmt,
293
+ "return statement",
294
+ );
252
295
  }
253
296
  }
254
297
  },
@@ -288,7 +331,14 @@ export const statementCheckMethods = {
288
331
  }
289
332
  },
290
333
 
291
- _checkForStmt(stmt, scope, returnType) {
334
+ // `checkBody(bodyScope)` checks the loop body; templ `for` loops pass one
335
+ // that checks their HTML nodes in place of the header's empty block.
336
+ _checkForStmt(
337
+ stmt,
338
+ scope,
339
+ returnType,
340
+ checkBody = (s) => this.checkBlock(stmt.body, s, returnType),
341
+ ) {
292
342
  const inner = new Scope(scope);
293
343
  let iterInfo = null;
294
344
  if (stmt.init?.rhs?.[0]?.kind === "RangeExpr") {
@@ -299,7 +349,7 @@ export const statementCheckMethods = {
299
349
  if (stmt.post) this.checkStmt(stmt.post, inner, returnType);
300
350
  this._loopDepth++;
301
351
  const bodyScope = new Scope(inner);
302
- this.checkBlock(stmt.body, bodyScope, returnType);
352
+ checkBody(bodyScope);
303
353
  this._reportUnused(bodyScope, stmt);
304
354
  this._loopDepth--;
305
355
  this._reportUnused(inner, stmt);
@@ -320,6 +370,19 @@ export const statementCheckMethods = {
320
370
  this._reportUnused(inner, stmt);
321
371
  },
322
372
 
373
+ // A case naming an interface (literal or declared) records the resolved
374
+ // type so backends test its method set.
375
+ _markInterfaceCaseType(t, scope) {
376
+ if (!t || (t.kind !== "InterfaceType" && t.kind !== "TypeName")) return;
377
+ if (t.kind === "TypeName" && (t.name === "nil" || t.name === "error"))
378
+ return;
379
+ const resolved = this.resolveTypeNode(t, scope);
380
+ const u = this.resolveType(
381
+ resolved?.kind === "named" ? resolved.underlying : resolved,
382
+ );
383
+ if (u?.kind === "interface") t._type = resolved;
384
+ },
385
+
323
386
  _checkTypeSwitchStmt(stmt, scope, returnType) {
324
387
  const inner = new Scope(scope);
325
388
  this.checkExpr(stmt.expr, inner);
@@ -327,10 +390,23 @@ export const statementCheckMethods = {
327
390
  this._typeSwitchDepth++;
328
391
  for (const c of stmt.cases) {
329
392
  const caseScope = new Scope(inner);
393
+ // Resolve instantiated generic case types so backends can tell
394
+ // `*Stack[int]` from `*Stack[string]`.
395
+ for (const t of c.types ?? []) {
396
+ const base = t?.kind === "PointerType" ? t.base : t;
397
+ if (base?.kind === "GenericTypeName") this.resolveTypeNode(t, inner);
398
+ this._markInterfaceCaseType(t, inner);
399
+ }
330
400
  if (stmt.assign) {
331
- // Bind the variable to the single case type, or any for multi/default
332
- const bindType =
333
- c.types?.length === 1 ? this.resolveTypeNode(c.types[0], inner) : ANY;
401
+ // Bind the variable to the single case type, or any for multi/default.
402
+ // `case nil` binds the switch expression's own type, as in Go.
403
+ const only = c.types?.length === 1 ? c.types[0] : null;
404
+ const isNilCase = only?.kind === "TypeName" && only.name === "nil";
405
+ const bindType = isNilCase
406
+ ? (stmt.expr._type ?? ANY)
407
+ : only
408
+ ? this.resolveTypeNode(only, inner)
409
+ : ANY;
334
410
  caseScope.defineLocal(stmt.assign, bindType);
335
411
  // The capture variable is always considered used — it's the whole
336
412
  // point of the switch-with-assign form. Each case body uses its own
@@ -346,7 +422,12 @@ export const statementCheckMethods = {
346
422
 
347
423
  _checkBranchStmt(stmt) {
348
424
  const kw = stmt.keyword;
349
- if (kw === "continue" && this._loopDepth === 0)
425
+ if (kw === "goto")
426
+ this.err(
427
+ "goto is not supported; restructure with labeled break/continue",
428
+ stmt,
429
+ );
430
+ else if (kw === "continue" && this._loopDepth === 0)
350
431
  this.err("continue statement outside for loop", stmt);
351
432
  else if (kw === "break" && this._loopDepth === 0 && this._switchDepth === 0)
352
433
  this.err("break statement outside for loop or switch", stmt);