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.
- package/README.md +13 -13
- package/package.json +8 -37
- package/src/backend/js/expressions.js +1341 -148
- package/src/backend/js/fmt-runtime.js +573 -0
- package/src/backend/js/index.js +375 -57
- package/src/backend/js/runtime.js +1460 -133
- package/src/backend/js/statements.js +900 -86
- package/src/backend/js/stdlib/bits.js +87 -14
- package/src/backend/js/stdlib/builder.js +41 -6
- package/src/backend/js/stdlib/bytes.js +253 -7
- package/src/backend/js/stdlib/errors.js +2 -1
- package/src/backend/js/stdlib/fmt.js +349 -10
- package/src/backend/js/stdlib/index.js +8 -3
- package/src/backend/js/stdlib/json.js +247 -52
- package/src/backend/js/stdlib/maps.js +0 -8
- package/src/backend/js/stdlib/math.js +17 -1
- package/src/backend/js/stdlib/simd.js +10 -0
- package/src/backend/js/stdlib/slices.js +36 -6
- package/src/backend/js/stdlib/strconv.js +10 -5
- package/src/backend/js/stdlib/strings.js +83 -4
- package/src/backend/js/stdlib/testing.js +7 -0
- package/src/backend/js/stdlib/time.js +79 -55
- package/src/backend/js/stdlib/unicode.js +1 -1
- package/src/backend/js/stdlib/utf8.js +1 -1
- package/src/backend/js/templ.js +38 -76
- package/src/backend/js/type-info.js +272 -0
- package/src/backend/shared/fmt-types.js +188 -0
- package/src/backend/wasm/boundary.js +436 -80
- package/src/backend/wasm/emit-builtins.js +303 -13
- package/src/backend/wasm/emit-exprs.js +1397 -203
- package/src/backend/wasm/emit-maps.js +61 -13
- package/src/backend/wasm/emit-stmts.js +1359 -164
- package/src/backend/wasm/emit.js +512 -77
- package/src/backend/wasm/encode.js +43 -13
- package/src/backend/wasm/globals.js +452 -0
- package/src/backend/wasm/index.js +194 -2489
- package/src/backend/wasm/method-expr.js +381 -0
- package/src/backend/wasm/module-emitter.js +2240 -0
- package/src/backend/wasm/monomorph.js +62 -4
- package/src/backend/wasm/prescan.js +397 -0
- package/src/backend/wasm/stdlib/bytes.js +1804 -127
- package/src/backend/wasm/stdlib/core.js +1574 -199
- package/src/backend/wasm/stdlib/index.js +0 -5
- package/src/backend/wasm/stdlib/io.js +1567 -150
- package/src/backend/wasm/stdlib/packages.js +2 -0
- package/src/backend/wasm/stdlib/simd.js +293 -28
- package/src/backend/wasm/stdlib/time.js +1041 -12
- package/src/backend/wasm/types.js +200 -15
- package/src/backend/wasm/variadic.js +93 -0
- package/src/backend/wasm/wat.js +47 -20
- package/src/{cli-core.js → cli/cli-core.js} +236 -10
- package/src/{test-runner.js → cli/test-runner.js} +332 -39
- package/src/{vendor.js → cli/vendor.js} +3 -4
- package/src/compiler.js +107 -269
- package/src/index.js +15 -169
- package/src/{lexer.js → lexer/lexer.js} +102 -55
- package/src/{tokens.js → lexer/tokens.js} +1 -0
- package/src/link/sourcemap.js +97 -0
- package/src/link/stdlib.js +515 -0
- package/src/link/wasm.js +294 -0
- package/src/lower/bounds.js +394 -0
- package/src/lower/boxing.js +1 -1
- package/src/lower/captures.js +176 -32
- package/src/lower/index.js +26 -18
- package/src/lower/json-codecs.js +1398 -0
- package/src/lower/ownership.js +22 -1
- package/src/lower/range.js +86 -1
- package/src/lower/reachability.js +132 -0
- package/src/parser/declarations.js +58 -13
- package/src/parser/expressions.js +29 -7
- package/src/parser/index.js +2 -1
- package/src/parser/statements.js +37 -22
- package/src/{templ-parser.js → parser/templ.js} +138 -15
- package/src/parser/types.js +69 -9
- package/src/resolver.js +22 -1
- package/src/typechecker/assignability.js +176 -17
- package/src/typechecker/const-fold.js +356 -0
- package/src/typechecker/constants.js +256 -0
- package/src/typechecker/expressions.js +931 -122
- package/src/typechecker/index.js +459 -67
- package/src/typechecker/init-order.js +330 -0
- package/src/typechecker/resolve.js +451 -56
- package/src/typechecker/statements.js +90 -9
- package/src/typechecker/stdlib/core.js +333 -55
- package/src/typechecker/stdlib/excluded.js +898 -0
- package/src/typechecker/stdlib/extended.js +322 -26
- package/src/typechecker/{stdlib.js → stdlib/index.js} +5 -5
- package/src/typechecker/stdlib/simd.js +65 -15
- package/src/typechecker/termination.js +1 -1
- package/src/typechecker/types.js +149 -25
- package/stdlib/bytes/iter.go +192 -0
- package/stdlib/bytes/search.go +240 -0
- package/stdlib/bytes/split.go +218 -0
- package/stdlib/cmp/cmp.go +65 -0
- package/stdlib/encoding/json/errors.go +31 -0
- package/stdlib/encoding/json/indent.go +71 -0
- package/stdlib/encoding/json/number.go +12 -0
- package/stdlib/encoding/json/stream.go +173 -0
- package/stdlib/errors/overlay.go +12 -0
- package/stdlib/hash/hash.go +53 -0
- package/stdlib/internal/jsonrt/dec.go +738 -0
- package/stdlib/internal/jsonrt/enc.go +366 -0
- package/stdlib/internal/jsonrt/indent.go +135 -0
- package/stdlib/internal/jsonrt/number.go +27 -0
- package/stdlib/internal/jsonrt/reader.go +73 -0
- package/stdlib/internal/jsonrt/scanner.go +649 -0
- package/stdlib/io/io.go +346 -0
- package/stdlib/iter/iter.go +18 -0
- package/stdlib/maps/iter.go +65 -0
- package/stdlib/math/extra.go +270 -0
- package/stdlib/slices/extra.go +73 -0
- package/stdlib/slices/iter.go +113 -0
- package/stdlib/sort/sort.go +561 -0
- package/stdlib/strconv/quote.go +341 -0
- package/stdlib/strings/extra.go +35 -0
- package/stdlib/strings/iter.go +122 -0
- package/stdlib/sync/extra.go +105 -0
- package/stdlib/unicode/unicode.go +112 -0
- package/stdlib/unicode/utf8/bytes.go +239 -0
- package/src/backend/wasm/const-fold.js +0 -205
- package/src/backend/wasm/emit-stdlib.js +0 -13
- /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
- /package/src/{colors.js → cli/colors.js} +0 -0
- /package/src/{dev-server.js → cli/dev-server.js} +0 -0
- /package/src/{minifier.js → cli/minifier.js} +0 -0
- /package/src/{project-config.js → cli/project-config.js} +0 -0
- /package/src/{pwa.js → cli/pwa.js} +0 -0
- /package/src/{templ-lexer.js → lexer/templ-lexer.js} +0 -0
package/src/lower/captures.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// are mutated and thus require heap-allocated environment cells for WASM closures.
|
|
4
4
|
|
|
5
5
|
import { collectMutatedVars } from "./ownership.js";
|
|
6
|
+
import { getOrCreateIteratorFuncLit, isIteratorRangeFor } from "./range.js";
|
|
6
7
|
import { forEachChild } from "./walk.js";
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -40,7 +41,7 @@ export function collectDeclaredNames(node, names = new Set()) {
|
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
// Do not descend into nested functions when collecting local declarations
|
|
43
|
-
if (node.kind === "FuncLit") return names;
|
|
44
|
+
if (node.kind === "FuncLit" || isIteratorRangeFor(node)) return names;
|
|
44
45
|
|
|
45
46
|
forEachChild(node, (child) => collectDeclaredNames(child, names));
|
|
46
47
|
return names;
|
|
@@ -92,6 +93,53 @@ function collectReferencedNames(node, localDecls, refs = new Set()) {
|
|
|
92
93
|
return refs;
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
function hasReturnInNode(n) {
|
|
97
|
+
let found = false;
|
|
98
|
+
const check = (x) => {
|
|
99
|
+
if (!x || typeof x !== "object" || found) return;
|
|
100
|
+
if (Array.isArray(x)) {
|
|
101
|
+
for (const elem of x) check(elem);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (x.kind === "ReturnStmt") {
|
|
105
|
+
found = true;
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (x.kind === "FuncLit" && !x._isYieldClosure) return;
|
|
109
|
+
for (const k of Object.keys(x)) {
|
|
110
|
+
if (k.startsWith("_")) continue;
|
|
111
|
+
check(x[k]);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
check(n);
|
|
115
|
+
return found;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function hasIteratorWithReturn(body) {
|
|
119
|
+
let found = false;
|
|
120
|
+
const check = (x) => {
|
|
121
|
+
if (!x || typeof x !== "object" || found) return;
|
|
122
|
+
if (Array.isArray(x)) {
|
|
123
|
+
for (const elem of x) check(elem);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (x.kind === "FuncLit") return;
|
|
127
|
+
if (isIteratorRangeFor(x)) {
|
|
128
|
+
const lit = getOrCreateIteratorFuncLit(x);
|
|
129
|
+
if (hasReturnInNode(lit?.body)) {
|
|
130
|
+
found = true;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
for (const k of Object.keys(x)) {
|
|
135
|
+
if (k.startsWith("_")) continue;
|
|
136
|
+
check(x[k]);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
check(body);
|
|
140
|
+
return found;
|
|
141
|
+
}
|
|
142
|
+
|
|
95
143
|
/**
|
|
96
144
|
* Analyzes a function or method declaration for closures and their captured variables.
|
|
97
145
|
* @param {Object} fnDecl AST FuncDecl or FuncLit node
|
|
@@ -101,6 +149,26 @@ export function analyzeCaptures(fnDecl) {
|
|
|
101
149
|
const result = new CaptureAnalysis();
|
|
102
150
|
if (!fnDecl?.body) return result;
|
|
103
151
|
|
|
152
|
+
// Synthesize named returns if not already present, so iterator returns can share boxed slots
|
|
153
|
+
if (
|
|
154
|
+
fnDecl.returnType &&
|
|
155
|
+
!fnDecl.returnType._namedReturns &&
|
|
156
|
+
hasIteratorWithReturn(fnDecl.body)
|
|
157
|
+
) {
|
|
158
|
+
const ret = fnDecl.returnType;
|
|
159
|
+
if (ret.name !== "void") {
|
|
160
|
+
const types =
|
|
161
|
+
ret.kind === "TupleType" || ret.kind === "tuple" ? ret.types : [ret];
|
|
162
|
+
if (types && types.length > 0) {
|
|
163
|
+
fnDecl.returnType._namedReturns = types.map((t, i) => ({
|
|
164
|
+
name: `__retVal$${i}`,
|
|
165
|
+
type: { ...t, _namedReturns: undefined },
|
|
166
|
+
_synthesized: true,
|
|
167
|
+
}));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
104
172
|
// Collect parameters, receiver and named returns of the root function
|
|
105
173
|
const rootScope = new Set();
|
|
106
174
|
if (fnDecl.recvName && fnDecl.recvName !== "_") {
|
|
@@ -117,46 +185,87 @@ export function analyzeCaptures(fnDecl) {
|
|
|
117
185
|
// Fast pre-collected set of all mutated variables in the entire function
|
|
118
186
|
const mutatedVars = collectMutatedVars(fnDecl.body);
|
|
119
187
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return;
|
|
188
|
+
const handleIteratorRange = (node, scopeStack) => {
|
|
189
|
+
const funcLit = getOrCreateIteratorFuncLit(node);
|
|
190
|
+
if (node._iterStateName) {
|
|
191
|
+
rootScope.add(node._iterStateName);
|
|
192
|
+
result.mutatedCaptures.add(node._iterStateName);
|
|
126
193
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
for (const
|
|
131
|
-
if (
|
|
194
|
+
const rootNamed = fnDecl.returnType?._namedReturns ?? [];
|
|
195
|
+
const hasRet = hasReturnInNode(funcLit.body);
|
|
196
|
+
if (hasRet && rootNamed.length > 0) {
|
|
197
|
+
for (const r of rootNamed) {
|
|
198
|
+
if (r.name && r.name !== "_") {
|
|
199
|
+
rootScope.add(r.name);
|
|
200
|
+
result.mutatedCaptures.add(r.name);
|
|
201
|
+
}
|
|
132
202
|
}
|
|
133
|
-
|
|
134
|
-
|
|
203
|
+
}
|
|
204
|
+
walkClosures(funcLit, scopeStack);
|
|
205
|
+
// A func literal ranged over directly is a closure of its own.
|
|
206
|
+
walkClosures(node.cond?.expr ?? node.init?.rhs?.[0]?.expr, scopeStack);
|
|
207
|
+
const captured = result.capturesByClosure.get(funcLit) ?? new Set();
|
|
208
|
+
if (node._iterStateName) {
|
|
209
|
+
captured.add(node._iterStateName);
|
|
210
|
+
}
|
|
211
|
+
if (hasRet && rootNamed.length > 0) {
|
|
212
|
+
for (const r of rootNamed) {
|
|
213
|
+
if (r.name && r.name !== "_") {
|
|
214
|
+
captured.add(r.name);
|
|
215
|
+
}
|
|
135
216
|
}
|
|
136
|
-
|
|
217
|
+
}
|
|
218
|
+
result.capturesByClosure.set(funcLit, captured);
|
|
219
|
+
};
|
|
137
220
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
221
|
+
const handleFuncLit = (node, scopeStack) => {
|
|
222
|
+
const closureLocals = new Set();
|
|
223
|
+
for (const p of node.params ?? []) {
|
|
224
|
+
if (p.name && p.name !== "_") closureLocals.add(p.name);
|
|
225
|
+
}
|
|
226
|
+
for (const r of node.returnType?._namedReturns ?? []) {
|
|
227
|
+
if (r.name && r.name !== "_") closureLocals.add(r.name);
|
|
228
|
+
}
|
|
229
|
+
collectDeclaredNames(node.body, closureLocals);
|
|
143
230
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
for (const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
231
|
+
const allOuterScope = new Set();
|
|
232
|
+
for (const scope of scopeStack) {
|
|
233
|
+
for (const name of scope) allOuterScope.add(name);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const allRefs = collectReferencedNames(node.body, closureLocals);
|
|
237
|
+
const captured = new Set();
|
|
238
|
+
for (const ref of allRefs) {
|
|
239
|
+
if (allOuterScope.has(ref)) {
|
|
240
|
+
captured.add(ref);
|
|
150
241
|
}
|
|
151
|
-
|
|
242
|
+
}
|
|
243
|
+
result.capturesByClosure.set(node, captured);
|
|
152
244
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
245
|
+
for (const varName of captured) {
|
|
246
|
+
if (mutatedVars.has(varName)) {
|
|
247
|
+
result.mutatedCaptures.add(varName);
|
|
157
248
|
}
|
|
249
|
+
}
|
|
158
250
|
|
|
159
|
-
|
|
251
|
+
walkClosures(node.body, [...scopeStack, closureLocals]);
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
// Traverse closures with lexical scope stack to properly handle arbitrary nesting
|
|
255
|
+
const walkClosures = (node, scopeStack) => {
|
|
256
|
+
if (!node || typeof node !== "object") return;
|
|
257
|
+
if (Array.isArray(node)) {
|
|
258
|
+
for (const item of node) walkClosures(item, scopeStack);
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (isIteratorRangeFor(node)) {
|
|
263
|
+
handleIteratorRange(node, scopeStack);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (node.kind === "FuncLit") {
|
|
268
|
+
handleFuncLit(node, scopeStack);
|
|
160
269
|
return;
|
|
161
270
|
}
|
|
162
271
|
|
|
@@ -166,3 +275,38 @@ export function analyzeCaptures(fnDecl) {
|
|
|
166
275
|
walkClosures(fnDecl.body, [rootScope]);
|
|
167
276
|
return result;
|
|
168
277
|
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Go 1.22 per-iteration loop variables: the names declared by a three-clause
|
|
281
|
+
* `for` init (`for i := …`) that a closure inside the loop (body, cond or
|
|
282
|
+
* post) refers to, or whose address is taken there (`&i`, `&p.X`): a pointer
|
|
283
|
+
* from one iteration must keep pointing at that iteration's variable.
|
|
284
|
+
* Conservative by name. Only these need a fresh copy per iteration; the
|
|
285
|
+
* others stay plain locals.
|
|
286
|
+
*/
|
|
287
|
+
export function loopVarsCapturedInLoop(stmt) {
|
|
288
|
+
const out = new Set();
|
|
289
|
+
if (stmt?.init?.kind !== "DefineStmt") return out;
|
|
290
|
+
const names = new Set(
|
|
291
|
+
(stmt.init.lhs ?? [])
|
|
292
|
+
.filter((l) => l.kind === "Ident" && l.name !== "_")
|
|
293
|
+
.map((l) => l.name),
|
|
294
|
+
);
|
|
295
|
+
if (names.size === 0) return out;
|
|
296
|
+
const walk = (node, inClosure) => {
|
|
297
|
+
if (!node || typeof node !== "object") return;
|
|
298
|
+
if (Array.isArray(node)) {
|
|
299
|
+
for (const n of node) walk(n, inClosure);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if (inClosure && node.kind === "Ident" && names.has(node.name))
|
|
303
|
+
out.add(node.name);
|
|
304
|
+
const nowIn = inClosure || node.kind === "FuncLit";
|
|
305
|
+
forEachChild(node, (child) => walk(child, nowIn));
|
|
306
|
+
};
|
|
307
|
+
const loop = [stmt.cond, stmt.post, stmt.body];
|
|
308
|
+
walk(loop, false);
|
|
309
|
+
for (const name of collectMutatedVars(loop, new Set(), true))
|
|
310
|
+
if (names.has(name)) out.add(name);
|
|
311
|
+
return out;
|
|
312
|
+
}
|
package/src/lower/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/lower/index.js
|
|
2
2
|
// Lowering step: analyzes AST and types to populate side-tables for backends (JS and WASM).
|
|
3
3
|
|
|
4
|
+
export * from "./bounds.js";
|
|
4
5
|
export * from "./boxing.js";
|
|
5
6
|
export * from "./captures.js";
|
|
6
7
|
export * from "./embedding.js";
|
|
@@ -42,6 +43,30 @@ class LowerResult {
|
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Runs the per-function analyses for `d` and records them in `res`. Also
|
|
48
|
+
* used for synthesized functions (the package-level initializer).
|
|
49
|
+
*/
|
|
50
|
+
export function lowerFunction(res, d) {
|
|
51
|
+
if (!d.body) return;
|
|
52
|
+
const boxed = scanAddressTaken(d.body, new Set());
|
|
53
|
+
res.boxedVars.set(d, boxed);
|
|
54
|
+
res.ownership.set(d, new OwnershipContext(d.body));
|
|
55
|
+
res.functions.set(d, {
|
|
56
|
+
hasDefer: hasDefer(d.body),
|
|
57
|
+
namedReturns: extractNamedReturns(d),
|
|
58
|
+
});
|
|
59
|
+
res.captures.set(d, analyzeCaptures(d));
|
|
60
|
+
|
|
61
|
+
const escapingParams = new Set();
|
|
62
|
+
for (const p of d.params ?? []) {
|
|
63
|
+
if (p.name && p.name !== "_" && paramEscapes(d.body, p.name)) {
|
|
64
|
+
escapingParams.add(p.name);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
res.escapes.set(d, escapingParams);
|
|
68
|
+
}
|
|
69
|
+
|
|
45
70
|
/**
|
|
46
71
|
* Runs lowering analyses across an AST or collection of programs, returning side-tables.
|
|
47
72
|
* @param {Object} programOrPrograms
|
|
@@ -74,24 +99,7 @@ export function lower(programOrPrograms, checker = null) {
|
|
|
74
99
|
|
|
75
100
|
for (const d of program.decls) {
|
|
76
101
|
if (d.kind === "FuncDecl" || d.kind === "MethodDecl") {
|
|
77
|
-
|
|
78
|
-
const boxed = scanAddressTaken(d.body, new Set());
|
|
79
|
-
res.boxedVars.set(d, boxed);
|
|
80
|
-
res.ownership.set(d, new OwnershipContext(d.body));
|
|
81
|
-
res.functions.set(d, {
|
|
82
|
-
hasDefer: hasDefer(d.body),
|
|
83
|
-
namedReturns: extractNamedReturns(d),
|
|
84
|
-
});
|
|
85
|
-
res.captures.set(d, analyzeCaptures(d));
|
|
86
|
-
|
|
87
|
-
const escapingParams = new Set();
|
|
88
|
-
for (const p of d.params ?? []) {
|
|
89
|
-
if (p.name && p.name !== "_" && paramEscapes(d.body, p.name)) {
|
|
90
|
-
escapingParams.add(p.name);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
res.escapes.set(d, escapingParams);
|
|
94
|
-
}
|
|
102
|
+
lowerFunction(res, d);
|
|
95
103
|
}
|
|
96
104
|
}
|
|
97
105
|
|