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,392 @@
1
+ // src/backend/wasm/method-expr.js
2
+ // Method expressions (`T.M`, `(*T).M`) and method values (`x.M`) in WASM.
3
+ // A call through a method expression, `(*T).M(p, a)`, becomes the ordinary
4
+ // method call `p.M(a)`. Any other use becomes a func literal that forwards
5
+ // to the method, `func(recv *T, a0 A) R { return recv.M(a0) }`, which the
6
+ // closure lifting then emits like any other func value. A method value
7
+ // binds its receiver when it is evaluated (copying a value receiver, taking
8
+ // the address of an addressable one for a pointer receiver):
9
+ // `func(recv$ *T) func(A) R { return func(a0 A) R { return recv$.M(a0) } }(&x)`. Runs after monomorphisation, so the
10
+ // receiver and method types are concrete, on the WASM pipeline's own copy of
11
+ // the programs.
12
+
13
+ import { typeToTypeNode as toNode } from "./monomorph.js";
14
+
15
+ // Func types stay semantic types: `typeToTypeNode` has no func form and
16
+ // would turn them into `any`.
17
+ function typeToTypeNode(t) {
18
+ return t?.kind === "func" ? t : toNode(t);
19
+ }
20
+
21
+ function isVoid(t) {
22
+ return !t || (t.kind === "basic" && t.name === "void");
23
+ }
24
+
25
+ function returnTypeNode(t) {
26
+ if (isVoid(t)) return null;
27
+ if (t.kind === "tuple")
28
+ return { kind: "TupleType", types: t.types.map(typeToTypeNode) };
29
+ return typeToTypeNode(t);
30
+ }
31
+
32
+ function ident(name, type, at) {
33
+ return { kind: "Ident", name, _type: type, _line: at._line, _col: at._col };
34
+ }
35
+
36
+ // `recv.M(args)` for the method expression `sel` (type `func(recv, …)`).
37
+ function methodCall(sel, recvExpr, args, fnType) {
38
+ const result = fnType.returns?.[0];
39
+ return {
40
+ kind: "CallExpr",
41
+ func: {
42
+ kind: "SelectorExpr",
43
+ expr: recvExpr,
44
+ field: sel.field,
45
+ _type: {
46
+ kind: "func",
47
+ params: fnType.params.slice(1),
48
+ returns: fnType.returns,
49
+ variadic: fnType.variadic,
50
+ },
51
+ _line: sel._line,
52
+ _col: sel._col,
53
+ },
54
+ args,
55
+ _type: isVoid(result) ? { kind: "basic", name: "void" } : result,
56
+ _line: sel._line,
57
+ _col: sel._col,
58
+ };
59
+ }
60
+
61
+ // Each method value's outer literal gets its own receiver name: captures are
62
+ // resolved by name, so two method values of different receiver types in one
63
+ // function must not share `recv$`.
64
+ let recvCounter = 0;
65
+ let bundled = null;
66
+
67
+ function forwardingFuncLit(sel, recvName = "recv$") {
68
+ const fnType = sel._type;
69
+ const [recvType, ...paramTypes] = fnType.params;
70
+ const params = [
71
+ { name: recvName, type: typeToTypeNode(recvType) },
72
+ ...paramTypes.map((t, i) => ({
73
+ name: `a$${i}`,
74
+ type: typeToTypeNode(t),
75
+ variadic: fnType.variadic && i === paramTypes.length - 1,
76
+ })),
77
+ ];
78
+ const args = paramTypes.map((t, i) => {
79
+ const a = ident(`a$${i}`, t, sel);
80
+ if (fnType.variadic && i === paramTypes.length - 1) a._spread = true;
81
+ return a;
82
+ });
83
+ const call = methodCall(sel, ident(recvName, recvType, sel), args, fnType);
84
+ const result = fnType.returns?.[0];
85
+ const stmts = isVoid(result)
86
+ ? [{ kind: "ExprStmt", expr: call }]
87
+ : [{ kind: "ReturnStmt", values: [call] }];
88
+ return {
89
+ kind: "FuncLit",
90
+ params,
91
+ returnType: returnTypeNode(result),
92
+ body: { kind: "Block", stmts },
93
+ _type: fnType,
94
+ _line: sel._line,
95
+ _col: sel._col,
96
+ };
97
+ }
98
+
99
+ function isInterfaceRecv(t) {
100
+ return (t?.underlying ?? t)?.kind === "interface";
101
+ }
102
+
103
+ function methodValueLit(sel) {
104
+ const fnType = sel._type;
105
+ let recvType = sel.expr._type;
106
+ let recvArg = sel.expr;
107
+ if (fnType._ptrRecv && recvType?.kind !== "pointer") {
108
+ recvType = { kind: "pointer", base: recvType };
109
+ recvArg = {
110
+ kind: "UnaryExpr",
111
+ op: "&",
112
+ operand: sel.expr,
113
+ _type: recvType,
114
+ _line: sel._line,
115
+ _col: sel._col,
116
+ };
117
+ } else if (sel._derefRecv && recvType?.kind === "pointer") {
118
+ // `p.M` with a value receiver binds a copy of `*p` now.
119
+ recvType = recvType.base;
120
+ recvArg = {
121
+ kind: "UnaryExpr",
122
+ op: "*",
123
+ operand: sel.expr,
124
+ _type: recvType,
125
+ _line: sel._line,
126
+ _col: sel._col,
127
+ };
128
+ }
129
+ const params = fnType.params ?? [];
130
+ const recvName = `recv$${recvCounter++}`;
131
+ const inner = forwardingFuncLit(
132
+ {
133
+ ...sel,
134
+ _type: { ...fnType, params: [recvType, ...params] },
135
+ },
136
+ recvName,
137
+ );
138
+ // The receiver is the outer parameter; the inner literal takes the rest.
139
+ inner.params = inner.params.slice(1);
140
+ inner._type = fnType;
141
+ const outerType = { kind: "func", params: [recvType], returns: [fnType] };
142
+ return {
143
+ kind: "CallExpr",
144
+ func: {
145
+ kind: "FuncLit",
146
+ params: [{ name: recvName, type: typeToTypeNode(recvType) }],
147
+ returnType: typeToTypeNode(fnType),
148
+ body: {
149
+ kind: "Block",
150
+ stmts: [
151
+ // A method value on a nil interface panics when it is
152
+ // evaluated, not when it is called.
153
+ ...(isInterfaceRecv(recvType)
154
+ ? [{ kind: "NilCheckStmt", expr: ident(recvName, recvType, sel) }]
155
+ : []),
156
+ { kind: "ReturnStmt", values: [inner] },
157
+ ],
158
+ },
159
+ _type: outerType,
160
+ _line: sel._line,
161
+ _col: sel._col,
162
+ },
163
+ args: [recvArg],
164
+ _type: fnType,
165
+ _line: sel._line,
166
+ _col: sel._col,
167
+ };
168
+ }
169
+
170
+ // True for a stdlib function used as a value: `pkg.Fn` on an imported
171
+ // package that is not bundled GoFront source (those resolve as plain
172
+ // functions), with a concrete (non-generic) func type.
173
+ function isStdlibFuncValue(node) {
174
+ if (node?.kind !== "SelectorExpr" || node._type?.kind !== "func")
175
+ return false;
176
+ const ns = node.expr;
177
+ if (ns?.kind !== "Ident" || ns._type?.kind !== "namespace") return false;
178
+ return !bundled?.has(ns.name) && !hasTypeParam(node._type);
179
+ }
180
+
181
+ function hasTypeParam(t) {
182
+ const text = JSON.stringify([t.params, t.returns], (k, v) =>
183
+ k.startsWith("_") || k === "underlying" ? undefined : v,
184
+ );
185
+ return text.includes('"typeParam"') || text.includes('"typeparam"');
186
+ }
187
+
188
+ // Largest number of variadic operands a forwarded stdlib function value
189
+ // accepts: stdlib emitters take their operands unpacked, so the forwarder
190
+ // dispatches on the operand count.
191
+ const MAX_FORWARDED_VARIADIC = 8;
192
+
193
+ const INT_TYPE = { kind: "basic", name: "int" };
194
+
195
+ function intLit(n, at) {
196
+ return {
197
+ kind: "BasicLit",
198
+ litKind: "INT",
199
+ value: String(n),
200
+ _type: INT_TYPE,
201
+ _line: at._line,
202
+ _col: at._col,
203
+ };
204
+ }
205
+
206
+ function lineInfo(at) {
207
+ return { _line: at._line, _col: at._col };
208
+ }
209
+
210
+ function typedCall(func, args, type, at) {
211
+ return { kind: "CallExpr", func, args, _type: type, ...lineInfo(at) };
212
+ }
213
+
214
+ // The statements calling `sel(args)` and returning its result.
215
+ function callStmts(sel, args) {
216
+ const result = sel._type.returns?.[0];
217
+ const type = isVoid(result) ? { kind: "basic", name: "void" } : result;
218
+ const call = typedCall(sel, args, type, sel);
219
+ return isVoid(result)
220
+ ? [
221
+ { kind: "ExprStmt", expr: call },
222
+ { kind: "ReturnStmt", values: [] },
223
+ ]
224
+ : [{ kind: "ReturnStmt", values: [call] }];
225
+ }
226
+
227
+ // `if len(rest) == k { return pkg.Fn(fixed..., rest[0..k-1]) }` for one k.
228
+ function operandCountBranch(sel, fixed, rest, elemType, k) {
229
+ const at = sel;
230
+ const elems = Array.from({ length: k }, (_, i) => ({
231
+ kind: "IndexExpr",
232
+ expr: rest,
233
+ index: intLit(i, at),
234
+ _type: elemType,
235
+ ...lineInfo(at),
236
+ }));
237
+ const len = typedCall(ident("len", null, at), [rest], INT_TYPE, at);
238
+ const body = callStmts(sel, [...fixed, ...elems]);
239
+ return {
240
+ kind: "IfStmt",
241
+ init: null,
242
+ cond: {
243
+ kind: "BinaryExpr",
244
+ left: len,
245
+ op: "==",
246
+ right: intLit(k, at),
247
+ _type: { kind: "basic", name: "bool" },
248
+ ...lineInfo(at),
249
+ },
250
+ body: { kind: "Block", stmts: body, list: body },
251
+ elseBody: null,
252
+ };
253
+ }
254
+
255
+ function tooManyOperands(sel) {
256
+ const msg = {
257
+ kind: "BasicLit",
258
+ litKind: "STRING",
259
+ value: `too many arguments in call to ${sel.expr.name}.${sel.field}`,
260
+ _type: { kind: "basic", name: "string" },
261
+ };
262
+ const panic = typedCall(
263
+ ident("panic", null, sel),
264
+ [msg],
265
+ { kind: "basic", name: "void" },
266
+ sel,
267
+ );
268
+ return [{ kind: "ExprStmt", expr: panic }];
269
+ }
270
+
271
+ function variadicDispatch(sel, fixed, elemType) {
272
+ const rest = ident(
273
+ `a$${fixed.length}`,
274
+ { kind: "slice", elem: elemType },
275
+ sel,
276
+ );
277
+ const stmts = [];
278
+ for (let k = 0; k <= MAX_FORWARDED_VARIADIC; k++)
279
+ stmts.push(operandCountBranch(sel, fixed, rest, elemType, k));
280
+ return [...stmts, ...tooManyOperands(sel)];
281
+ }
282
+
283
+ // `func(a0 A, a1 B) R { return pkg.Fn(a0, a1) }` for the stdlib function
284
+ // value `pkg.Fn`. A variadic one dispatches on the operand count:
285
+ // `if len(rest) == 0 { return pkg.Fn(a0) }; if len(rest) == 1 { ... }`.
286
+ function stdlibFuncLit(sel) {
287
+ const fnType = sel._type;
288
+ const ps = fnType.params ?? [];
289
+ const nFixed = fnType.variadic ? ps.length - 1 : ps.length;
290
+ const params = ps.map((t, i) => ({
291
+ name: `a$${i}`,
292
+ type: typeToTypeNode(t),
293
+ variadic: i === nFixed,
294
+ }));
295
+ const fixed = ps.slice(0, nFixed).map((t, i) => ident(`a$${i}`, t, sel));
296
+ const stmts = fnType.variadic
297
+ ? variadicDispatch(sel, fixed, ps[nFixed])
298
+ : callStmts(sel, fixed);
299
+ return {
300
+ kind: "FuncLit",
301
+ params,
302
+ returnType: returnTypeNode(fnType.returns?.[0]),
303
+ body: { kind: "Block", stmts, list: stmts },
304
+ _type: fnType,
305
+ ...lineInfo(sel),
306
+ };
307
+ }
308
+
309
+ function rewrite(node, isCallee) {
310
+ return rewriteMethods(node, isCallee) ?? rewriteStdlibValue(node, isCallee);
311
+ }
312
+
313
+ // The forwarder passes plain operands and returns one value, so a stdlib
314
+ // function that takes a callback or returns several values cannot be one.
315
+ function assertForwardable(sel) {
316
+ const t = sel._type;
317
+ // Stdlib signatures type a callback as `any`, and the forwarder cannot
318
+ // pass an `any` operand to an emitter that expects a slice or function.
319
+ const fixed = t.variadic ? (t.params ?? []).slice(0, -1) : (t.params ?? []);
320
+ const hasCallback = fixed.some(
321
+ (p) => p?.kind === "func" || (p?.kind === "basic" && p.name === "any"),
322
+ );
323
+ if (hasCallback || (t.returns?.length ?? 0) > 1)
324
+ throw new Error(
325
+ `${sel.expr.name}.${sel.field} cannot be used as a value in WASM (it takes a callback or returns several values)`,
326
+ );
327
+ }
328
+
329
+ function rewriteStdlibValue(node, isCallee) {
330
+ if (isCallee || !isStdlibFuncValue(node)) return null;
331
+ assertForwardable(node);
332
+ return stdlibFuncLit(node);
333
+ }
334
+
335
+ function rewriteMethods(node, isCallee) {
336
+ if (node?.kind === "SelectorExpr" && node._isMethodExpr && node._type)
337
+ return forwardingFuncLit(node);
338
+ if (
339
+ node?.kind === "SelectorExpr" &&
340
+ node._isMethodValue &&
341
+ node._type?.kind === "func" &&
342
+ !isCallee
343
+ )
344
+ return methodValueLit(node);
345
+ if (
346
+ node?.kind === "CallExpr" &&
347
+ node.func?.kind === "SelectorExpr" &&
348
+ node.func._isMethodExpr &&
349
+ node.func._type &&
350
+ node.args?.length > 0 &&
351
+ !node._multiForward
352
+ ) {
353
+ const [recv, ...rest] = node.args;
354
+ const call = methodCall(node.func, recv, rest, node.func._type);
355
+ call._type = node._type;
356
+ return call;
357
+ }
358
+ return null;
359
+ }
360
+
361
+ /** Rewrites method expressions in place; true if anything changed. */
362
+ export function desugarMethodExprs(node, bundledPackages = null) {
363
+ recvCounter = 0;
364
+ bundled = bundledPackages;
365
+ return desugar(node);
366
+ }
367
+
368
+ function desugar(node) {
369
+ if (!node || typeof node !== "object") return false;
370
+ let changed = false;
371
+ if (Array.isArray(node)) {
372
+ for (let i = 0; i < node.length; i++) {
373
+ const r = rewrite(node[i]);
374
+ if (r) {
375
+ node[i] = r;
376
+ changed = true;
377
+ }
378
+ changed = desugar(node[i]) || changed;
379
+ }
380
+ return changed;
381
+ }
382
+ for (const key of Object.keys(node)) {
383
+ if (key.charCodeAt(0) === 95) continue; // "_" side tables
384
+ const r = rewrite(node[key], node.kind === "CallExpr" && key === "func");
385
+ if (r) {
386
+ node[key] = r;
387
+ changed = true;
388
+ }
389
+ changed = desugar(node[key]) || changed;
390
+ }
391
+ return changed;
392
+ }