gofront 1.4.0 → 1.5.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 (61) hide show
  1. package/README.md +72 -9
  2. package/package.json +2 -1
  3. package/src/{codegen → backend/js}/expressions.js +217 -60
  4. package/src/{codegen → backend/js}/index.js +21 -35
  5. package/src/{codegen → backend/js}/statements.js +43 -48
  6. package/src/backend/js/stdlib/bits.js +32 -0
  7. package/src/{codegen → backend/js}/stdlib/index.js +3 -0
  8. package/src/{codegen → backend/js}/templ.js +2 -2
  9. package/src/backend/wasm/boundary.js +1345 -0
  10. package/src/backend/wasm/emit.js +5779 -0
  11. package/src/backend/wasm/encode.js +789 -0
  12. package/src/backend/wasm/glue.js +130 -0
  13. package/src/backend/wasm/index.js +1413 -0
  14. package/src/backend/wasm/types.js +420 -0
  15. package/src/backend/wasm/wat.js +255 -0
  16. package/src/cli-core.js +52 -7
  17. package/src/compiler.js +322 -12
  18. package/src/dev-server.js +56 -15
  19. package/src/index.js +17 -9
  20. package/src/lexer.js +18 -0
  21. package/src/lower/boxing.js +36 -0
  22. package/src/lower/captures.js +179 -0
  23. package/src/lower/embedding.js +30 -0
  24. package/src/lower/escape.js +169 -0
  25. package/src/lower/functions.js +30 -0
  26. package/src/lower/globals.js +324 -0
  27. package/src/lower/index.js +115 -0
  28. package/src/lower/ownership.js +142 -0
  29. package/src/lower/range.js +70 -0
  30. package/src/minifier.js +2 -0
  31. package/src/parser/index.js +8 -3
  32. package/src/resolver.js +1 -0
  33. package/src/test-runner.js +74 -20
  34. package/src/typechecker/expressions.js +40 -1
  35. package/src/typechecker/index.js +234 -4
  36. package/src/typechecker/statements.js +7 -0
  37. package/src/typechecker/stdlib/core.js +17 -0
  38. package/src/typechecker/types.js +56 -2
  39. /package/src/{codegen → backend/js}/runtime.js +0 -0
  40. /package/src/{codegen → backend/js}/source-map.js +0 -0
  41. /package/src/{codegen → backend/js}/stdlib/builder.js +0 -0
  42. /package/src/{codegen → backend/js}/stdlib/bytes.js +0 -0
  43. /package/src/{codegen → backend/js}/stdlib/errors.js +0 -0
  44. /package/src/{codegen → backend/js}/stdlib/fmt.js +0 -0
  45. /package/src/{codegen → backend/js}/stdlib/gom.js +0 -0
  46. /package/src/{codegen → backend/js}/stdlib/html.js +0 -0
  47. /package/src/{codegen → backend/js}/stdlib/io.js +0 -0
  48. /package/src/{codegen → backend/js}/stdlib/maps.js +0 -0
  49. /package/src/{codegen → backend/js}/stdlib/math.js +0 -0
  50. /package/src/{codegen → backend/js}/stdlib/os.js +0 -0
  51. /package/src/{codegen → backend/js}/stdlib/path.js +0 -0
  52. /package/src/{codegen → backend/js}/stdlib/rand.js +0 -0
  53. /package/src/{codegen → backend/js}/stdlib/regexp.js +0 -0
  54. /package/src/{codegen → backend/js}/stdlib/slices.js +0 -0
  55. /package/src/{codegen → backend/js}/stdlib/sort.js +0 -0
  56. /package/src/{codegen → backend/js}/stdlib/strconv.js +0 -0
  57. /package/src/{codegen → backend/js}/stdlib/strings.js +0 -0
  58. /package/src/{codegen → backend/js}/stdlib/testing.js +0 -0
  59. /package/src/{codegen → backend/js}/stdlib/time.js +0 -0
  60. /package/src/{codegen → backend/js}/stdlib/unicode.js +0 -0
  61. /package/src/{codegen → backend/js}/stdlib/utf8.js +0 -0
@@ -1,6 +1,13 @@
1
- // CodeGen statement methods — installed as a mixin on CodeGen.prototype.
2
-
3
- import { isComplex, isNumeric } from "../typechecker/types.js";
1
+ import {
2
+ bodyRedeclares,
3
+ isIntRangeType,
4
+ isMapRangeType,
5
+ isRangeFor,
6
+ isSimpleIntRange,
7
+ isStringRangeType,
8
+ nodeAssigns,
9
+ } from "../../lower/index.js";
10
+ import { isComplex } from "../../typechecker/types.js";
4
11
 
5
12
  /** @typedef {import('./index.js').CodeGen} CodeGen */
6
13
 
@@ -55,9 +62,20 @@ export const statementGenMethods = {
55
62
  case "TypeDecl":
56
63
  this.genTypeDeclWithMethods(stmt, []);
57
64
  break;
58
- case "IncDecStmt":
59
- this.line(`${this.genExpr(stmt.expr)}${stmt.op};`);
65
+ case "IncDecStmt": {
66
+ if (
67
+ this.strict &&
68
+ this._genStrictCompound(
69
+ stmt.expr,
70
+ stmt.op === "++" ? "+" : "-",
71
+ "1",
72
+ srcLine,
73
+ )
74
+ )
75
+ break;
76
+ this.line(`${this.genExpr(stmt.expr)}${stmt.op};`, srcLine);
60
77
  break;
78
+ }
61
79
  case "ExprStmt":
62
80
  this.line(`${this.genExpr(stmt.expr)};`);
63
81
  break;
@@ -248,6 +266,19 @@ export const statementGenMethods = {
248
266
  if (active.length === 0) {
249
267
  if (rhs.length > 0) this.line(`${rhs[0]};`);
250
268
  } else if (lhs.length === 1) {
269
+ if (
270
+ this.strict &&
271
+ stmt.op !== "=" &&
272
+ this._genStrictCompound(
273
+ stmt.lhs[0],
274
+ stmt.op.slice(0, -1),
275
+ active[0].r,
276
+ null,
277
+ active[0].l,
278
+ )
279
+ ) {
280
+ return;
281
+ }
251
282
  this.line(`${active[0].l} ${stmt.op} ${active[0].r};`);
252
283
  } else {
253
284
  this._genAssignMulti(stmt, lhs, rhs, active, pairs);
@@ -449,28 +480,19 @@ export const statementGenMethods = {
449
480
  },
450
481
 
451
482
  isRangeFor(stmt) {
452
- if (!stmt.init) return false;
453
- const init = stmt.init;
454
- if (init.kind !== "DefineStmt" && init.kind !== "AssignStmt") return false;
455
- return init.rhs?.[0]?.kind === "RangeExpr";
483
+ return isRangeFor(stmt);
456
484
  },
457
485
 
458
486
  _isIntRangeType(iterType) {
459
- return isNumeric(iterType);
487
+ return isIntRangeType(iterType);
460
488
  },
461
489
 
462
490
  _isMapRangeType(iterType) {
463
- return (
464
- iterType?.kind === "map" ||
465
- (iterType?.kind === "named" && iterType.underlying?.kind === "map")
466
- );
491
+ return isMapRangeType(iterType);
467
492
  },
468
493
 
469
494
  _isStringRangeType(iterType) {
470
- return (
471
- (iterType?.kind === "basic" && iterType.name === "string") ||
472
- (iterType?.kind === "untyped" && iterType.base === "string")
473
- );
495
+ return isStringRangeType(iterType);
474
496
  },
475
497
 
476
498
  _rangeVarTarget(e, isAssign) {
@@ -498,17 +520,7 @@ export const statementGenMethods = {
498
520
 
499
521
  // True when the body re-declares one of `names` at its top level (legal Go shadowing).
500
522
  _bodyRedeclares(body, names) {
501
- if (names.length === 0) return false;
502
- for (const s of body.stmts ?? []) {
503
- if (s.kind === "DefineStmt" && s.lhs.some((e) => names.includes(e.name)))
504
- return true;
505
- if (
506
- (s.kind === "VarDecl" || s.kind === "ConstDecl") &&
507
- s.decls?.some((d) => d.names?.some((n) => names.includes(n)))
508
- )
509
- return true;
510
- }
511
- return false;
523
+ return bodyRedeclares(body, names);
512
524
  },
513
525
 
514
526
  // Range value variable: aliases the element unless the body writes the variable or the collection.
@@ -565,9 +577,7 @@ export const statementGenMethods = {
565
577
 
566
578
  // Whether `for i := range n` can be emitted as a plain `for (let i = 0; …)` without hidden registers.
567
579
  _isSimpleIntRange(stmt, name, isAssign) {
568
- if (isAssign) return false;
569
- if (!name || name === "_") return true;
570
- return !this._boxedVars.has(name) && !this._nodeAssigns(stmt.body, name);
580
+ return isSimpleIntRange(stmt, name, isAssign, this._boxedVars);
571
581
  },
572
582
 
573
583
  _genIntRangeBody(stmt, name, isAssign) {
@@ -603,22 +613,7 @@ export const statementGenMethods = {
603
613
 
604
614
  // True when `node` contains an assignment or ++/-- targeting identifier `name`.
605
615
  _nodeAssigns(node, name) {
606
- if (!node || typeof node !== "object") return false;
607
- if (Array.isArray(node))
608
- return node.some((n) => this._nodeAssigns(n, name));
609
- if (
610
- (node.kind === "AssignStmt" &&
611
- node.lhs.some((e) => e.kind === "Ident" && e.name === name)) ||
612
- (node.kind === "IncDecStmt" &&
613
- node.expr.kind === "Ident" &&
614
- node.expr.name === name)
615
- )
616
- return true;
617
- for (const key of Object.keys(node)) {
618
- if (key.startsWith("_")) continue;
619
- if (this._nodeAssigns(node[key], name)) return true;
620
- }
621
- return false;
616
+ return nodeAssigns(node, name);
622
617
  },
623
618
 
624
619
  _genIterFor(init, iterType, iteree, lhs, body) {
@@ -0,0 +1,32 @@
1
+ // src/backend/js/stdlib/bits.js
2
+ // CodeGen for Go `math/bits` package.
3
+
4
+ /** @typedef {import('../index.js').CodeGen} CodeGen */
5
+
6
+ const BITS_MAP = {
7
+ LeadingZeros32: ([x]) => `Math.clz32((${x}) >>> 0)`,
8
+ TrailingZeros32: ([x]) =>
9
+ `((() => { const v = (${x}) >>> 0; return v === 0 ? 32 : 31 - Math.clz32(v & -v); })())`,
10
+ OnesCount32: ([x]) =>
11
+ `((() => { let v = (${x}) >>> 0; v = v - ((v >>> 1) & 0x55555555); v = (v & 0x33333333) + ((v >>> 2) & 0x33333333); return (Math.imul((v + (v >>> 4)) & 0x0f0f0f0f, 0x01010101)) >>> 24; })())`,
12
+ RotateLeft32: ([x, k]) =>
13
+ `((() => { const s = (${k}) & 31; const v = (${x}) >>> 0; return ((v << s) | (v >>> ((32 - s) & 31))) >>> 0; })())`,
14
+
15
+ LeadingZeros64: ([x]) =>
16
+ `((() => { const v = BigInt.asUintN(64, BigInt(${x})); if (v === 0n) return 64; const hi = Number(v >> 32n); return hi !== 0 ? Math.clz32(hi) : 32 + Math.clz32(Number(v & 0xffffffffn)); })())`,
17
+ TrailingZeros64: ([x]) =>
18
+ `((() => { const v = BigInt.asUintN(64, BigInt(${x})); if (v === 0n) return 64; const lo = Number(v & 0xffffffffn); if (lo !== 0) return 31 - Math.clz32(lo & -lo); const hi = Number((v >> 32n) & 0xffffffffn); return 32 + (31 - Math.clz32(hi & -hi)); })())`,
19
+ OnesCount64: ([x]) =>
20
+ `((() => { let v = BigInt.asUintN(64, BigInt(${x})); let c = 0; while (v > 0n) { if (v & 1n) c++; v >>= 1n; } return c; })())`,
21
+ RotateLeft64: ([x, k]) =>
22
+ `((() => { const s = BigInt(${k}) & 63n; const v = BigInt.asUintN(64, BigInt(${x})); return BigInt.asUintN(64, (v << s) | (v >> ((64n - s) & 63n))); })())`,
23
+ };
24
+
25
+ /** @type {ThisType<CodeGen>} */
26
+ export const bitsMethods = {
27
+ _genBits(fn, a) {
28
+ const args = a();
29
+ const gen = BITS_MAP[fn];
30
+ return gen ? gen(args) : undefined;
31
+ },
32
+ };
@@ -1,6 +1,7 @@
1
1
  // CodeGen stdlib call generation — installed as a mixin on CodeGen.prototype.
2
2
  // One file per Go package under ./stdlib/. This index merges them.
3
3
 
4
+ import { bitsMethods } from "./bits.js";
4
5
  import { builderMethods } from "./builder.js";
5
6
  import { bytesMethods } from "./bytes.js";
6
7
  import { errorsMethods } from "./errors.js";
@@ -34,6 +35,7 @@ const STDLIB_METHOD_MAP = {
34
35
  strconv: "_genStrconv",
35
36
  sort: "_genSort",
36
37
  math: "_genMath",
38
+ bits: "_genBits",
37
39
  unicode: "_genUnicode",
38
40
  os: "_genOs",
39
41
  errors: "_genErrors",
@@ -76,6 +78,7 @@ const dispatchMethods = {
76
78
 
77
79
  /** @type {ThisType<CodeGen>} */
78
80
  export const stdlibGenMethods = {
81
+ ...bitsMethods,
79
82
  ...builderMethods,
80
83
  ...bytesMethods,
81
84
  ...errorsMethods,
@@ -2,8 +2,8 @@
2
2
  // Mounts an HTML/expression tree onto a parent DOM node by emitting plain
3
3
  // document.createElement / appendChild / setAttribute calls.
4
4
 
5
- import { Parser } from "../parser/index.js";
6
- import { T, Token } from "../tokens.js";
5
+ import { Parser } from "../../parser/index.js";
6
+ import { T, Token } from "../../tokens.js";
7
7
 
8
8
  /** @typedef {import('./index.js').CodeGen} CodeGen */
9
9