gofront 1.7.0 → 1.9.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 (194) hide show
  1. package/README.md +14 -14
  2. package/package.json +10 -38
  3. package/src/backend/js/expressions.js +2060 -389
  4. package/src/backend/js/index.js +586 -174
  5. package/src/backend/js/natives.js +383 -0
  6. package/src/backend/js/runtime.js +936 -1644
  7. package/src/backend/js/statements.js +1349 -132
  8. package/src/backend/js/stdlib/index.js +51 -94
  9. package/src/backend/js/templ.js +67 -118
  10. package/src/backend/js/type-info.js +436 -0
  11. package/src/backend/shared/fixed-float.js +20 -0
  12. package/src/backend/shared/fmt-types.js +80 -0
  13. package/src/backend/shared/host-unicode.js +36 -0
  14. package/src/backend/wasm/boundary.js +753 -872
  15. package/src/backend/wasm/emit-builtins.js +914 -237
  16. package/src/backend/wasm/emit-exprs.js +1456 -195
  17. package/src/backend/wasm/emit-maps.js +78 -380
  18. package/src/backend/wasm/emit-stmts.js +1659 -214
  19. package/src/backend/wasm/emit.js +614 -88
  20. package/src/backend/wasm/encode.js +43 -13
  21. package/src/backend/wasm/globals.js +491 -0
  22. package/src/backend/wasm/glue.js +2 -4
  23. package/src/backend/wasm/index.js +406 -3195
  24. package/src/backend/wasm/method-expr.js +392 -0
  25. package/src/backend/wasm/module-emitter.js +1615 -0
  26. package/src/backend/wasm/monomorph.js +164 -9
  27. package/src/backend/wasm/natives.js +596 -0
  28. package/src/backend/wasm/prescan.js +249 -0
  29. package/src/backend/wasm/prune-funcs.js +89 -0
  30. package/src/backend/wasm/stdlib/index.js +2 -37
  31. package/src/backend/wasm/stdlib/simd.js +293 -28
  32. package/src/backend/wasm/types.js +260 -27
  33. package/src/backend/wasm/variadic.js +93 -0
  34. package/src/backend/wasm/wat.js +47 -20
  35. package/src/{cli-core.js → cli/cli-core.js} +241 -11
  36. package/src/{test-runner.js → cli/test-runner.js} +188 -122
  37. package/src/{vendor.js → cli/vendor.js} +3 -4
  38. package/src/compiler.js +202 -386
  39. package/src/index.js +15 -169
  40. package/src/{lexer.js → lexer/lexer.js} +203 -62
  41. package/src/{templ-lexer.js → lexer/templ-lexer.js} +61 -18
  42. package/src/{tokens.js → lexer/tokens.js} +2 -0
  43. package/src/link/sourcemap.js +97 -0
  44. package/src/link/stdlib.js +737 -0
  45. package/src/link/type-names.js +148 -0
  46. package/src/link/wasm.js +318 -0
  47. package/src/lower/bounds.js +547 -0
  48. package/src/lower/boxing.js +1 -1
  49. package/src/lower/captures.js +267 -64
  50. package/src/lower/embedding.js +32 -3
  51. package/src/lower/errors-as.js +196 -0
  52. package/src/lower/fmt-formatters.js +905 -0
  53. package/src/lower/functions.js +2 -0
  54. package/src/lower/gen-types.js +274 -0
  55. package/src/lower/index.js +33 -19
  56. package/src/lower/json-codecs.js +1379 -0
  57. package/src/lower/ownership.js +47 -8
  58. package/src/lower/range.js +86 -1
  59. package/src/lower/reachability.js +150 -0
  60. package/src/lower/walk.js +12 -0
  61. package/src/parser/declarations.js +83 -15
  62. package/src/parser/expressions.js +110 -18
  63. package/src/parser/index.js +2 -1
  64. package/src/parser/statements.js +38 -22
  65. package/src/{templ-parser.js → parser/templ.js} +179 -17
  66. package/src/parser/types.js +70 -9
  67. package/src/resolver.js +21 -1
  68. package/src/typechecker/assignability.js +291 -19
  69. package/src/typechecker/const-fold.js +399 -0
  70. package/src/typechecker/constants.js +282 -0
  71. package/src/typechecker/expressions.js +1220 -183
  72. package/src/typechecker/index.js +659 -92
  73. package/src/typechecker/init-order.js +426 -0
  74. package/src/typechecker/operand-text.js +40 -0
  75. package/src/typechecker/resolve.js +613 -62
  76. package/src/typechecker/statements.js +212 -20
  77. package/src/typechecker/stdlib/excluded.js +902 -0
  78. package/src/typechecker/stdlib/index.js +38 -0
  79. package/src/typechecker/stdlib/simd.js +65 -15
  80. package/src/typechecker/termination.js +11 -2
  81. package/src/typechecker/types.js +268 -514
  82. package/stdlib/bytes/buffer.go +479 -0
  83. package/stdlib/bytes/bytes.go +1010 -0
  84. package/stdlib/bytes/reader.go +161 -0
  85. package/stdlib/cmp/cmp.go +65 -0
  86. package/stdlib/context/context.go +115 -0
  87. package/stdlib/crypto/rand/rand.go +34 -0
  88. package/stdlib/crypto/sha256/sha256.go +249 -0
  89. package/stdlib/encoding/base64/base64.go +331 -0
  90. package/stdlib/encoding/binary/binary.go +332 -0
  91. package/stdlib/encoding/hex/hex.go +140 -0
  92. package/stdlib/encoding/json/errors.go +31 -0
  93. package/stdlib/encoding/json/indent.go +71 -0
  94. package/stdlib/encoding/json/json.go +62 -0
  95. package/stdlib/encoding/json/number.go +12 -0
  96. package/stdlib/encoding/json/stream.go +173 -0
  97. package/stdlib/errors/errors.go +174 -0
  98. package/stdlib/fmt/errors.go +110 -0
  99. package/stdlib/fmt/format.go +732 -0
  100. package/stdlib/fmt/print.go +1232 -0
  101. package/stdlib/gom/gom.go +293 -0
  102. package/stdlib/hash/hash.go +53 -0
  103. package/stdlib/html/html.go +251 -0
  104. package/stdlib/internal/fmtrt/fmtrt.go +163 -0
  105. package/stdlib/internal/jsonrt/dec.go +871 -0
  106. package/stdlib/internal/jsonrt/enc.go +516 -0
  107. package/stdlib/internal/jsonrt/indent.go +135 -0
  108. package/stdlib/internal/jsonrt/number.go +27 -0
  109. package/stdlib/internal/jsonrt/reader.go +73 -0
  110. package/stdlib/internal/jsonrt/scanner.go +658 -0
  111. package/stdlib/io/io.go +502 -0
  112. package/stdlib/iter/iter.go +18 -0
  113. package/stdlib/maps/maps.go +131 -0
  114. package/stdlib/math/bits/bits.go +507 -0
  115. package/stdlib/math/extra.go +272 -0
  116. package/stdlib/math/math.go +439 -0
  117. package/stdlib/math/rand/rand.go +297 -0
  118. package/stdlib/os/os.go +93 -0
  119. package/stdlib/path/filepath/filepath.go +47 -0
  120. package/stdlib/path/path.go +394 -0
  121. package/stdlib/regexp/regexp.go +231 -0
  122. package/stdlib/slices/slices.go +526 -0
  123. package/stdlib/slices/sort.go +209 -0
  124. package/stdlib/slices/zsort_cmp.go +480 -0
  125. package/stdlib/slices/zsort_ordered.go +482 -0
  126. package/stdlib/sort/sort.go +500 -0
  127. package/stdlib/sort/zsort_func.go +480 -0
  128. package/stdlib/sort/zsort_iface.go +480 -0
  129. package/stdlib/strconv/float.go +1699 -0
  130. package/stdlib/strconv/isprint.go +752 -0
  131. package/stdlib/strconv/quote.go +526 -0
  132. package/stdlib/strconv/strconv.go +616 -0
  133. package/stdlib/strings/builder.go +95 -0
  134. package/stdlib/strings/reader.go +163 -0
  135. package/stdlib/strings/replacer.go +102 -0
  136. package/stdlib/strings/strings.go +807 -0
  137. package/stdlib/sync/sync.go +268 -0
  138. package/stdlib/testing/async_js.go +61 -0
  139. package/stdlib/testing/benchmark.go +297 -0
  140. package/stdlib/testing/testing.go +523 -0
  141. package/stdlib/time/duration.go +233 -0
  142. package/stdlib/time/format.go +745 -0
  143. package/stdlib/time/parse.go +790 -0
  144. package/stdlib/time/sleep_js.go +63 -0
  145. package/stdlib/time/time.go +834 -0
  146. package/stdlib/unicode/unicode.go +250 -0
  147. package/stdlib/unicode/utf8/utf8.go +464 -0
  148. package/src/backend/js/stdlib/base64.js +0 -12
  149. package/src/backend/js/stdlib/binary.js +0 -102
  150. package/src/backend/js/stdlib/bits.js +0 -46
  151. package/src/backend/js/stdlib/builder.js +0 -63
  152. package/src/backend/js/stdlib/bytes.js +0 -122
  153. package/src/backend/js/stdlib/errors.js +0 -44
  154. package/src/backend/js/stdlib/fmt.js +0 -178
  155. package/src/backend/js/stdlib/gom.js +0 -155
  156. package/src/backend/js/stdlib/hex.js +0 -17
  157. package/src/backend/js/stdlib/html.js +0 -20
  158. package/src/backend/js/stdlib/io.js +0 -137
  159. package/src/backend/js/stdlib/json.js +0 -972
  160. package/src/backend/js/stdlib/maps.js +0 -45
  161. package/src/backend/js/stdlib/math.js +0 -69
  162. package/src/backend/js/stdlib/os.js +0 -13
  163. package/src/backend/js/stdlib/path.js +0 -48
  164. package/src/backend/js/stdlib/rand.js +0 -32
  165. package/src/backend/js/stdlib/regexp.js +0 -54
  166. package/src/backend/js/stdlib/sha256.js +0 -12
  167. package/src/backend/js/stdlib/shared.js +0 -17
  168. package/src/backend/js/stdlib/simd.js +0 -24
  169. package/src/backend/js/stdlib/slices.js +0 -77
  170. package/src/backend/js/stdlib/sort.js +0 -30
  171. package/src/backend/js/stdlib/strconv.js +0 -74
  172. package/src/backend/js/stdlib/strings.js +0 -222
  173. package/src/backend/js/stdlib/sync.js +0 -13
  174. package/src/backend/js/stdlib/testing.js +0 -34
  175. package/src/backend/js/stdlib/time.js +0 -128
  176. package/src/backend/js/stdlib/unicode.js +0 -25
  177. package/src/backend/js/stdlib/utf8.js +0 -26
  178. package/src/backend/wasm/const-fold.js +0 -205
  179. package/src/backend/wasm/emit-stdlib.js +0 -13
  180. package/src/backend/wasm/stdlib/bytes.js +0 -5039
  181. package/src/backend/wasm/stdlib/core.js +0 -8903
  182. package/src/backend/wasm/stdlib/io.js +0 -2161
  183. package/src/backend/wasm/stdlib/packages.js +0 -2400
  184. package/src/backend/wasm/stdlib/pure.js +0 -720
  185. package/src/backend/wasm/stdlib/time.js +0 -1200
  186. package/src/typechecker/stdlib/core.js +0 -801
  187. package/src/typechecker/stdlib/extended.js +0 -914
  188. package/src/typechecker/stdlib.js +0 -22
  189. /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
  190. /package/src/{colors.js → cli/colors.js} +0 -0
  191. /package/src/{dev-server.js → cli/dev-server.js} +0 -0
  192. /package/src/{minifier.js → cli/minifier.js} +0 -0
  193. /package/src/{project-config.js → cli/project-config.js} +0 -0
  194. /package/src/{pwa.js → cli/pwa.js} +0 -0
@@ -0,0 +1,148 @@
1
+ // Same-named types in different local packages.
2
+ //
3
+ // Local packages are inlined into one flat JS module, so `a.Pt` and `b.Pt`
4
+ // would both become `class Pt`. A package that declares a type another
5
+ // package already owns gets that type renamed to `Pt$$b` before it is
6
+ // type-checked, the convention Go-source stdlib packages use: diagnostics and
7
+ // `%T` show it as `b.Pt`, and importers reach it through `b.Pt` as usual.
8
+
9
+ import { forEachChild } from "../lower/walk.js";
10
+
11
+ function topLevelTypeNames(programs) {
12
+ const names = [];
13
+ for (const p of programs)
14
+ for (const d of p.decls ?? [])
15
+ if (d.kind === "TypeDecl") names.push(d.name);
16
+ return names;
17
+ }
18
+
19
+ // Registers the package's type names in `owners` (name -> package key) and
20
+ // renames those another package registered first. Returns Map<name, mangled>
21
+ // for the renamed types, empty when nothing collides.
22
+ export function mangleCollidingTypes(programs, pkgKey, pkgName, owners) {
23
+ const renamed = new Map();
24
+ for (const name of topLevelTypeNames(programs)) {
25
+ const owner = owners.get(name);
26
+ if (owner === undefined) owners.set(name, pkgKey);
27
+ else if (owner !== pkgKey) renamed.set(name, `${name}$$${pkgName}`);
28
+ }
29
+ if (renamed.size > 0)
30
+ for (const p of programs)
31
+ for (const d of p.decls ?? [])
32
+ renameTypeRefs(d, renamed, new Set(), new Set());
33
+ return renamed;
34
+ }
35
+
36
+ // Function-local types are scoped to their block, but the checker and both
37
+ // backends key types by bare name. A local type whose name another type of the
38
+ // package also uses (a package-level type or a local of another function)
39
+ // is renamed to `Name__L<n>` for its scope; `%T` and diagnostics drop the
40
+ // suffix (see `displayTypeName`). Returns whether anything was renamed.
41
+ let localTypeCounter = 0;
42
+
43
+ export function renameLocalTypes(programs) {
44
+ const counts = new Map();
45
+ const count = (node) => {
46
+ if (!node || typeof node !== "object") return;
47
+ if (Array.isArray(node)) return node.forEach(count);
48
+ if (node.kind === "TypeDecl")
49
+ counts.set(node.name, (counts.get(node.name) ?? 0) + 1);
50
+ forEachChild(node, count);
51
+ };
52
+ for (const p of programs) count(p.decls);
53
+ const dup = new Set([...counts].filter(([, n]) => n > 1).map(([k]) => k));
54
+ if (dup.size === 0) return false;
55
+ let changed = false;
56
+ // Inner scopes first, so an outer rename never touches a nested
57
+ // declaration that already has its own name.
58
+ const scan = (node) => {
59
+ if (!node || typeof node !== "object") return;
60
+ if (Array.isArray(node)) {
61
+ node.forEach(scan);
62
+ for (let i = 0; i < node.length; i++) {
63
+ const d = node[i];
64
+ if (d?.kind !== "TypeDecl" || !dup.has(d.name)) continue;
65
+ const renamed = new Map([
66
+ [d.name, `${d.name}__L${++localTypeCounter}`],
67
+ ]);
68
+ for (let j = i; j < node.length; j++)
69
+ renameTypeRefs(node[j], renamed, new Set(), new Set());
70
+ changed = true;
71
+ }
72
+ return;
73
+ }
74
+ forEachChild(node, scan);
75
+ };
76
+ for (const p of programs)
77
+ for (const d of p.decls ?? []) if (d.kind !== "TypeDecl") scan(d);
78
+ return changed;
79
+ }
80
+
81
+ // `tparams` are type parameters in scope; `values` are names a function
82
+ // declares as parameters or locals, which shadow a same-spelled bare `Ident`.
83
+ function renameTypeRefs(node, renamed, tparams, values) {
84
+ if (!node || typeof node !== "object") return;
85
+ if (Array.isArray(node)) {
86
+ for (const n of node) renameTypeRefs(n, renamed, tparams, values);
87
+ return;
88
+ }
89
+ const tp = withTypeParams(node, tparams);
90
+ const vals = FUNC_KINDS.has(node.kind) ? withLocals(node, values) : values;
91
+ if (isTypeRef(node, vals) && renamed.has(node.name) && !tp.has(node.name))
92
+ node.name = renamed.get(node.name);
93
+ forEachChild(node, (child) => {
94
+ if (node.kind === "KeyValueExpr" && child === node.key) return;
95
+ renameTypeRefs(child, renamed, tp, vals);
96
+ });
97
+ }
98
+
99
+ const FUNC_KINDS = new Set(["FuncDecl", "MethodDecl", "FuncLit"]);
100
+
101
+ // Adds every parameter and local name declared anywhere inside a function.
102
+ function withLocals(fn, values) {
103
+ const out = new Set(values);
104
+ const visit = (node) => {
105
+ if (!node || typeof node !== "object") return;
106
+ if (Array.isArray(node)) return node.forEach(visit);
107
+ for (const n of declaredNames(node)) out.add(n);
108
+ forEachChild(node, visit);
109
+ };
110
+ visit(fn);
111
+ return out;
112
+ }
113
+
114
+ function declaredNames(node) {
115
+ const names = [];
116
+ if (node.kind === "DefineStmt")
117
+ for (const l of node.lhs) if (l.kind === "Ident") names.push(l.name);
118
+ if (node.kind === "VarDecl" || node.kind === "ConstDecl")
119
+ for (const d of node.decls ?? []) names.push(...(d.names ?? []));
120
+ if (node.kind === "TypeSwitchStmt" && node.assign) names.push(node.assign);
121
+ for (const p of node.params ?? []) if (p.name) names.push(p.name);
122
+ if (node.recvName) names.push(node.recvName);
123
+ return names;
124
+ }
125
+
126
+ function withTypeParams(node, tparams) {
127
+ if (!(node.typeParams?.length > 0)) return tparams;
128
+ return new Set([...tparams, ...node.typeParams.map((t) => t.name)]);
129
+ }
130
+
131
+ const TYPE_REF_KINDS = new Set([
132
+ "TypeDecl",
133
+ "TypeName",
134
+ "GenericTypeName",
135
+ "Ident",
136
+ ]);
137
+
138
+ function isTypeRef(node, values) {
139
+ if (node.kind === "Ident") return !values.has(node.name);
140
+ return TYPE_REF_KINDS.has(node.kind);
141
+ }
142
+
143
+ // Importers name a renamed type by its declared name (`b.Pt`).
144
+ export function withOriginalTypeNames(types, renamed) {
145
+ for (const [name, mangled] of renamed)
146
+ if (types.has(mangled)) types.set(name, types.get(mangled));
147
+ return types;
148
+ }
@@ -0,0 +1,318 @@
1
+ // Linking of `wasm`/`both` package units into one `app.wasm`: unit
2
+ // registration, collision checks, link-copy AST rewrites and the facade splice.
3
+
4
+ import { compileWasmModule } from "../backend/wasm/index.js";
5
+ import { lower } from "../lower/index.js";
6
+ import { reachableStdlibDecls } from "../lower/reachability.js";
7
+ import { forEachChild } from "../lower/walk.js";
8
+ import { TypeCheckError, TypeChecker } from "../typechecker/index.js";
9
+
10
+ // ── WASM linking ──────────────────────────────────────────────
11
+ //
12
+ // Every `wasm`/`both` package reached during a build registers a unit in the
13
+ // shared `options.wasmUnits` array. The root compile links all units into a
14
+ // single `app.wasm` and splices the generated JS facade into the bundle where
15
+ // the first wasm package's JS would have been.
16
+
17
+ const WASM_MARKER_RE = /^\/\*__GOFRONT_WASM_UNIT:[^*]*\*\/$/m;
18
+
19
+ export function wasmMarker(pkgName) {
20
+ return `/*__GOFRONT_WASM_UNIT:${pkgName}*/`;
21
+ }
22
+
23
+ export function registerWasmUnit(options, unit) {
24
+ const units = options.wasmUnits;
25
+ if (!units) return;
26
+ if (units.some((u) => u.key === unit.key)) return;
27
+ units.push(unit);
28
+ }
29
+
30
+ // Registers a `wasm`/`both` package as a link unit and returns the target the
31
+ // package's own code is emitted for. `options.wasmTests` runs a `both`
32
+ // package's tests through the wasm backend (the package is then treated as
33
+ // `wasm` for linking so its test functions are exposed by the facade).
34
+ export function registerPackageUnit(options, unit) {
35
+ const { pkgTarget, programs } = unit;
36
+ if (pkgTarget !== "wasm" && pkgTarget !== "both") return pkgTarget;
37
+ const emitTarget =
38
+ options.wasmTests && options.isTest && pkgTarget === "both"
39
+ ? "wasm"
40
+ : pkgTarget;
41
+ registerWasmUnit(options, {
42
+ ...unit,
43
+ target: emitTarget,
44
+ programs:
45
+ emitTarget === pkgTarget
46
+ ? programs
47
+ : programs.map((p) => ({ ...p, target: emitTarget })),
48
+ });
49
+ return emitTarget;
50
+ }
51
+
52
+ function linkWasmUnits(
53
+ units,
54
+ {
55
+ emitWat = false,
56
+ rootTarget = "js",
57
+ sourceMappingURL = null,
58
+ natives = true,
59
+ } = {},
60
+ ) {
61
+ if (!units.some((u) => u.target === "wasm")) return null;
62
+ checkLinkCollisions(units);
63
+
64
+ const types = new Map();
65
+ const bundledPackages = new Set();
66
+ const programs = [];
67
+ const stdlibPrograms = [];
68
+ // Check the stdlib bodies the linked code reaches before the ASTs are
69
+ // copied; lazily checked bodies are annotated and mangled in place.
70
+ reachableStdlibDecls(
71
+ units
72
+ .filter((u) => !u.key.startsWith("stdlib:"))
73
+ .flatMap((u) => u.programs),
74
+ units.filter((u) => u.key.startsWith("stdlib:")).flatMap((u) => u.programs),
75
+ );
76
+ for (const u of units) {
77
+ for (const b of u.bundledPackages) bundledPackages.add(b);
78
+ const copies = u.programs.map((p) => cloneAstForWasm(p));
79
+ programs.push(...copies);
80
+ if (u.key.startsWith("stdlib:")) stdlibPrograms.push(...copies);
81
+ }
82
+ lowerStdlibRefs(programs);
83
+ dequalifyBundledRefs(programs, bundledPackages);
84
+ const keepType = pruneStdlibPrograms(programs, stdlibPrograms);
85
+ for (const u of units)
86
+ for (const [k, v] of u.types) if (keepType(v)) types.set(k, v);
87
+ const checker = Object.assign(new TypeChecker(), {
88
+ types,
89
+ errors: [],
90
+ err(msg, node) {
91
+ const e = new TypeCheckError(
92
+ msg,
93
+ node,
94
+ this._currentFile,
95
+ this._currentSource,
96
+ );
97
+ this.errors.push(e);
98
+ return e;
99
+ },
100
+ });
101
+ const lowerRes = lower(programs, checker);
102
+ return compileWasmModule(programs, checker, lowerRes, {
103
+ boundary: true,
104
+ bundledPackages,
105
+ natives,
106
+ emitWat,
107
+ callMain: rootTarget === "wasm",
108
+ sourceMappingURL,
109
+ });
110
+ }
111
+
112
+ // The WASM pipeline rewrites ASTs in place (package dequalification,
113
+ // monomorphisation, variadic desugaring). Parsed ASTs are cached across
114
+ // builds and shared with JS codegen, so the link works on a structural copy;
115
+ // side tables (`_type`, …) are shared by reference.
116
+ function cloneAstForWasm(node, seen = new Map()) {
117
+ if (!node || typeof node !== "object") return node;
118
+ const prev = seen.get(node);
119
+ if (prev) return prev;
120
+ const copy = Array.isArray(node) ? [] : {};
121
+ seen.set(node, copy);
122
+ if (Array.isArray(node)) {
123
+ for (const n of node) copy.push(cloneAstForWasm(n, seen));
124
+ return copy;
125
+ }
126
+ for (const [k, v] of Object.entries(node)) {
127
+ copy[k] = k.charCodeAt(0) === 95 ? v : cloneAstForWasm(v, seen);
128
+ }
129
+ return copy;
130
+ }
131
+
132
+ // Drops unreachable Go-source stdlib declarations from the link copy and
133
+ // returns a filter that drops their (mangled) named types.
134
+ function pruneStdlibPrograms(programs, stdlibPrograms) {
135
+ if (stdlibPrograms.length === 0) return () => true;
136
+ const std = new Set(stdlibPrograms);
137
+ const reached = reachableStdlibDecls(
138
+ programs.filter((p) => !std.has(p)),
139
+ stdlibPrograms,
140
+ );
141
+ const types = new Set();
142
+ for (const p of stdlibPrograms) {
143
+ p.decls = p.decls.filter((d) => reached.has(d));
144
+ for (const d of p.decls) if (d.kind === "TypeDecl") types.add(d.name);
145
+ }
146
+ return (t) => {
147
+ const name = typeof t?.name === "string" ? t.name : "";
148
+ return !name.includes("$$") || types.has(name.replace(/\[.*$/, ""));
149
+ };
150
+ }
151
+
152
+ // The linked module is flat, so `util.Two` names the top-level `Two`. Done on
153
+ // the link copy before monomorphisation, whose re-check of all programs has no
154
+ // package namespaces. A local variable that shadows the package is typed and
155
+ // is left alone.
156
+ function isBundledSelector(node, bundled) {
157
+ const base = node.expr;
158
+ return (
159
+ base?.kind === "Ident" &&
160
+ bundled.has(base.name) &&
161
+ (base._type == null || base._type.kind === "namespace")
162
+ );
163
+ }
164
+
165
+ function dequalifyBundledRefs(node, bundled) {
166
+ if (!node || typeof node !== "object") return;
167
+ if (Array.isArray(node)) {
168
+ for (const n of node) dequalifyBundledRefs(n, bundled);
169
+ return;
170
+ }
171
+ if (node.kind === "SelectorExpr" && isBundledSelector(node, bundled)) {
172
+ node.kind = "Ident";
173
+ node.name = node.field;
174
+ delete node.expr;
175
+ delete node.field;
176
+ } else if (node.kind === "TypeName" || node.kind === "GenericTypeName") {
177
+ const dot = node.name?.indexOf(".") ?? -1;
178
+ if (dot > 0 && bundled.has(node.name.slice(0, dot)))
179
+ node.name = node.name.slice(dot + 1);
180
+ }
181
+ forEachChild(node, (child) => dequalifyBundledRefs(child, bundled));
182
+ }
183
+
184
+ // The linked module is one flat namespace (like the JS bundle), so a top-level
185
+ // name declared by two different packages would silently resolve to whichever
186
+ // was emitted last. Reject it up front.
187
+ function topLevelDeclNames(decl) {
188
+ switch (decl.kind) {
189
+ case "FuncDecl":
190
+ return [decl.name];
191
+ case "MethodDecl":
192
+ return [`${decl.recvType?.name ?? "?"}.${decl.name}`];
193
+ case "TypeDecl":
194
+ return [decl.name];
195
+ case "VarDecl":
196
+ case "ConstDecl":
197
+ return (decl.decls ?? []).flatMap((spec) => spec.names ?? []);
198
+ default:
199
+ return [];
200
+ }
201
+ }
202
+
203
+ export function checkLinkCollisions(units) {
204
+ const owner = new Map(); // name -> pkgName
205
+ const errors = [];
206
+ for (const u of units) {
207
+ for (const p of u.programs) {
208
+ for (const d of p.decls ?? []) {
209
+ for (const name of topLevelDeclNames(d)) {
210
+ if (name === "_") continue;
211
+ const prev = owner.get(name);
212
+ if (prev === undefined) owner.set(name, u.pkgName);
213
+ else if (prev !== u.pkgName)
214
+ errors.push(
215
+ `cannot link wasm packages: '${name}' is declared in both '${prev}' and '${u.pkgName}' (linked wasm packages share one namespace)`,
216
+ );
217
+ }
218
+ }
219
+ }
220
+ }
221
+ if (errors.length > 0) throw new Error([...new Set(errors)].join("\n"));
222
+ }
223
+
224
+ // Replaces the first wasm marker with the facade (dropping the others) and
225
+ // shifts source-map lines that follow it.
226
+ function spliceFacade(merged, facade) {
227
+ const lines = merged.js.split("\n");
228
+ const first = lines.findIndex((l) => WASM_MARKER_RE.test(l));
229
+ if (first < 0) {
230
+ merged.js = `${facade}\n${merged.js}`;
231
+ const shift = facade.split("\n").length;
232
+ for (const m of merged.mappings) m.genLine += shift;
233
+ return;
234
+ }
235
+ const facadeLines = facade.split("\n");
236
+ const delta = facadeLines.length - 1;
237
+ for (const m of merged.mappings) {
238
+ if (m.genLine > first) m.genLine += delta;
239
+ }
240
+ const out = [...lines.slice(0, first), ...facadeLines];
241
+ for (let i = first + 1; i < lines.length; i++) {
242
+ if (!WASM_MARKER_RE.test(lines[i])) out.push(lines[i]);
243
+ }
244
+ merged.js = out.join("\n");
245
+ }
246
+
247
+ // Root compiles only: link every registered unit into app.wasm and splice the
248
+ // facade into the merged bundle. Returns `{ wasm, wat, sourceMapInfo }`
249
+ // (nulls when there is nothing to link).
250
+ export function linkIntoBundle(
251
+ options,
252
+ merged,
253
+ pkgTarget,
254
+ { sourceMappingURL } = {},
255
+ ) {
256
+ const none = {
257
+ wasm: null,
258
+ wat: null,
259
+ sourceMapInfo: null,
260
+ stringTable: null,
261
+ };
262
+ if (options.isDependency) return none;
263
+ const linked = linkWasmUnits(options.wasmUnits, {
264
+ emitWat: options.emitWat,
265
+ natives: options.natives,
266
+ rootTarget: pkgTarget,
267
+ sourceMappingURL,
268
+ });
269
+ if (!linked) return none;
270
+ spliceFacade(merged, linked.facade);
271
+ return {
272
+ wasm: linked.wasm,
273
+ wat: linked.wat ?? null,
274
+ sourceMapInfo: linked.sourceMapInfo ?? null,
275
+ stringTable: linked.stringTable ?? null,
276
+ };
277
+ }
278
+
279
+ // Turns `cmp.Compare` / `cmp.Ordered` references (marked `_stdName` by the
280
+ // checker) into plain identifiers with the mangled name, so WASM
281
+ // monomorphisation sees ordinary top-level references. Only for ASTs that
282
+ // are not cached: a stdlib package's own parse and the WASM link copy (user
283
+ // ASTs are re-checked on the next build; the JS backend reads `_stdName`).
284
+ export function lowerStdlibRefs(node) {
285
+ if (!node || typeof node !== "object") return;
286
+ if (Array.isArray(node)) {
287
+ for (const n of node) lowerStdlibRefs(n);
288
+ return;
289
+ }
290
+ // A generated entry replaces the stdlib declaration the checker resolved
291
+ // (errors.As) the call to.
292
+ if (node._genEntry && node._stdName) delete node._stdName;
293
+ if (node._stdName) {
294
+ if (node.kind === "SelectorExpr") {
295
+ delete node.expr;
296
+ delete node.field;
297
+ node.kind = "Ident";
298
+ }
299
+ node.name = node._stdName;
300
+ delete node._stdName;
301
+ }
302
+ if (node.kind === "CallExpr" && node.func?._jsonStream) {
303
+ const entry = node.func._genEntry;
304
+ node.args.unshift(node.func.expr);
305
+ delete node.func.expr;
306
+ delete node.func.field;
307
+ delete node.func._jsonStream;
308
+ delete node.func._genEntry;
309
+ node.func.kind = "Ident";
310
+ node.func.name = entry;
311
+ } else if (node._genEntry && node.kind === "SelectorExpr") {
312
+ delete node.expr;
313
+ delete node.field;
314
+ node.kind = "Ident";
315
+ node.name = node._genEntry;
316
+ }
317
+ forEachChild(node, lowerStdlibRefs);
318
+ }