gofront 1.6.1 → 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 (132) hide show
  1. package/README.md +45 -49
  2. package/package.json +12 -8
  3. package/src/backend/js/expressions.js +1627 -148
  4. package/src/backend/js/fmt-runtime.js +573 -0
  5. package/src/backend/js/index.js +508 -102
  6. package/src/backend/js/runtime.js +1997 -106
  7. package/src/backend/js/statements.js +931 -87
  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 +7 -1
  12. package/src/backend/js/stdlib/fmt.js +349 -10
  13. package/src/backend/js/stdlib/index.js +19 -2
  14. package/src/backend/js/stdlib/json.js +1167 -0
  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 +34 -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 +446 -72
  29. package/src/backend/wasm/emit-builtins.js +320 -13
  30. package/src/backend/wasm/emit-exprs.js +1404 -199
  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 +518 -74
  34. package/src/backend/wasm/encode.js +128 -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/optimize.js +4 -2
  41. package/src/backend/wasm/prescan.js +397 -0
  42. package/src/backend/wasm/stdlib/bytes.js +1804 -127
  43. package/src/backend/wasm/stdlib/core.js +1574 -199
  44. package/src/backend/wasm/stdlib/index.js +3 -5
  45. package/src/backend/wasm/stdlib/io.js +1567 -150
  46. package/src/backend/wasm/stdlib/packages.js +2 -0
  47. package/src/backend/wasm/stdlib/simd.js +499 -0
  48. package/src/backend/wasm/stdlib/time.js +1041 -12
  49. package/src/backend/wasm/types.js +221 -15
  50. package/src/backend/wasm/variadic.js +93 -0
  51. package/src/backend/wasm/wat.js +84 -20
  52. package/src/{cli-core.js → cli/cli-core.js} +236 -10
  53. package/src/{test-runner.js → cli/test-runner.js} +332 -39
  54. package/src/{vendor.js → cli/vendor.js} +89 -15
  55. package/src/compiler.js +107 -269
  56. package/src/dts-parser.js +71 -14
  57. package/src/index.js +15 -169
  58. package/src/{lexer.js → lexer/lexer.js} +102 -55
  59. package/src/{tokens.js → lexer/tokens.js} +1 -0
  60. package/src/link/sourcemap.js +97 -0
  61. package/src/link/stdlib.js +515 -0
  62. package/src/link/wasm.js +294 -0
  63. package/src/lower/bounds.js +394 -0
  64. package/src/lower/boxing.js +1 -6
  65. package/src/lower/captures.js +176 -32
  66. package/src/lower/embedding.js +2 -1
  67. package/src/lower/index.js +26 -18
  68. package/src/lower/json-codecs.js +1398 -0
  69. package/src/lower/ownership.js +22 -1
  70. package/src/lower/range.js +86 -1
  71. package/src/lower/reachability.js +132 -0
  72. package/src/parser/declarations.js +58 -13
  73. package/src/parser/expressions.js +29 -7
  74. package/src/parser/index.js +2 -1
  75. package/src/parser/statements.js +37 -22
  76. package/src/parser/struct-tag.js +144 -0
  77. package/src/{templ-parser.js → parser/templ.js} +138 -15
  78. package/src/parser/types.js +130 -13
  79. package/src/resolver.js +22 -1
  80. package/src/typechecker/assignability.js +215 -11
  81. package/src/typechecker/const-fold.js +356 -0
  82. package/src/typechecker/constants.js +256 -0
  83. package/src/typechecker/expressions.js +960 -99
  84. package/src/typechecker/index.js +491 -72
  85. package/src/typechecker/init-order.js +330 -0
  86. package/src/typechecker/resolve.js +596 -52
  87. package/src/typechecker/statements.js +157 -17
  88. package/src/typechecker/stdlib/core.js +333 -55
  89. package/src/typechecker/stdlib/excluded.js +898 -0
  90. package/src/typechecker/stdlib/extended.js +359 -26
  91. package/src/typechecker/{stdlib.js → stdlib/index.js} +6 -4
  92. package/src/typechecker/stdlib/simd.js +123 -0
  93. package/src/typechecker/termination.js +1 -1
  94. package/src/typechecker/types.js +165 -26
  95. package/stdlib/bytes/iter.go +192 -0
  96. package/stdlib/bytes/search.go +240 -0
  97. package/stdlib/bytes/split.go +218 -0
  98. package/stdlib/cmp/cmp.go +65 -0
  99. package/stdlib/encoding/json/errors.go +31 -0
  100. package/stdlib/encoding/json/indent.go +71 -0
  101. package/stdlib/encoding/json/number.go +12 -0
  102. package/stdlib/encoding/json/stream.go +173 -0
  103. package/stdlib/errors/overlay.go +12 -0
  104. package/stdlib/hash/hash.go +53 -0
  105. package/stdlib/internal/jsonrt/dec.go +738 -0
  106. package/stdlib/internal/jsonrt/enc.go +366 -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 +649 -0
  111. package/stdlib/io/io.go +346 -0
  112. package/stdlib/iter/iter.go +18 -0
  113. package/stdlib/maps/iter.go +65 -0
  114. package/stdlib/math/extra.go +270 -0
  115. package/stdlib/slices/extra.go +73 -0
  116. package/stdlib/slices/iter.go +113 -0
  117. package/stdlib/sort/sort.go +561 -0
  118. package/stdlib/strconv/quote.go +341 -0
  119. package/stdlib/strings/extra.go +35 -0
  120. package/stdlib/strings/iter.go +122 -0
  121. package/stdlib/sync/extra.go +105 -0
  122. package/stdlib/unicode/unicode.go +112 -0
  123. package/stdlib/unicode/utf8/bytes.go +239 -0
  124. package/src/backend/wasm/const-fold.js +0 -205
  125. package/src/backend/wasm/emit-stdlib.js +0 -13
  126. /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
  127. /package/src/{colors.js → cli/colors.js} +0 -0
  128. /package/src/{dev-server.js → cli/dev-server.js} +0 -0
  129. /package/src/{minifier.js → cli/minifier.js} +0 -0
  130. /package/src/{project-config.js → cli/project-config.js} +0 -0
  131. /package/src/{pwa.js → cli/pwa.js} +0 -0
  132. /package/src/{templ-lexer.js → lexer/templ-lexer.js} +0 -0
@@ -0,0 +1,515 @@
1
+ // Go-source stdlib pipeline: packages under stdlib/<path>/ are parsed, checked
2
+ // twice (probe, then mangled), linked into app.wasm and spliced into the JS
3
+ // bundle. compiler.js owns import resolution, so the functions that need it
4
+ // (and the parser/checker helpers it also exports) arrive through an injected
5
+ // `deps` argument: `{ gwFilesIn, resolveImports, TypeChecker }`. Importing
6
+ // compiler.js from here would create a cycle.
7
+
8
+ import { readFileSync } from "node:fs";
9
+ import { basename, dirname, join, resolve } from "node:path";
10
+ import { CodeGen } from "../backend/js/index.js";
11
+ import { Lexer } from "../lexer/lexer.js";
12
+ import { generateJsonCodecs } from "../lower/json-codecs.js";
13
+ import { reachableStdlibDecls } from "../lower/reachability.js";
14
+ import { forEachChild } from "../lower/walk.js";
15
+ import { Parser } from "../parser/index.js";
16
+ import {
17
+ isBuiltinPackage,
18
+ isLocalPath,
19
+ resolveStdlibSource,
20
+ } from "../resolver.js";
21
+ import { lowerStdlibRefs, registerWasmUnit } from "./wasm.js";
22
+
23
+ // ── Go-source stdlib ──────────────────────────────────────────
24
+ //
25
+ // Packages under stdlib/<path>/ are GoFront Go. Each is type-checked
26
+ // and compiled once per build as a `both` package (strict numerics): its JS
27
+ // is bundled for js/both importers and its programs are linked into app.wasm
28
+ // for wasm/both importers, never through the boundary facade. Top-level
29
+ // names are mangled to `Name$$path` so they cannot collide with user
30
+ // declarations in the flat JS bundle or the linked module. A directory for an
31
+ // emitter-backed package (`errors`) is an overlay: its members join that
32
+ // namespace and unqualified references to emitter members become `errors.X`.
33
+
34
+ function stdlibSuffix(importPath) {
35
+ return `$$${importPath.replaceAll("/", "$")}`;
36
+ }
37
+
38
+ function parseStdlibFiles(dir, deps) {
39
+ return deps.gwFilesIn(dir).map((f) => {
40
+ const source = readFileSync(f, "utf8");
41
+ const filename = basename(f);
42
+ const tokens = new Lexer(source, filename).tokenize();
43
+ const ast = new Parser(tokens, filename, source).parse();
44
+ ast._source = source;
45
+ ast._path = resolve(f);
46
+ ast.target = "both";
47
+ return ast;
48
+ });
49
+ }
50
+
51
+ // Top-level value and type names declared by the package.
52
+ function stdlibTopLevelNames(programs) {
53
+ const values = new Set();
54
+ const types = new Set();
55
+ for (const p of programs) {
56
+ for (const d of p.decls ?? []) {
57
+ if (d.kind === "TypeDecl") types.add(d.name);
58
+ else if (d.kind === "FuncDecl" && d.name !== "init") values.add(d.name);
59
+ else if (d.kind === "VarDecl" || d.kind === "ConstDecl")
60
+ for (const spec of d.decls ?? [])
61
+ for (const n of spec.names ?? []) if (n !== "_") values.add(n);
62
+ }
63
+ }
64
+ return { values, types };
65
+ }
66
+
67
+ // Renames the package's top-level declarations and every reference to them.
68
+ // `refs` holds the `file:line:col` of identifiers the first type-check
69
+ // resolved to package scope; type names are resolved by name (GoFront types
70
+ // are package-flat) except where a type parameter shadows them.
71
+ export function mangleStdlibAst(programs, ctx) {
72
+ for (const p of programs) {
73
+ for (const d of p.decls ?? []) mangleDeclNames(d, ctx);
74
+ mangleRefs(p.decls, p._filename, new Set(), ctx);
75
+ }
76
+ }
77
+
78
+ function mangleDeclNames(d, { suffix, values }) {
79
+ if (d.kind === "TypeDecl" || (d.kind === "FuncDecl" && values.has(d.name))) {
80
+ d.name += suffix;
81
+ } else if (d.kind === "VarDecl" || d.kind === "ConstDecl") {
82
+ for (const spec of d.decls ?? [])
83
+ spec.names = spec.names.map((n) => (values.has(n) ? n + suffix : n));
84
+ }
85
+ }
86
+
87
+ function mangleRefs(node, file, tparams, ctx) {
88
+ if (!node || typeof node !== "object") return;
89
+ if (Array.isArray(node)) {
90
+ for (const n of node) mangleRefs(n, file, tparams, ctx);
91
+ return;
92
+ }
93
+ const tp =
94
+ node.typeParams?.length > 0
95
+ ? new Set([...tparams, ...node.typeParams.map((t) => t.name)])
96
+ : tparams;
97
+ switch (node.kind) {
98
+ case "TypeName":
99
+ case "GenericTypeName":
100
+ mangleTypeRef(node, tp, ctx);
101
+ break;
102
+ case "CompositeLit":
103
+ if (node.typeExpr?.kind === "Ident")
104
+ mangleTypeRef(node.typeExpr, tp, ctx);
105
+ break;
106
+ case "InstantiationExpr": // `Stack[T]{}`, `Pair[K, V](x)`
107
+ case "IndexExpr":
108
+ if (node.expr?.kind === "Ident") mangleTypeRef(node.expr, tp, ctx);
109
+ break;
110
+ case "CallExpr":
111
+ if (
112
+ (node.func?.name === "new" || node.func?.name === "make") &&
113
+ node.args?.[0]?.kind === "Ident"
114
+ ) {
115
+ mangleTypeRef(node.args[0], tp, ctx);
116
+ }
117
+ break;
118
+ case "Ident":
119
+ if (ctx.refs.has(`${file}:${node._line}:${node._col}`))
120
+ mangleIdentRef(node, ctx);
121
+ break;
122
+ }
123
+ forEachChild(node, (child) => mangleRefs(child, file, tp, ctx));
124
+ }
125
+
126
+ function mangleTypeRef(node, tparams, { suffix, types, overlay }) {
127
+ if (types.has(node.name) && !tparams.has(node.name)) {
128
+ node.name += suffix;
129
+ } else if (overlay && node.name in overlay.members) {
130
+ node.name = `${overlay.name}.${node.name}`;
131
+ }
132
+ }
133
+
134
+ // A package-scope identifier: a package declaration gets the suffix; in an
135
+ // overlay, an emitter member (`New` in errors) becomes `errors.New`.
136
+ function mangleIdentRef(node, { suffix, values, types, overlay }) {
137
+ if (values.has(node.name) || types.has(node.name)) {
138
+ node.name += suffix;
139
+ } else if (overlay && node.name in overlay.members) {
140
+ const field = node.name;
141
+ delete node.name;
142
+ Object.assign(node, {
143
+ kind: "SelectorExpr",
144
+ expr: { kind: "Ident", name: overlay.name, _line: node._line },
145
+ field,
146
+ });
147
+ }
148
+ }
149
+
150
+ function checkStdlibPrograms(programs, pkgName, options, overlay, deps) {
151
+ const checker = new deps.TypeChecker();
152
+ checker.target = "both";
153
+ checker.pkgName = pkgName;
154
+ checker.isStdlib = true;
155
+ if (overlay) {
156
+ for (const [name, t] of Object.entries(overlay.members)) {
157
+ checker.globals.define(name, t);
158
+ if (t.kind === "interface" || t.kind === "named" || t.kind === "struct") {
159
+ checker.types.set(name, t);
160
+ }
161
+ }
162
+ }
163
+ deps.resolveImports(
164
+ programs,
165
+ programs[0]._path,
166
+ checker,
167
+ new Map(),
168
+ new Set(),
169
+ [],
170
+ new Set(),
171
+ options,
172
+ );
173
+ return checker;
174
+ }
175
+
176
+ // Errors in stdlib source are compiler bugs; the importer reports them at its
177
+ // import (see reportStdlibLoadError), so only the message text is kept, never
178
+ // a location inside stdlib/.
179
+ function throwStdlibErrors(errors) {
180
+ if (errors.length === 0) return;
181
+ const detail = (e) =>
182
+ e.message
183
+ .split("\n")[0]
184
+ .replace(/^Type error(?: in \S+)?(?: at line \d+:\d+)?:\s*/, "");
185
+ throw new Error([...new Set(errors.map(detail))].join("; "));
186
+ }
187
+
188
+ // Pass 1: type-check the package as written and record which identifiers
189
+ // refer to package scope. An overlay sees its emitter members unqualified.
190
+ function probeStdlibPackage(_importPath, dir, options, overlay, deps) {
191
+ const programs = parseStdlibFiles(dir, deps);
192
+ const pkgName = programs[0].pkg.name;
193
+ const { values, types } = stdlibTopLevelNames(programs);
194
+ for (const n of [...values, ...types])
195
+ if (overlay && n in overlay.members)
196
+ throw new Error(`overlay redeclares ${overlay.name}.${n}`);
197
+ const probe = checkStdlibPrograms(programs, pkgName, options, overlay, deps);
198
+ probe._pkgRefs = new Set();
199
+ throwStdlibErrors(probe.checkAll(programs));
200
+ return { pkgName, values, types, refs: probe._pkgRefs };
201
+ }
202
+
203
+ // Exported members as seen by importers (original name -> type) and the
204
+ // original -> mangled name map; an overlay keeps the emitter members too.
205
+ function stdlibNamespace(checker, { pkgName, values, types, suffix }, overlay) {
206
+ const members = overlay ? { ...overlay.members } : {};
207
+ const mangle = new Map();
208
+ for (const name of [...values, ...types]) {
209
+ const t = checker.globals.symbols.get(name + suffix);
210
+ if (!/^[A-Z]/.test(name) || t === undefined) continue;
211
+ members[name] = t;
212
+ mangle.set(name, name + suffix);
213
+ }
214
+ return {
215
+ ...(overlay ?? {}),
216
+ kind: "namespace",
217
+ name: pkgName,
218
+ members,
219
+ _gofront: !overlay,
220
+ _target: "both",
221
+ _mangle: mangle,
222
+ };
223
+ }
224
+
225
+ // Mangled type names (needed by the backends) plus `pkg.T` for exported ones.
226
+ function stdlibExportedTypes(checker, { pkgName, suffix }) {
227
+ const out = new Map();
228
+ for (const [k, t] of checker.types) {
229
+ const at = k.indexOf("$$");
230
+ if (at < 0) continue;
231
+ out.set(k, t);
232
+ const orig = k.slice(0, at);
233
+ if (k === orig + suffix && /^[A-Z]/.test(orig))
234
+ out.set(`${pkgName}.${orig}`, t);
235
+ }
236
+ return out;
237
+ }
238
+
239
+ // Loads (once per build) and compiles the Go-source package at `dir`. A
240
+ // failure is cached too, so every importer reports it.
241
+ function loadStdlibPackage(importPath, dir, options, deps) {
242
+ const cache = options.stdlibCache;
243
+ const cached = cache.get(importPath);
244
+ if (cached === null)
245
+ throw new Error(`import cycle in Go-source stdlib: ${importPath}`);
246
+ if (cached instanceof Error) throw cached;
247
+ if (cached) return cached;
248
+ cache.set(importPath, null);
249
+ try {
250
+ const pkg = buildStdlibPackage(importPath, dir, options, deps);
251
+ cache.set(importPath, pkg);
252
+ return pkg;
253
+ } catch (e) {
254
+ cache.set(importPath, e);
255
+ throw e;
256
+ }
257
+ }
258
+
259
+ function buildStdlibPackage(importPath, dir, options, deps) {
260
+ const cache = options.stdlibCache;
261
+ const overlay = isBuiltinPackage(importPath)
262
+ ? new deps.TypeChecker().globals.lookup(importPath.split("/").at(-1))
263
+ : null;
264
+ const info = {
265
+ ...probeStdlibPackage(importPath, dir, options, overlay, deps),
266
+ suffix: stdlibSuffix(importPath),
267
+ };
268
+
269
+ // Pass 2: mangle a fresh parse and check it again.
270
+ const programs = parseStdlibFiles(dir, deps);
271
+ mangleStdlibAst(programs, { ...info, overlay });
272
+ const checker = checkStdlibPrograms(
273
+ programs,
274
+ info.pkgName,
275
+ options,
276
+ null,
277
+ deps,
278
+ );
279
+ throwStdlibErrors(checker.checkAll(programs));
280
+ lowerStdlibRefs(programs);
281
+
282
+ const pkg = {
283
+ importPath,
284
+ checker,
285
+ pkgName: info.pkgName,
286
+ overlay,
287
+ namespace: stdlibNamespace(checker, info, overlay),
288
+ exportedTypes: stdlibExportedTypes(checker, info),
289
+ deps: programs
290
+ .flatMap((p) => p.imports.flatMap((imp) => imp.imports))
291
+ .map(({ path }) => cache.get(path))
292
+ .filter(Boolean),
293
+ unit: {
294
+ key: `stdlib:${importPath}`,
295
+ pkgName: info.pkgName,
296
+ target: "both",
297
+ programs,
298
+ types: checker.types,
299
+ bundledPackages: new Set(),
300
+ },
301
+ };
302
+ return pkg;
303
+ }
304
+
305
+ // A Go-source package's JS is generated at the root compile, once every
306
+ // JS-emitted user program is known, so only reachable declarations are
307
+ // emitted (see lower/reachability.js). Importers leave a marker line.
308
+ const STDLIB_MARKER_RE = /^\/\*__GOFRONT_STDLIB:([^*]*)\*\/$/;
309
+
310
+ function stdlibMarker(importPath) {
311
+ return `/*__GOFRONT_STDLIB:${importPath}*/`;
312
+ }
313
+
314
+ function stdlibJs(pkg, reached) {
315
+ const programs = pkg.unit.programs.map((p) => ({
316
+ ...p,
317
+ decls: p.decls.filter((d) => reached.has(d)),
318
+ }));
319
+ if (programs.every((p) => p.decls.length === 0)) return "";
320
+ return new CodeGen(pkg.checker, new Map(), new Set(), {
321
+ target: "both",
322
+ strict: true,
323
+ }).generateAll(programs, { isTest: false });
324
+ }
325
+
326
+ // The API a wasm package exposes to JS through the facade: exported func and
327
+ // method signatures and exported type declarations.
328
+ function wasmExportedSignatures(units) {
329
+ const out = [];
330
+ for (const u of units) {
331
+ if (u.target !== "wasm" || u.key.startsWith("stdlib:")) continue;
332
+ for (const d of u.programs.flatMap((p) => p.decls ?? [])) {
333
+ if (!/^[A-Z]/.test(d.name ?? "")) continue;
334
+ if (d.kind === "TypeDecl") out.push(d.type);
335
+ else if (d.kind === "FuncDecl" || d.kind === "MethodDecl")
336
+ out.push(d.params, d.returnType);
337
+ }
338
+ }
339
+ return out;
340
+ }
341
+
342
+ // Replaces each marker with the package's reachable code (no line at all when
343
+ // nothing is reachable) and shifts the source-map lines that follow.
344
+ function spliceStdlibJs(merged, options) {
345
+ const lines = merged.js.split("\n");
346
+ const pkgs = lines
347
+ .map((l) => l.match(STDLIB_MARKER_RE)?.[1])
348
+ .filter(Boolean)
349
+ .map((path) => options.stdlibCache.get(path));
350
+ if (pkgs.length === 0) return;
351
+ const reached = reachableStdlibDecls(
352
+ [options.jsRootPrograms, wasmExportedSignatures(options.wasmUnits)],
353
+ pkgs.flatMap((pkg) => pkg.unit.programs),
354
+ );
355
+ const out = [];
356
+ const spliced = new Set();
357
+ for (const line of lines) {
358
+ const path = line.match(STDLIB_MARKER_RE)?.[1];
359
+ if (!path) {
360
+ out.push(line);
361
+ continue;
362
+ }
363
+ if (spliced.has(path)) continue;
364
+ spliced.add(path);
365
+ const js = stdlibJs(options.stdlibCache.get(path), reached);
366
+ const code = js === "" ? [] : js.split("\n");
367
+ const delta = code.length - 1;
368
+ for (const m of merged.mappings)
369
+ if (m.genLine > out.length) m.genLine += delta;
370
+ out.push(...code);
371
+ }
372
+ merged.js = out.join("\n");
373
+ }
374
+
375
+ // Records a package's JS-emitted programs as reachability roots; the root
376
+ // compile then splices in the stdlib code they reach.
377
+ export function finishStdlibJs(merged, options, programs, emitTarget) {
378
+ if (emitTarget !== "wasm") options.jsRootPrograms.push(...programs);
379
+ if (!options.isDependency) spliceStdlibJs(merged, options);
380
+ }
381
+
382
+ // Adds a loaded package (and, first, its Go-source dependencies) to the
383
+ // importer's output: JS for js/both importers, a link unit for wasm/both.
384
+ function emitStdlibPackage(
385
+ pkg,
386
+ importerTarget,
387
+ preambles,
388
+ bundledDirs,
389
+ options,
390
+ ) {
391
+ for (const dep of pkg.deps)
392
+ emitStdlibPackage(dep, importerTarget, preambles, bundledDirs, options);
393
+ // Every importer leaves a JS marker: the facade of a wasm package may
394
+ // expose a stdlib type; unreachable code splices to nothing.
395
+ const key = `${pkg.unit.key}:js`;
396
+ if (!bundledDirs.has(key)) {
397
+ bundledDirs.add(key);
398
+ preambles.push(stdlibMarker(pkg.importPath));
399
+ }
400
+ if (importerTarget !== "js") registerWasmUnit(options, pkg.unit);
401
+ }
402
+
403
+ function importNode({ _line, _col, line, col }) {
404
+ return { _line, _col, line: line ?? _line, col: col ?? _col ?? 1 };
405
+ }
406
+
407
+ // Reports `msg` at an import spec of program `p`.
408
+ function errAtImport(checker, p, spec, msg, hint = null) {
409
+ const saved = [checker._currentFile, checker._currentSource];
410
+ checker._currentFile = p._filename ?? null;
411
+ checker._currentSource = p._source ?? null;
412
+ checker.err(msg, importNode(spec), hint);
413
+ [checker._currentFile, checker._currentSource] = saved;
414
+ }
415
+
416
+ // Defines the import's namespace (and `pkg.T` type names) in the importer.
417
+ function bindStdlibImport(checker, p, spec, pkg) {
418
+ const { path, alias } = spec;
419
+ if (alias === "_") return;
420
+ if (alias === ".") {
421
+ errAtImport(checker, p, spec, `dot-import of '${path}' is not supported`);
422
+ return;
423
+ }
424
+ const name = alias ?? pkg.pkgName;
425
+ // Emitter-backed members are emitted by package name, so an overlaid
426
+ // package cannot be renamed (aliases of emitter packages never worked).
427
+ if (pkg.overlay && name !== pkg.pkgName) {
428
+ errAtImport(
429
+ checker,
430
+ p,
431
+ spec,
432
+ `import alias for '${path}' is not supported`,
433
+ );
434
+ return;
435
+ }
436
+ checker.globals.define(name, { ...pkg.namespace, name });
437
+ for (const [k, t] of pkg.exportedTypes) {
438
+ const dot = k.indexOf(".");
439
+ checker.types.set(dot < 0 ? k : `${name}${k.slice(dot)}`, t);
440
+ }
441
+ if (!pkg.overlay)
442
+ checker.trackImport(name, importNode(spec), p._filename, p._source);
443
+ }
444
+
445
+ // Generates, imports and checks the codecs for the package's `encoding/json`
446
+ // calls as one more (wasm-only) file. Returns the generated programs: none
447
+ // for a js package, a package with errors, or one that makes no json calls.
448
+ export function checkJsonCodecs(programs, checker, preambles, options, deps) {
449
+ const wasm = checker.target === "wasm" || checker.target === "both";
450
+ if (!wasm || checker.errors.length > 0) return [];
451
+ const gen = generateJsonCodecs(programs, checker, checker.pkgName);
452
+ if (!gen) return [];
453
+ for (const { program, node, message, hint } of gen.diagnostics) {
454
+ checker._setCurrentFile(program);
455
+ checker.recordBlocker("unsupported stdlib member", message);
456
+ checker.err(message, node, hint);
457
+ }
458
+ if (gen.diagnostics.length > 0) return [];
459
+ const filename = "json_codecs.go";
460
+ const ast = new Parser(
461
+ new Lexer(gen.source, filename).tokenize(),
462
+ filename,
463
+ gen.source,
464
+ ).parse();
465
+ ast._source = gen.source;
466
+ ast._path = join(dirname(programs[0]._path ?? "."), filename);
467
+ ast.target = checker.target;
468
+ importStdlibPackages(
469
+ [ast],
470
+ checker,
471
+ preambles,
472
+ options.bundledDirs ?? new Set(),
473
+ options,
474
+ deps,
475
+ );
476
+ const before = checker.errors.length;
477
+ checker.checkAll([ast]);
478
+ if (checker.errors.length > before) {
479
+ const detail = checker.errors
480
+ .slice(before)
481
+ .map((e) => e.message)
482
+ .join("\n");
483
+ throw new Error(
484
+ `internal error in the generated encoding/json codecs; please report\n${detail}`,
485
+ );
486
+ }
487
+ return [ast];
488
+ }
489
+
490
+ export function importStdlibPackages(
491
+ programs,
492
+ checker,
493
+ preambles,
494
+ bundledDirs,
495
+ options,
496
+ deps,
497
+ ) {
498
+ for (const p of programs) {
499
+ for (const spec of p.imports.flatMap((imp) => imp.imports)) {
500
+ if (spec.path.startsWith("js:") || isLocalPath(spec.path)) continue;
501
+ const dir = resolveStdlibSource(spec.path, options.stdlibRoot);
502
+ if (!dir) continue;
503
+ let pkg;
504
+ try {
505
+ pkg = loadStdlibPackage(spec.path, dir, options, deps);
506
+ } catch (e) {
507
+ const msg = `internal stdlib error in ${spec.path}; please report`;
508
+ errAtImport(checker, p, spec, msg, e.message);
509
+ continue;
510
+ }
511
+ emitStdlibPackage(pkg, checker.target, preambles, bundledDirs, options);
512
+ bindStdlibImport(checker, p, spec, pkg);
513
+ }
514
+ }
515
+ }