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,330 @@
1
+ // Package initialisation order (Go spec, "Package initialization").
2
+ //
3
+ // A package-level variable is initialised once every variable its initialiser
4
+ // refers to has been, where "refers to" follows references to functions and
5
+ // methods transitively. Each step picks the earliest variable in declaration
6
+ // order that is ready; a step with none left over is an initialisation cycle.
7
+ // Constants are folded by value, so they only need ordering among themselves
8
+ // (a constant may name one declared later).
9
+ //
10
+ // The checker reports cycles; both backends emit initialisers in this order.
11
+ // Shadowing is handled conservatively: a name declared anywhere in a function
12
+ // body (or as a parameter) is never counted as a reference to the package-level
13
+ // name inside that function, so the analysis can miss a dependency but never
14
+ // invents a cycle.
15
+
16
+ function forEachChildNode(node, fn) {
17
+ for (const key of Object.keys(node)) {
18
+ if (key.charCodeAt(0) === 95) continue; // "_" side tables
19
+ const v = node[key];
20
+ if (v && typeof v === "object") fn(v);
21
+ }
22
+ }
23
+
24
+ // Names declared inside a function-like node (parameters, results, locals).
25
+ function declaredNames(node, out = new Set()) {
26
+ if (!node || typeof node !== "object") return out;
27
+ if (Array.isArray(node)) {
28
+ for (const n of node) declaredNames(n, out);
29
+ return out;
30
+ }
31
+ if (node.kind === "DefineStmt") {
32
+ for (const l of [node.lhs].flat()) if (l?.kind === "Ident") out.add(l.name);
33
+ } else if (node.kind === "VarDecl" || node.kind === "ConstDecl") {
34
+ for (const spec of node.decls ?? []) for (const n of spec.names) out.add(n);
35
+ } else if (node.kind === "RangeStmt" || node.kind === "ForRangeStmt") {
36
+ for (const k of [node.key, node.value, node.keyVar, node.valueVar])
37
+ if (k?.kind === "Ident") out.add(k.name);
38
+ if (typeof node.key === "string") out.add(node.key);
39
+ if (typeof node.value === "string") out.add(node.value);
40
+ } else if (node.kind === "TypeSwitchStmt" && node.assign) {
41
+ out.add(node.assign);
42
+ }
43
+ if (Array.isArray(node.params))
44
+ for (const p of node.params) if (p?.name) out.add(p.name);
45
+ if (node.recvName) out.add(node.recvName);
46
+ for (const r of node.returnType?._namedReturns ?? [])
47
+ if (r.name) out.add(r.name);
48
+ forEachChildNode(node, (c) => declaredNames(c, out));
49
+ return out;
50
+ }
51
+
52
+ // The `Type.method` key of the declaration `name` selects on a value of type
53
+ // `t`, found the way the checker finds it: on the type itself, else on an
54
+ // embedded type (through pointers too). Interface methods have no body to
55
+ // follow, so a call through an interface adds no dependency (Go does the same).
56
+ function methodKeyOf(t, name, funcs, depth = 0) {
57
+ let x = t;
58
+ if (x?.kind === "pointer") x = x.base;
59
+ if (x?.kind !== "named" || depth > 8) return null;
60
+ for (const typeName of [x.name, x._generic?.name]) {
61
+ const key = `${typeName}.${name}`;
62
+ if (typeName && funcs.has(key)) return key;
63
+ }
64
+ for (const e of x.underlying?._embeds ?? []) {
65
+ const key = methodKeyOf(e, name, funcs, depth + 1);
66
+ if (key) return key;
67
+ }
68
+ return null;
69
+ }
70
+
71
+ // Whether the keys of a composite literal are expressions (map, slice and
72
+ // array literals) rather than field names (struct literals). Before the
73
+ // literal is checked its written type decides; an unnamed one stays ambiguous
74
+ // and its keys are skipped.
75
+ function litHasExprKeys(lit) {
76
+ let t = lit._type;
77
+ for (let i = 0; t && i < 8; i++) {
78
+ if (t.kind === "named") t = t.underlying;
79
+ else if (t.kind === "pointer") t = t.base;
80
+ else break;
81
+ }
82
+ if (t?.kind) return ["map", "slice", "array"].includes(t.kind);
83
+ return ["MapType", "SliceType", "ArrayType"].includes(lit.typeExpr?.kind);
84
+ }
85
+
86
+ function walkRefs(node, shadow, ctx, out) {
87
+ if (!node || typeof node !== "object") return;
88
+ if (Array.isArray(node)) {
89
+ for (const n of node) walkRefs(n, shadow, ctx, out);
90
+ return;
91
+ }
92
+ if (node.kind === "Ident") {
93
+ if (ctx.pkgNames.has(node.name) && !shadow.has(node.name))
94
+ out.names.add(node.name);
95
+ return;
96
+ }
97
+ if (node.kind === "SelectorExpr") {
98
+ const key = methodKeyOf(node.expr?._type, node.field, ctx.funcs);
99
+ if (key) out.methods.add(key);
100
+ }
101
+ if (node.kind === "CompositeLit") {
102
+ const exprKeys = litHasExprKeys(node);
103
+ for (const el of node.elems ?? []) {
104
+ if (el?.kind !== "KeyValueExpr") walkRefs(el, shadow, ctx, out);
105
+ else {
106
+ // A struct literal's key is a field name, not a reference.
107
+ if (exprKeys || el.key?.kind !== "Ident")
108
+ walkRefs(el.key, shadow, ctx, out);
109
+ walkRefs(el.value, shadow, ctx, out);
110
+ }
111
+ }
112
+ walkRefs(node.typeExpr, shadow, ctx, out);
113
+ return;
114
+ }
115
+ forEachChildNode(node, (c) => walkRefs(c, shadow, ctx, out));
116
+ }
117
+
118
+ /**
119
+ * Collects what `root` (an initialiser expression or a function declaration)
120
+ * refers to: package-level names (`names`) and declarations selected as methods
121
+ * (`methods`, keyed `Type.method`). The single place shadowing is decided:
122
+ * a name declared anywhere inside `root` never counts as the package-level one.
123
+ */
124
+ function collectRefs(root, ctx, out) {
125
+ walkRefs(root, declaredNames(root), ctx, out);
126
+ }
127
+
128
+ const emptyRefs = () => ({ names: new Set(), methods: new Set() });
129
+
130
+ // Package-level specs and callable declarations of all files.
131
+ function collectDecls(programs) {
132
+ const varEntries = [];
133
+ const constEntries = [];
134
+ const funcs = new Map(); // name | "Type.method" -> declaration
135
+ for (const program of programs) {
136
+ for (const d of program.decls ?? []) {
137
+ if (d.kind === "VarDecl" || d.kind === "ConstDecl") {
138
+ const into = d.kind === "VarDecl" ? varEntries : constEntries;
139
+ for (const spec of d.decls ?? [])
140
+ into.push({ decl: d, spec, names: spec.names ?? [], program });
141
+ } else if (d.kind === "FuncDecl") {
142
+ funcs.set(d.name, d);
143
+ } else if (d.kind === "MethodDecl") {
144
+ const t = d.recvType?.name ?? d.recvType?.base?.name;
145
+ if (t) funcs.set(`${t}.${d.name}`, d);
146
+ }
147
+ }
148
+ }
149
+ return { varEntries, constEntries, funcs };
150
+ }
151
+
152
+ // For each var spec, the other var specs its initialiser depends on (through
153
+ // functions and methods too), with the name chain leading to each.
154
+ function buildVarDeps({ varEntries, constEntries, funcs }) {
155
+ const varOwner = new Map(); // var name -> entry
156
+ for (const e of varEntries) for (const n of e.names) varOwner.set(n, e);
157
+ const pkgNames = new Set([
158
+ ...varOwner.keys(),
159
+ ...funcs.keys(),
160
+ ...constEntries.flatMap((e) => e.names),
161
+ ]);
162
+ const ctx = { pkgNames, funcs };
163
+ const funcRefs = new Map();
164
+ const refsOfFunc = (key) => {
165
+ if (funcRefs.has(key)) return funcRefs.get(key);
166
+ const decl = funcs.get(key);
167
+ const out = emptyRefs();
168
+ funcRefs.set(key, out);
169
+ if (decl) collectRefs(decl, ctx, out);
170
+ return out;
171
+ };
172
+ const depsOf = (entry) => {
173
+ const deps = new Map(); // owner entry -> path of names
174
+ const seen = new Set();
175
+ const follow = (key, path) => {
176
+ if (!funcs.has(key) || seen.has(key)) return;
177
+ seen.add(key);
178
+ visit(refsOfFunc(key), [...path, key]);
179
+ };
180
+ const visit = (refs, path) => {
181
+ for (const name of refs.names) {
182
+ const owner = varOwner.get(name);
183
+ if (owner) {
184
+ if (!deps.has(owner)) deps.set(owner, [...path, name]);
185
+ } else follow(name, path);
186
+ }
187
+ for (const m of refs.methods) follow(m, path);
188
+ };
189
+ const refs = emptyRefs();
190
+ for (const v of entry.spec.value ?? []) collectRefs(v, ctx, refs);
191
+ visit(refs, []);
192
+ return deps;
193
+ };
194
+ return new Map(varEntries.map((e) => [e, depsOf(e)]));
195
+ }
196
+
197
+ // A chain of names leading from `start` back to itself through the specs in
198
+ // `pending`, e.g. ["a", "f", "b", "a"]; null when `start` is on no cycle.
199
+ function findCycle(start, depsOf, pending) {
200
+ const visited = new Set();
201
+ const walk = (entry, chain) => {
202
+ for (const [dep, path] of depsOf.get(entry)) {
203
+ const next = [...chain, ...path];
204
+ if (dep === start) return next;
205
+ if (!pending.has(dep) || visited.has(dep)) continue;
206
+ visited.add(dep);
207
+ const found = walk(dep, next);
208
+ if (found) return found;
209
+ }
210
+ return null;
211
+ };
212
+ const chain = walk(start, [start.names[0]]);
213
+ return chain && chain.length === 2 ? [chain[0]] : chain;
214
+ }
215
+
216
+ function cycleMessage(entry, chain) {
217
+ const name = entry.names[0];
218
+ if (!chain) return `initialization cycle for ${name}`;
219
+ if (chain.length === 1)
220
+ return `initialization cycle: ${name} refers to itself`;
221
+ return `initialization cycle for ${name}: ${chain.join(" refers to ")}`;
222
+ }
223
+
224
+ // Go's rule: repeatedly take the earliest spec whose dependencies are done.
225
+ function orderVars(varEntries, depsOf) {
226
+ const done = new Set();
227
+ const vars = [];
228
+ const ready = (e) => {
229
+ for (const dep of depsOf.get(e).keys()) {
230
+ if (dep === e && e.names.length > 1) continue;
231
+ if (!done.has(dep)) return false;
232
+ }
233
+ return true;
234
+ };
235
+ const remaining = varEntries.slice();
236
+ while (remaining.length > 0) {
237
+ const idx = remaining.findIndex(ready);
238
+ if (idx === -1) {
239
+ // Everything left is on or behind a cycle: report the first spec
240
+ // that is on one.
241
+ const pending = new Set(remaining);
242
+ let culprit = remaining[0];
243
+ let chain = null;
244
+ for (const e of remaining) {
245
+ chain = findCycle(e, depsOf, pending);
246
+ if (chain) {
247
+ culprit = e;
248
+ break;
249
+ }
250
+ }
251
+ vars.push(...remaining);
252
+ return {
253
+ vars,
254
+ cycles: [{ spec: culprit.spec, message: cycleMessage(culprit, chain) }],
255
+ };
256
+ }
257
+ const [e] = remaining.splice(idx, 1);
258
+ done.add(e);
259
+ vars.push(e);
260
+ }
261
+ return { vars, cycles: [] };
262
+ }
263
+
264
+ // Constants depend on other constants only.
265
+ function orderConsts(constEntries) {
266
+ const constNames = new Set(constEntries.flatMap((e) => e.names));
267
+ const ctx = { pkgNames: constNames, funcs: new Map() };
268
+ const owner = new Map();
269
+ for (const e of constEntries) for (const n of e.names) owner.set(n, e);
270
+ const consts = [];
271
+ const state = new Set();
272
+ const visit = (e) => {
273
+ if (state.has(e)) return;
274
+ state.add(e);
275
+ const refs = emptyRefs();
276
+ for (const v of e.spec.value ?? []) collectRefs(v, ctx, refs);
277
+ for (const n of refs.names) if (owner.has(n)) visit(owner.get(n));
278
+ consts.push(e);
279
+ };
280
+ for (const e of constEntries) visit(e);
281
+ return consts;
282
+ }
283
+
284
+ /**
285
+ * @param {object[]} programs parsed (and, for method resolution, checked) files
286
+ * @returns {{ consts: object[], vars: object[], cycles: object[] }}
287
+ * `consts` / `vars`: entries `{ decl, spec, names, program }` in initialisation
288
+ * order; `cycles`: `{ spec, message }` for each initialisation cycle.
289
+ */
290
+ export function orderPackageInits(programs) {
291
+ const decls = collectDecls(programs);
292
+ const depsOf = buildVarDeps(decls);
293
+ const { vars, cycles } = orderVars(decls.varEntries, depsOf);
294
+ return { consts: orderConsts(decls.constEntries), vars, cycles };
295
+ }
296
+
297
+ /**
298
+ * Package-level `var` specs in the order their initialisers must be *typed*:
299
+ * a spec that names another package variable (directly, even inside a func
300
+ * literal) comes after it, since `var a = b + 1; var b = f()` infers `a` from
301
+ * `b`. Declaration order is kept otherwise.
302
+ */
303
+ export function orderVarSpecsForTyping(programs) {
304
+ const entries = [];
305
+ for (const program of programs)
306
+ for (const d of program.decls ?? [])
307
+ if (d.kind === "VarDecl")
308
+ for (const spec of d.decls ?? [])
309
+ entries.push({ program, decl: d, spec });
310
+ const owner = new Map();
311
+ for (const e of entries) for (const n of e.spec.names) owner.set(n, e);
312
+ const ctx = { pkgNames: new Set(owner.keys()), funcs: new Map() };
313
+ const out = [];
314
+ const state = new Set();
315
+ const visit = (e) => {
316
+ if (state.has(e)) return;
317
+ state.add(e);
318
+ if (!e.spec.type) {
319
+ const refs = emptyRefs();
320
+ for (const v of e.spec.value ?? []) collectRefs(v, ctx, refs);
321
+ for (const n of refs.names) {
322
+ const o = owner.get(n);
323
+ if (o && o !== e) visit(o);
324
+ }
325
+ }
326
+ out.push(e);
327
+ };
328
+ for (const e of entries) visit(e);
329
+ return out;
330
+ }