gofront 1.6.0 → 1.6.1

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 (68) hide show
  1. package/package.json +1 -1
  2. package/src/backend/js/expressions.js +238 -109
  3. package/src/backend/js/index.js +38 -1
  4. package/src/backend/js/runtime.js +953 -53
  5. package/src/backend/js/statements.js +55 -67
  6. package/src/backend/js/stdlib/base64.js +12 -0
  7. package/src/backend/js/stdlib/binary.js +102 -0
  8. package/src/backend/js/stdlib/bits.js +15 -1
  9. package/src/backend/js/stdlib/builder.js +28 -9
  10. package/src/backend/js/stdlib/bytes.js +75 -18
  11. package/src/backend/js/stdlib/errors.js +20 -1
  12. package/src/backend/js/stdlib/fmt.js +70 -13
  13. package/src/backend/js/stdlib/hex.js +17 -0
  14. package/src/backend/js/stdlib/html.js +1 -1
  15. package/src/backend/js/stdlib/index.js +16 -0
  16. package/src/backend/js/stdlib/io.js +105 -3
  17. package/src/backend/js/stdlib/math.js +13 -1
  18. package/src/backend/js/stdlib/path.js +18 -4
  19. package/src/backend/js/stdlib/rand.js +10 -5
  20. package/src/backend/js/stdlib/sha256.js +12 -0
  21. package/src/backend/js/stdlib/slices.js +52 -26
  22. package/src/backend/js/stdlib/strconv.js +21 -5
  23. package/src/backend/js/stdlib/strings.js +148 -15
  24. package/src/backend/js/stdlib/sync.js +13 -0
  25. package/src/backend/js/stdlib/time.js +90 -19
  26. package/src/backend/js/stdlib/unicode.js +2 -2
  27. package/src/backend/wasm/boundary.js +1207 -41
  28. package/src/backend/wasm/const-fold.js +205 -0
  29. package/src/backend/wasm/emit-builtins.js +203 -76
  30. package/src/backend/wasm/emit-exprs.js +464 -276
  31. package/src/backend/wasm/emit-maps.js +144 -8
  32. package/src/backend/wasm/emit-stdlib.js +12 -3005
  33. package/src/backend/wasm/emit-stmts.js +264 -270
  34. package/src/backend/wasm/emit.js +115 -87
  35. package/src/backend/wasm/encode.js +55 -29
  36. package/src/backend/wasm/index.js +1001 -32
  37. package/src/backend/wasm/optimize.js +13 -4
  38. package/src/backend/wasm/stdlib/bytes.js +5039 -0
  39. package/src/backend/wasm/stdlib/core.js +8903 -0
  40. package/src/backend/wasm/stdlib/index.js +40 -0
  41. package/src/backend/wasm/stdlib/io.js +2161 -0
  42. package/src/backend/wasm/stdlib/packages.js +2400 -0
  43. package/src/backend/wasm/stdlib/pure.js +720 -0
  44. package/src/backend/wasm/stdlib/time.js +1200 -0
  45. package/src/backend/wasm/types.js +153 -1
  46. package/src/cli-core.js +1 -1
  47. package/src/compiler.js +18 -4
  48. package/src/dts-parser.js +79 -126
  49. package/src/index.js +2 -6
  50. package/src/lexer.js +80 -29
  51. package/src/lower/boxing.js +1 -2
  52. package/src/lower/captures.js +2 -6
  53. package/src/lower/ownership.js +30 -9
  54. package/src/minifier.js +20 -68
  55. package/src/parser/declarations.js +3 -6
  56. package/src/parser/expressions.js +3 -8
  57. package/src/parser/index.js +18 -3
  58. package/src/parser/statements.js +25 -38
  59. package/src/parser/types.js +1 -2
  60. package/src/resolver.js +2 -27
  61. package/src/templ-lexer.js +29 -63
  62. package/src/templ-parser.js +22 -45
  63. package/src/typechecker/assignability.js +81 -13
  64. package/src/typechecker/expressions.js +102 -2
  65. package/src/typechecker/resolve.js +36 -6
  66. package/src/typechecker/stdlib/core.js +280 -89
  67. package/src/typechecker/stdlib/extended.js +453 -1
  68. package/src/typechecker/types.js +344 -6
@@ -0,0 +1,2161 @@
1
+ // src/backend/wasm/stdlib/io.js
2
+ // FunctionEmitter mixin: io, readers/writers, fmt.Fprint*, fmt.Sscan*.
3
+
4
+ import { toWasmType } from "../types.js";
5
+
6
+ export class IoEmitter {
7
+ _isIoConst(expr) {
8
+ return (
9
+ this._isPkgExpr(expr, "io") &&
10
+ (expr.field === "EOF" || expr.field === "Discard")
11
+ );
12
+ }
13
+
14
+ emitIoConst(field, _targetWasmType) {
15
+ if (field === "EOF") {
16
+ this._emitLazyErrorGlobal(this.mod.getIoErrGlobalIndex("EOF"), "EOF");
17
+ return;
18
+ }
19
+ if (field === "Discard") {
20
+ const gIdx = this.mod.getIoDiscardGlobalIndex();
21
+ const discardInfo = this.mod.getStructType("io.discard");
22
+ this.pushInstruction({ op: "global.get", index: gIdx });
23
+ this.pushInstruction("ref.is_null");
24
+ this.pushInstruction({ op: "if", blockType: "void" });
25
+ if (discardInfo) {
26
+ this.pushInstruction({
27
+ op: "struct.new",
28
+ typeIndex: discardInfo.typeIndex,
29
+ });
30
+ } else {
31
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
32
+ }
33
+ this.pushInstruction({ op: "global.set", index: gIdx });
34
+ this.pushInstruction("end");
35
+ this.pushInstruction({ op: "global.get", index: gIdx });
36
+ return;
37
+ }
38
+ throw new Error(`Unsupported io constant: ${field}`);
39
+ }
40
+
41
+ emitIoCall(name, call, targetWasmType) {
42
+ if (name === "WriteString") {
43
+ this._emitIoWriteString(call, targetWasmType);
44
+ return;
45
+ }
46
+ if (name === "ReadAll") {
47
+ this._emitIoReadAll(call, targetWasmType);
48
+ return;
49
+ }
50
+ if (name === "LimitReader") {
51
+ this._emitIoLimitReader(call, targetWasmType);
52
+ return;
53
+ }
54
+ if (name === "Copy") {
55
+ this._emitIoCopy(call, targetWasmType);
56
+ return;
57
+ }
58
+ if (name === "CopyN") {
59
+ this._emitIoCopyN(call, targetWasmType);
60
+ return;
61
+ }
62
+ throw new Error(`Unsupported io call: ${name}`);
63
+ }
64
+
65
+ _emitIoWriteString(call, _targetWasmType) {
66
+ const wExpr = call.args[0];
67
+ const strExpr = call.args[1];
68
+ const strTmp = this.acquireTemp("externref");
69
+ this.emitExpr(strExpr, "externref");
70
+ this.pushInstruction({ op: "local.set", index: strTmp });
71
+ this._emitWriterWrite(wExpr, strTmp);
72
+ this.releaseTemp(strTmp, "externref");
73
+ }
74
+
75
+ _emitWriterWrite(wExpr, strTmp) {
76
+ const wType = wExpr._type ?? this._resolveExprGoType(wExpr);
77
+ const targetName =
78
+ wType?.name ?? (wType?.kind === "pointer" ? wType.base?.name : null);
79
+ if (targetName === "strings.Builder") {
80
+ const builderInfo = this.mod.getStructType("strings.Builder");
81
+ const builderW = {
82
+ kind: "ref",
83
+ nullable: true,
84
+ typeIndex: builderInfo.typeIndex,
85
+ };
86
+ const bTmp = this.acquireTemp(builderW);
87
+ this.emitExpr(wExpr, builderW);
88
+ this.pushInstruction({ op: "local.set", index: bTmp });
89
+ this._emitBuilderWriteStringCore(bTmp, strTmp);
90
+ this.releaseTemp(bTmp, builderW);
91
+ return;
92
+ }
93
+ if (targetName === "bytes.Buffer") {
94
+ const bufInfo = this.mod.getStructType("bytes.Buffer");
95
+ const bufW = {
96
+ kind: "ref",
97
+ nullable: true,
98
+ typeIndex: bufInfo.typeIndex,
99
+ };
100
+ const bTmp = this.acquireTemp(bufW);
101
+ this.emitExpr(wExpr, bufW);
102
+ this.pushInstruction({ op: "local.set", index: bTmp });
103
+ this._emitBufferWriteStringCore(bTmp, strTmp);
104
+ this.releaseTemp(bTmp, bufW);
105
+ return;
106
+ }
107
+
108
+ const wTmp = this.acquireTemp("anyref");
109
+ this.emitExpr(wExpr, "anyref");
110
+ this.pushInstruction({ op: "local.set", index: wTmp });
111
+
112
+ this.pushInstruction({ op: "local.get", index: wTmp });
113
+ this.pushInstruction({ op: "local.get", index: strTmp });
114
+ this._emitStringToByteSlice({ elem: { kind: "basic", name: "byte" } });
115
+
116
+ const dispatchIdx = this.mod.resolveFuncIndex("__dispatch_io.Writer_Write");
117
+ if (dispatchIdx !== null) {
118
+ this.pushInstruction({ op: "call", funcIndex: dispatchIdx });
119
+ } else {
120
+ this.pushInstruction({ op: "i64.const", value: 0n });
121
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
122
+ }
123
+ this.releaseTemp(wTmp, "anyref");
124
+ }
125
+
126
+ _emitIoReadAll(call, _targetWasmType) {
127
+ const rExpr = call.args[0];
128
+ const rTmp = this.acquireTemp("anyref");
129
+ this.emitExpr(rExpr, "anyref");
130
+ this.pushInstruction({ op: "local.set", index: rTmp });
131
+
132
+ const byteElemGo = { kind: "basic", name: "byte" };
133
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
134
+ const arrInfo = sliceInfo.arrInfo;
135
+ const sliceW = {
136
+ kind: "ref",
137
+ nullable: true,
138
+ typeIndex: sliceInfo.typeIndex,
139
+ };
140
+ const arrW = { kind: "ref", nullable: true, typeIndex: arrInfo.typeIndex };
141
+
142
+ // chunks slice (len: 0, cap: 512)
143
+ const chunksTmp = this.acquireTemp(sliceW);
144
+ this.pushInstruction({ op: "i32.const", value: 512 });
145
+ this.pushInstruction({
146
+ op: "array.new_default",
147
+ typeIndex: arrInfo.typeIndex,
148
+ });
149
+ this.pushInstruction({ op: "i32.const", value: 0 });
150
+ this.pushInstruction({ op: "i32.const", value: 0 });
151
+ this.pushInstruction({ op: "i32.const", value: 512 });
152
+ this.pushInstruction({
153
+ op: "struct.new",
154
+ typeIndex: sliceInfo.typeIndex,
155
+ });
156
+ this.pushInstruction({ op: "local.set", index: chunksTmp });
157
+
158
+ // buf slice (len: 512, cap: 512)
159
+ const bufTmp = this.acquireTemp(sliceW);
160
+ this.pushInstruction({ op: "i32.const", value: 512 });
161
+ this.pushInstruction({
162
+ op: "array.new_default",
163
+ typeIndex: arrInfo.typeIndex,
164
+ });
165
+ this.pushInstruction({ op: "i32.const", value: 0 });
166
+ this.pushInstruction({ op: "i32.const", value: 512 });
167
+ this.pushInstruction({ op: "i32.const", value: 512 });
168
+ this.pushInstruction({
169
+ op: "struct.new",
170
+ typeIndex: sliceInfo.typeIndex,
171
+ });
172
+ this.pushInstruction({ op: "local.set", index: bufTmp });
173
+
174
+ const errTmp = this.acquireTemp("anyref");
175
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
176
+ this.pushInstruction({ op: "local.set", index: errTmp });
177
+
178
+ const dispatchIdx = this.mod.resolveFuncIndex("__dispatch_io.Reader_Read");
179
+
180
+ this.pushInstruction({ op: "block", blockType: "void" });
181
+ this.pushInstruction({ op: "loop", blockType: "void" });
182
+
183
+ this.pushInstruction({ op: "local.get", index: rTmp });
184
+ this.pushInstruction({ op: "local.get", index: bufTmp });
185
+ if (dispatchIdx !== null) {
186
+ this.pushInstruction({ op: "call", funcIndex: dispatchIdx });
187
+ } else {
188
+ this.pushInstruction({ op: "i64.const", value: 0n });
189
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
190
+ }
191
+
192
+ // (n: i64, e: anyref)
193
+ this.pushInstruction({ op: "local.set", index: errTmp });
194
+ const nTmp = this.acquireTemp("i32");
195
+ this.pushInstruction("i32.wrap_i64");
196
+ this.pushInstruction({ op: "local.set", index: nTmp });
197
+
198
+ // if n > 0, append buf[0:n] to chunks
199
+ this.pushInstruction({ op: "local.get", index: nTmp });
200
+ this.pushInstruction({ op: "i32.const", value: 0 });
201
+ this.pushInstruction("i32.gt_s");
202
+ this.pushInstruction({ op: "if", blockType: "void" });
203
+ this._emitAppendSliceBytes(chunksTmp, bufTmp, nTmp, sliceInfo, arrW);
204
+ this.pushInstruction("end");
205
+ this.releaseTemp(nTmp, "i32");
206
+
207
+ // if err != nil: if errors.Is(err, io.EOF) err = nil; break loop
208
+ this.pushInstruction({ op: "local.get", index: errTmp });
209
+ this.pushInstruction("ref.is_null");
210
+ this.pushInstruction("i32.eqz");
211
+ this.pushInstruction({ op: "if", blockType: "void" });
212
+ this.pushInstruction({ op: "local.get", index: errTmp });
213
+ this.emitIoConst("EOF", "anyref");
214
+ this.pushInstruction({
215
+ op: "call",
216
+ funcIndex: this.mod.resolveFuncIndex("__errors_is"),
217
+ });
218
+ this.pushInstruction({ op: "if", blockType: "void" });
219
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
220
+ this.pushInstruction({ op: "local.set", index: errTmp });
221
+ this.pushInstruction("end");
222
+ this.pushInstruction({ op: "br", depth: 2 });
223
+ this.pushInstruction("end");
224
+
225
+ this.pushInstruction({ op: "br", depth: 0 });
226
+ this.pushInstruction("end");
227
+ this.pushInstruction("end");
228
+
229
+ this.pushInstruction({ op: "local.get", index: chunksTmp });
230
+ this.pushInstruction({ op: "local.get", index: errTmp });
231
+
232
+ this.releaseTemp(errTmp, "anyref");
233
+ this.releaseTemp(bufTmp, sliceW);
234
+ this.releaseTemp(chunksTmp, sliceW);
235
+ this.releaseTemp(rTmp, "anyref");
236
+ }
237
+
238
+ _emitIoLimitReader(call, _targetWasmType) {
239
+ const lrInfo = this.mod.getStructType("io.LimitedReader");
240
+ if (!lrInfo) {
241
+ throw new Error("io.LimitedReader struct type not found");
242
+ }
243
+ this.emitExpr(call.args[0], "anyref");
244
+ this.emitExpr(call.args[1], "i64");
245
+ this.pushInstruction({
246
+ op: "struct.new",
247
+ typeIndex: lrInfo.typeIndex,
248
+ });
249
+ }
250
+
251
+ _emitIoCopy(call, _targetWasmType) {
252
+ const dstTmp = this.acquireTemp("anyref");
253
+ const srcTmp = this.acquireTemp("anyref");
254
+ this.emitExpr(call.args[0], "anyref");
255
+ this.pushInstruction({ op: "local.set", index: dstTmp });
256
+ this.emitExpr(call.args[1], "anyref");
257
+ this.pushInstruction({ op: "local.set", index: srcTmp });
258
+
259
+ this._emitIoCopyCore(dstTmp, srcTmp);
260
+
261
+ this.releaseTemp(srcTmp, "anyref");
262
+ this.releaseTemp(dstTmp, "anyref");
263
+ }
264
+
265
+ _emitIoCopyN(call, _targetWasmType) {
266
+ const lrInfo = this.mod.getStructType("io.LimitedReader");
267
+ if (!lrInfo) {
268
+ throw new Error("io.LimitedReader struct type not found");
269
+ }
270
+ const dstTmp = this.acquireTemp("anyref");
271
+ const srcTmp = this.acquireTemp("anyref");
272
+ const nTmp = this.acquireTemp("i64");
273
+ this.emitExpr(call.args[0], "anyref");
274
+ this.pushInstruction({ op: "local.set", index: dstTmp });
275
+ this.emitExpr(call.args[1], "anyref");
276
+ this.pushInstruction({ op: "local.set", index: srcTmp });
277
+ this.emitExpr(call.args[2], "i64");
278
+ this.pushInstruction({ op: "local.set", index: nTmp });
279
+
280
+ const lrW = {
281
+ kind: "ref",
282
+ nullable: true,
283
+ typeIndex: lrInfo.typeIndex,
284
+ };
285
+ const lrTmp = this.acquireTemp(lrW);
286
+ this.pushInstruction({ op: "local.get", index: srcTmp });
287
+ this.pushInstruction({ op: "local.get", index: nTmp });
288
+ this.pushInstruction({
289
+ op: "struct.new",
290
+ typeIndex: lrInfo.typeIndex,
291
+ });
292
+ this.pushInstruction({ op: "local.set", index: lrTmp });
293
+
294
+ this._emitIoCopyCore(dstTmp, lrTmp);
295
+
296
+ const resErrTmp = this.acquireTemp("anyref");
297
+ const writtenTmp = this.acquireTemp("i64");
298
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
299
+ this.pushInstruction({ op: "local.set", index: writtenTmp });
300
+
301
+ // if written == n: err = nil
302
+ this.pushInstruction({ op: "local.get", index: writtenTmp });
303
+ this.pushInstruction({ op: "local.get", index: nTmp });
304
+ this.pushInstruction("i64.eq");
305
+ this.pushInstruction({ op: "if", blockType: "void" });
306
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
307
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
308
+ this.pushInstruction("else");
309
+ // if written < n && resErr == nil: resErr = io.EOF
310
+ this.pushInstruction({ op: "local.get", index: writtenTmp });
311
+ this.pushInstruction({ op: "local.get", index: nTmp });
312
+ this.pushInstruction("i64.lt_s");
313
+ this.pushInstruction({ op: "local.get", index: resErrTmp });
314
+ this.pushInstruction("ref.is_null");
315
+ this.pushInstruction("i32.and");
316
+ this.pushInstruction({ op: "if", blockType: "void" });
317
+ this.emitIoConst("EOF", "anyref");
318
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
319
+ this.pushInstruction("end");
320
+ this.pushInstruction("end");
321
+
322
+ this.pushInstruction({ op: "local.get", index: writtenTmp });
323
+ this.pushInstruction({ op: "local.get", index: resErrTmp });
324
+
325
+ this.releaseTemp(writtenTmp, "i64");
326
+ this.releaseTemp(resErrTmp, "anyref");
327
+ this.releaseTemp(lrTmp, lrW);
328
+ this.releaseTemp(nTmp, "i64");
329
+ this.releaseTemp(srcTmp, "anyref");
330
+ this.releaseTemp(dstTmp, "anyref");
331
+ }
332
+
333
+ _emitIoCopyCore(dstTmp, srcTmp) {
334
+ const byteElemGo = { kind: "basic", name: "byte" };
335
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
336
+ const arrInfo = sliceInfo.arrInfo;
337
+ const sliceW = {
338
+ kind: "ref",
339
+ nullable: true,
340
+ typeIndex: sliceInfo.typeIndex,
341
+ };
342
+ const arrW = { kind: "ref", nullable: true, typeIndex: arrInfo.typeIndex };
343
+
344
+ // Buffer: 32KB
345
+ const bufSize = 32768;
346
+ const bufArrTmp = this.acquireTemp(arrW);
347
+ this.pushInstruction({ op: "i32.const", value: bufSize });
348
+ this.pushInstruction({
349
+ op: "array.new_default",
350
+ typeIndex: arrInfo.typeIndex,
351
+ });
352
+ this.pushInstruction({ op: "local.set", index: bufArrTmp });
353
+
354
+ const bufTmp = this.acquireTemp(sliceW);
355
+ this.pushInstruction({ op: "local.get", index: bufArrTmp });
356
+ this.pushInstruction({ op: "i32.const", value: 0 });
357
+ this.pushInstruction({ op: "i32.const", value: bufSize });
358
+ this.pushInstruction({ op: "i32.const", value: bufSize });
359
+ this.pushInstruction({
360
+ op: "struct.new",
361
+ typeIndex: sliceInfo.typeIndex,
362
+ });
363
+ this.pushInstruction({ op: "local.set", index: bufTmp });
364
+
365
+ const totalWrittenTmp = this.acquireTemp("i64");
366
+ this.pushInstruction({ op: "i64.const", value: 0n });
367
+ this.pushInstruction({ op: "local.set", index: totalWrittenTmp });
368
+
369
+ const errTmp = this.acquireTemp("anyref");
370
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
371
+ this.pushInstruction({ op: "local.set", index: errTmp });
372
+
373
+ const readErrTmp = this.acquireTemp("anyref");
374
+ const nrI32Tmp = this.acquireTemp("i32");
375
+ const subsliceTmp = this.acquireTemp(sliceW);
376
+ const writeErrTmp = this.acquireTemp("anyref");
377
+ const nwTmp = this.acquireTemp("i64");
378
+
379
+ const dispatchReadIdx = this.mod.resolveFuncIndex(
380
+ "__dispatch_io.Reader_Read",
381
+ );
382
+ const dispatchWriteIdx = this.mod.resolveFuncIndex(
383
+ "__dispatch_io.Writer_Write",
384
+ );
385
+
386
+ this.pushInstruction({ op: "block", blockType: "void" });
387
+ this.pushInstruction({ op: "loop", blockType: "void" });
388
+
389
+ // Read: src.Read(buf)
390
+ this.pushInstruction({ op: "local.get", index: srcTmp });
391
+ this.pushInstruction({ op: "local.get", index: bufTmp });
392
+ if (dispatchReadIdx !== null) {
393
+ this.pushInstruction({ op: "call", funcIndex: dispatchReadIdx });
394
+ } else {
395
+ this.pushInstruction({ op: "i64.const", value: 0n });
396
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
397
+ }
398
+ this.pushInstruction({ op: "local.set", index: readErrTmp });
399
+ this.pushInstruction("i32.wrap_i64");
400
+ this.pushInstruction({ op: "local.set", index: nrI32Tmp });
401
+
402
+ // if nr > 0: write
403
+ this.pushInstruction({ op: "local.get", index: nrI32Tmp });
404
+ this.pushInstruction({ op: "i32.const", value: 0 });
405
+ this.pushInstruction("i32.gt_s");
406
+ this.pushInstruction({ op: "if", blockType: "void" });
407
+
408
+ // subslice = slice(bufArrTmp, 0, nrI32Tmp, nrI32Tmp)
409
+ this.pushInstruction({ op: "local.get", index: bufArrTmp });
410
+ this.pushInstruction({ op: "i32.const", value: 0 });
411
+ this.pushInstruction({ op: "local.get", index: nrI32Tmp });
412
+ this.pushInstruction({ op: "local.get", index: nrI32Tmp });
413
+ this.pushInstruction({
414
+ op: "struct.new",
415
+ typeIndex: sliceInfo.typeIndex,
416
+ });
417
+ this.pushInstruction({ op: "local.set", index: subsliceTmp });
418
+
419
+ // dst.Write(subslice)
420
+ this.pushInstruction({ op: "local.get", index: dstTmp });
421
+ this.pushInstruction({ op: "local.get", index: subsliceTmp });
422
+ if (dispatchWriteIdx !== null) {
423
+ this.pushInstruction({ op: "call", funcIndex: dispatchWriteIdx });
424
+ } else {
425
+ this.pushInstruction({ op: "i64.const", value: 0n });
426
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
427
+ }
428
+ this.pushInstruction({ op: "local.set", index: writeErrTmp });
429
+ this.pushInstruction({ op: "local.set", index: nwTmp });
430
+
431
+ // totalWritten += nw
432
+ this.pushInstruction({ op: "local.get", index: nwTmp });
433
+ this.pushInstruction({ op: "i64.const", value: 0n });
434
+ this.pushInstruction("i64.gt_s");
435
+ this.pushInstruction({ op: "if", blockType: "void" });
436
+ this.pushInstruction({ op: "local.get", index: totalWrittenTmp });
437
+ this.pushInstruction({ op: "local.get", index: nwTmp });
438
+ this.pushInstruction("i64.add");
439
+ this.pushInstruction({ op: "local.set", index: totalWrittenTmp });
440
+ this.pushInstruction("end");
441
+
442
+ // if writeErr != nil: err = writeErr; br 2 (break loop)
443
+ this.pushInstruction({ op: "local.get", index: writeErrTmp });
444
+ this.pushInstruction("ref.is_null");
445
+ this.pushInstruction("i32.eqz");
446
+ this.pushInstruction({ op: "if", blockType: "void" });
447
+ this.pushInstruction({ op: "local.get", index: writeErrTmp });
448
+ this.pushInstruction({ op: "local.set", index: errTmp });
449
+ this.pushInstruction({ op: "br", depth: 2 });
450
+ this.pushInstruction("end");
451
+
452
+ this.pushInstruction("end"); // end if nr > 0
453
+
454
+ // if readErr != nil:
455
+ this.pushInstruction({ op: "local.get", index: readErrTmp });
456
+ this.pushInstruction("ref.is_null");
457
+ this.pushInstruction("i32.eqz");
458
+ this.pushInstruction({ op: "if", blockType: "void" });
459
+ this.pushInstruction({ op: "local.get", index: readErrTmp });
460
+ this.emitIoConst("EOF", "anyref");
461
+ this.pushInstruction({
462
+ op: "call",
463
+ funcIndex: this.mod.resolveFuncIndex("__errors_is"),
464
+ });
465
+ this.pushInstruction({ op: "if", blockType: "void" });
466
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
467
+ this.pushInstruction({ op: "local.set", index: errTmp });
468
+ this.pushInstruction("else");
469
+ this.pushInstruction({ op: "local.get", index: readErrTmp });
470
+ this.pushInstruction({ op: "local.set", index: errTmp });
471
+ this.pushInstruction("end");
472
+ this.pushInstruction({ op: "br", depth: 2 }); // break loop
473
+ this.pushInstruction("end"); // end if readErr != nil
474
+
475
+ this.pushInstruction({ op: "br", depth: 0 }); // continue
476
+ this.pushInstruction("end"); // end loop
477
+ this.pushInstruction("end"); // end block
478
+
479
+ this.pushInstruction({ op: "local.get", index: totalWrittenTmp });
480
+ this.pushInstruction({ op: "local.get", index: errTmp });
481
+
482
+ this.releaseTemp(nwTmp, "i64");
483
+ this.releaseTemp(writeErrTmp, "anyref");
484
+ this.releaseTemp(subsliceTmp, sliceW);
485
+ this.releaseTemp(nrI32Tmp, "i32");
486
+ this.releaseTemp(readErrTmp, "anyref");
487
+ this.releaseTemp(errTmp, "anyref");
488
+ this.releaseTemp(totalWrittenTmp, "i64");
489
+ this.releaseTemp(bufTmp, sliceW);
490
+ this.releaseTemp(bufArrTmp, arrW);
491
+ }
492
+
493
+ _emitAppendSliceBytes(dstSliceTmp, srcSliceTmp, countTmp, sliceInfo, arrW) {
494
+ const arrInfo = sliceInfo.arrInfo;
495
+ const byteGo = { kind: "basic", name: "byte" };
496
+
497
+ const oldArrTmp = this.acquireTemp(arrW);
498
+ const oldOffTmp = this.acquireTemp("i32");
499
+ const oldLenTmp = this.acquireTemp("i32");
500
+ const oldCapTmp = this.acquireTemp("i32");
501
+ this._emitSliceUnpack(dstSliceTmp, sliceInfo, {
502
+ arr: oldArrTmp,
503
+ off: oldOffTmp,
504
+ len: oldLenTmp,
505
+ cap: oldCapTmp,
506
+ });
507
+
508
+ const newLenTmp = this.acquireTemp("i32");
509
+ this.pushInstruction({ op: "local.get", index: oldLenTmp });
510
+ this.pushInstruction({ op: "local.get", index: countTmp });
511
+ this.pushInstruction("i32.add");
512
+ this.pushInstruction({ op: "local.set", index: newLenTmp });
513
+
514
+ const newArrTmp = this.acquireTemp(arrW);
515
+ const newOffTmp = this.acquireTemp("i32");
516
+ const newCapTmp = this.acquireTemp("i32");
517
+ this._emitGrowSlice({
518
+ arrInfo,
519
+ elemGoType: byteGo,
520
+ oldArrTmp,
521
+ oldOffTmp,
522
+ oldLenTmp,
523
+ oldCapTmp,
524
+ newArrTmp,
525
+ newOffTmp,
526
+ newLenTmp,
527
+ newCapTmp,
528
+ });
529
+
530
+ const srcArrTmp = this.acquireTemp(arrW);
531
+ const srcOffTmp = this.acquireTemp("i32");
532
+ const srcLenTmp = this.acquireTemp("i32");
533
+ const srcCapTmp = this.acquireTemp("i32");
534
+ this._emitSliceUnpack(srcSliceTmp, sliceInfo, {
535
+ arr: srcArrTmp,
536
+ off: srcOffTmp,
537
+ len: srcLenTmp,
538
+ cap: srcCapTmp,
539
+ });
540
+ this.releaseTemp(srcCapTmp, "i32");
541
+ this.releaseTemp(srcLenTmp, "i32");
542
+
543
+ this.pushInstruction({ op: "local.get", index: newArrTmp });
544
+ this.pushInstruction({ op: "local.get", index: newOffTmp });
545
+ this.pushInstruction({ op: "local.get", index: oldLenTmp });
546
+ this.pushInstruction("i32.add");
547
+ this.pushInstruction({ op: "local.get", index: srcArrTmp });
548
+ this.pushInstruction({ op: "local.get", index: srcOffTmp });
549
+ this.pushInstruction({ op: "local.get", index: countTmp });
550
+ this._emitArrayCopy(arrInfo, byteGo);
551
+
552
+ this.releaseTemp(srcOffTmp, "i32");
553
+ this.releaseTemp(srcArrTmp, arrW);
554
+
555
+ this.pushInstruction({ op: "local.get", index: newArrTmp });
556
+ this.pushInstruction({ op: "local.get", index: newOffTmp });
557
+ this.pushInstruction({ op: "local.get", index: newLenTmp });
558
+ this.pushInstruction({ op: "local.get", index: newCapTmp });
559
+ this.pushInstruction({
560
+ op: "struct.new",
561
+ typeIndex: sliceInfo.typeIndex,
562
+ });
563
+ this.pushInstruction({ op: "local.set", index: dstSliceTmp });
564
+
565
+ this.releaseTemp(newCapTmp, "i32");
566
+ this.releaseTemp(newOffTmp, "i32");
567
+ this.releaseTemp(newArrTmp, arrW);
568
+ this.releaseTemp(newLenTmp, "i32");
569
+ this.releaseTemp(oldCapTmp, "i32");
570
+ this.releaseTemp(oldLenTmp, "i32");
571
+ this.releaseTemp(oldOffTmp, "i32");
572
+ this.releaseTemp(oldArrTmp, arrW);
573
+ }
574
+
575
+ emitStringsNewReader(call, _targetWasmType) {
576
+ const structInfo = this.mod.getStructType("strings.Reader");
577
+ this.emitExpr(call.args[0], "externref");
578
+ this._emitStringToByteSlice({ elem: { kind: "basic", name: "byte" } });
579
+ this.pushInstruction({ op: "i64.const", value: 0n });
580
+ this.pushInstruction({
581
+ op: "struct.new",
582
+ typeIndex: structInfo.typeIndex,
583
+ });
584
+ }
585
+
586
+ emitBytesNewReader(call, _targetWasmType) {
587
+ const structInfo = this.mod.getStructType("bytes.Reader");
588
+ const byteElemGo = { kind: "basic", name: "byte" };
589
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
590
+ const sliceW = {
591
+ kind: "ref",
592
+ nullable: true,
593
+ typeIndex: sliceInfo.typeIndex,
594
+ };
595
+ this.emitExpr(call.args[0], sliceW);
596
+ this.pushInstruction({ op: "i64.const", value: 0n });
597
+ this.pushInstruction({
598
+ op: "struct.new",
599
+ typeIndex: structInfo.typeIndex,
600
+ });
601
+ }
602
+
603
+ emitStringsReaderMethodCall(method, expr, args, targetWasmType) {
604
+ if (method === "Read") {
605
+ this._emitStringsReaderRead(expr, args);
606
+ return;
607
+ }
608
+ if (method === "Len") {
609
+ this._emitStringsReaderLen(expr, targetWasmType);
610
+ return;
611
+ }
612
+ if (method === "Reset") {
613
+ this._emitStringsReaderReset(expr, args);
614
+ return;
615
+ }
616
+ throw new Error(`Unsupported strings.Reader method: ${method}`);
617
+ }
618
+
619
+ _emitStringsReaderRead(expr, args) {
620
+ const structInfo = this.mod.getStructType("strings.Reader");
621
+ const readerW = {
622
+ kind: "ref",
623
+ nullable: true,
624
+ typeIndex: structInfo.typeIndex,
625
+ };
626
+ const rTmp = this.acquireTemp(readerW);
627
+ this.emitExpr(expr, readerW);
628
+ this.pushInstruction({ op: "local.set", index: rTmp });
629
+
630
+ const byteElemGo = { kind: "basic", name: "byte" };
631
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
632
+ const sliceW = {
633
+ kind: "ref",
634
+ nullable: true,
635
+ typeIndex: sliceInfo.typeIndex,
636
+ };
637
+ const pTmp = this.acquireTemp(sliceW);
638
+ this.emitExpr(args[0], sliceW);
639
+ this.pushInstruction({ op: "local.set", index: pTmp });
640
+
641
+ this._emitStringsReaderReadCore(rTmp, pTmp);
642
+ this.releaseTemp(pTmp, sliceW);
643
+ this.releaseTemp(rTmp, readerW);
644
+ }
645
+
646
+ _emitReaderReadCore(typeName, rTmp, pTmp) {
647
+ const structInfo = this.mod.getStructType(typeName);
648
+ const byteElemGo = { kind: "basic", name: "byte" };
649
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
650
+ const arrW = {
651
+ kind: "ref",
652
+ nullable: true,
653
+ typeIndex: sliceInfo.arrInfo.typeIndex,
654
+ };
655
+
656
+ const pArrTmp = this.acquireTemp(arrW);
657
+ const pOffTmp = this.acquireTemp("i32");
658
+ const pLenTmp = this.acquireTemp("i32");
659
+ const pCapTmp = this.acquireTemp("i32");
660
+ this._emitSliceUnpack(pTmp, sliceInfo, {
661
+ arr: pArrTmp,
662
+ off: pOffTmp,
663
+ len: pLenTmp,
664
+ cap: pCapTmp,
665
+ });
666
+ this.releaseTemp(pCapTmp, "i32");
667
+
668
+ const resNTmp = this.acquireTemp("i64");
669
+ const resErrTmp = this.acquireTemp("anyref");
670
+
671
+ // if p.len == 0: (0, nil)
672
+ this.pushInstruction({ op: "local.get", index: pLenTmp });
673
+ this.pushInstruction("i32.eqz");
674
+ this.pushInstruction({ op: "if", blockType: "void" });
675
+ this.pushInstruction({ op: "i64.const", value: 0n });
676
+ this.pushInstruction({ op: "local.set", index: resNTmp });
677
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
678
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
679
+ this.pushInstruction("else");
680
+
681
+ const srcSliceW = {
682
+ kind: "ref",
683
+ nullable: true,
684
+ typeIndex: sliceInfo.typeIndex,
685
+ };
686
+ const srcSliceTmp = this.acquireTemp(srcSliceW);
687
+ this.pushInstruction({ op: "local.get", index: rTmp });
688
+ this.pushInstruction({
689
+ op: "struct.get",
690
+ typeIndex: structInfo.typeIndex,
691
+ fieldIndex: 0,
692
+ });
693
+ this.pushInstruction({ op: "local.set", index: srcSliceTmp });
694
+
695
+ const srcArrTmp = this.acquireTemp(arrW);
696
+ const srcOffTmp = this.acquireTemp("i32");
697
+ const srcLenTmp = this.acquireTemp("i32");
698
+ const srcCapTmp = this.acquireTemp("i32");
699
+ this._emitSliceUnpack(srcSliceTmp, sliceInfo, {
700
+ arr: srcArrTmp,
701
+ off: srcOffTmp,
702
+ len: srcLenTmp,
703
+ cap: srcCapTmp,
704
+ });
705
+ this.releaseTemp(srcCapTmp, "i32");
706
+ this.releaseTemp(srcSliceTmp, srcSliceW);
707
+
708
+ const posTmp = this.acquireTemp("i64");
709
+ this.pushInstruction({ op: "local.get", index: rTmp });
710
+ this.pushInstruction({
711
+ op: "struct.get",
712
+ typeIndex: structInfo.typeIndex,
713
+ fieldIndex: 1,
714
+ });
715
+ this.pushInstruction({ op: "local.set", index: posTmp });
716
+
717
+ // if pos >= srcLen: (0, io.EOF)
718
+ this.pushInstruction({ op: "local.get", index: posTmp });
719
+ this.pushInstruction({ op: "local.get", index: srcLenTmp });
720
+ this.pushInstruction("i64.extend_i32_u");
721
+ this.pushInstruction("i64.ge_s");
722
+ this.pushInstruction({ op: "if", blockType: "void" });
723
+ this.pushInstruction({ op: "i64.const", value: 0n });
724
+ this.pushInstruction({ op: "local.set", index: resNTmp });
725
+ this.emitIoConst("EOF", "anyref");
726
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
727
+ this.pushInstruction("else");
728
+
729
+ // avail = srcLen - pos
730
+ const availTmp = this.acquireTemp("i32");
731
+ this.pushInstruction({ op: "local.get", index: srcLenTmp });
732
+ this.pushInstruction({ op: "local.get", index: posTmp });
733
+ this.pushInstruction("i32.wrap_i64");
734
+ this.pushInstruction("i32.sub");
735
+ this.pushInstruction({ op: "local.set", index: availTmp });
736
+
737
+ // n = min(p.len, avail)
738
+ const nTmp = this.acquireTemp("i32");
739
+ this.pushInstruction({ op: "local.get", index: pLenTmp });
740
+ this.pushInstruction({ op: "local.get", index: availTmp });
741
+ this.pushInstruction("i32.lt_s");
742
+ this.pushInstruction({ op: "if", blockType: "i32" });
743
+ this.pushInstruction({ op: "local.get", index: pLenTmp });
744
+ this.pushInstruction("else");
745
+ this.pushInstruction({ op: "local.get", index: availTmp });
746
+ this.pushInstruction("end");
747
+ this.pushInstruction({ op: "local.set", index: nTmp });
748
+
749
+ // copy bytes: p.arr[p.off] = src.arr[src.off + pos]
750
+ this.pushInstruction({ op: "local.get", index: pArrTmp });
751
+ this.pushInstruction({ op: "local.get", index: pOffTmp });
752
+ this.pushInstruction({ op: "local.get", index: srcArrTmp });
753
+ this.pushInstruction({ op: "local.get", index: srcOffTmp });
754
+ this.pushInstruction({ op: "local.get", index: posTmp });
755
+ this.pushInstruction("i32.wrap_i64");
756
+ this.pushInstruction("i32.add");
757
+ this.pushInstruction({ op: "local.get", index: nTmp });
758
+ this._emitArrayCopy(sliceInfo.arrInfo, byteElemGo);
759
+
760
+ // r._pos += n
761
+ this.pushInstruction({ op: "local.get", index: rTmp });
762
+ this.pushInstruction({ op: "local.get", index: posTmp });
763
+ this.pushInstruction({ op: "local.get", index: nTmp });
764
+ this.pushInstruction("i64.extend_i32_u");
765
+ this.pushInstruction("i64.add");
766
+ this.pushInstruction({
767
+ op: "struct.set",
768
+ typeIndex: structInfo.typeIndex,
769
+ fieldIndex: 1,
770
+ });
771
+
772
+ this.pushInstruction({ op: "local.get", index: nTmp });
773
+ this.pushInstruction("i64.extend_i32_u");
774
+ this.pushInstruction({ op: "local.set", index: resNTmp });
775
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
776
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
777
+
778
+ this.releaseTemp(nTmp, "i32");
779
+ this.releaseTemp(availTmp, "i32");
780
+ this.pushInstruction("end");
781
+ this.releaseTemp(posTmp, "i64");
782
+ this.releaseTemp(srcLenTmp, "i32");
783
+ this.releaseTemp(srcOffTmp, "i32");
784
+ this.releaseTemp(srcArrTmp, arrW);
785
+ this.pushInstruction("end");
786
+
787
+ this.pushInstruction({ op: "local.get", index: resNTmp });
788
+ this.pushInstruction({ op: "local.get", index: resErrTmp });
789
+
790
+ this.releaseTemp(resErrTmp, "anyref");
791
+ this.releaseTemp(resNTmp, "i64");
792
+ this.releaseTemp(pLenTmp, "i32");
793
+ this.releaseTemp(pOffTmp, "i32");
794
+ this.releaseTemp(pArrTmp, arrW);
795
+ }
796
+
797
+ _emitReaderLenCore(typeName, rTmp, targetWasmType) {
798
+ const structInfo = this.mod.getStructType(typeName);
799
+ const byteElemGo = { kind: "basic", name: "byte" };
800
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
801
+
802
+ this.pushInstruction({ op: "local.get", index: rTmp });
803
+ this.pushInstruction({
804
+ op: "struct.get",
805
+ typeIndex: structInfo.typeIndex,
806
+ fieldIndex: 0,
807
+ });
808
+ this.pushInstruction({
809
+ op: "struct.get",
810
+ typeIndex: sliceInfo.typeIndex,
811
+ fieldIndex: 2,
812
+ });
813
+ this.pushInstruction("i64.extend_i32_u");
814
+ this.pushInstruction({ op: "local.get", index: rTmp });
815
+ this.pushInstruction({
816
+ op: "struct.get",
817
+ typeIndex: structInfo.typeIndex,
818
+ fieldIndex: 1,
819
+ });
820
+ this.pushInstruction("i64.sub");
821
+ const resTmp = this.acquireTemp("i64");
822
+ this.pushInstruction({ op: "local.set", index: resTmp });
823
+
824
+ this.pushInstruction({ op: "local.get", index: resTmp });
825
+ this.pushInstruction({ op: "i64.const", value: 0n });
826
+ this.pushInstruction("i64.lt_s");
827
+ this.pushInstruction({ op: "if", blockType: "i64" });
828
+ this.pushInstruction({ op: "i64.const", value: 0n });
829
+ this.pushInstruction("else");
830
+ this.pushInstruction({ op: "local.get", index: resTmp });
831
+ this.pushInstruction("end");
832
+ if ((targetWasmType ?? "i64") === "i32") {
833
+ this.pushInstruction("i32.wrap_i64");
834
+ }
835
+ this.releaseTemp(resTmp, "i64");
836
+ }
837
+
838
+ _emitStringsReaderReadCore(rTmp, pTmp) {
839
+ this._emitReaderReadCore("strings.Reader", rTmp, pTmp);
840
+ }
841
+
842
+ _emitStringsReaderLen(expr, targetWasmType) {
843
+ const structInfo = this.mod.getStructType("strings.Reader");
844
+ const readerW = {
845
+ kind: "ref",
846
+ nullable: true,
847
+ typeIndex: structInfo.typeIndex,
848
+ };
849
+ const rTmp = this.acquireTemp(readerW);
850
+ this.emitExpr(expr, readerW);
851
+ this.pushInstruction({ op: "local.set", index: rTmp });
852
+
853
+ this._emitStringsReaderLenCore(rTmp, targetWasmType);
854
+ this.releaseTemp(rTmp, readerW);
855
+ }
856
+
857
+ _emitStringsReaderLenCore(rTmp, targetWasmType) {
858
+ this._emitReaderLenCore("strings.Reader", rTmp, targetWasmType);
859
+ }
860
+
861
+ _emitStringsReaderReset(expr, args) {
862
+ const structInfo = this.mod.getStructType("strings.Reader");
863
+ const readerW = {
864
+ kind: "ref",
865
+ nullable: true,
866
+ typeIndex: structInfo.typeIndex,
867
+ };
868
+ const rTmp = this.acquireTemp(readerW);
869
+ this.emitExpr(expr, readerW);
870
+ this.pushInstruction({ op: "local.set", index: rTmp });
871
+
872
+ const sTmp = this.acquireTemp("externref");
873
+ this.emitExpr(args[0], "externref");
874
+ this.pushInstruction({ op: "local.set", index: sTmp });
875
+
876
+ this._emitStringsReaderResetCore(rTmp, sTmp);
877
+ this.releaseTemp(sTmp, "externref");
878
+ this.releaseTemp(rTmp, readerW);
879
+ }
880
+
881
+ _emitStringsReaderResetCore(rTmp, sTmp) {
882
+ const structInfo = this.mod.getStructType("strings.Reader");
883
+ this.pushInstruction({ op: "local.get", index: rTmp });
884
+ this.pushInstruction({ op: "local.get", index: sTmp });
885
+ this._emitStringToByteSlice({ elem: { kind: "basic", name: "byte" } });
886
+ this.pushInstruction({
887
+ op: "struct.set",
888
+ typeIndex: structInfo.typeIndex,
889
+ fieldIndex: 0,
890
+ });
891
+ this.pushInstruction({ op: "local.get", index: rTmp });
892
+ this.pushInstruction({ op: "i64.const", value: 0n });
893
+ this.pushInstruction({
894
+ op: "struct.set",
895
+ typeIndex: structInfo.typeIndex,
896
+ fieldIndex: 1,
897
+ });
898
+ }
899
+
900
+ emitBytesReaderMethodCall(method, expr, args, targetWasmType) {
901
+ if (method === "Read") {
902
+ this._emitBytesReaderRead(expr, args);
903
+ return;
904
+ }
905
+ if (method === "Len") {
906
+ this._emitBytesReaderLen(expr, targetWasmType);
907
+ return;
908
+ }
909
+ if (method === "Reset") {
910
+ this._emitBytesReaderReset(expr, args);
911
+ return;
912
+ }
913
+ throw new Error(`Unsupported bytes.Reader method: ${method}`);
914
+ }
915
+
916
+ _emitBytesReaderRead(expr, args) {
917
+ const structInfo = this.mod.getStructType("bytes.Reader");
918
+ const readerW = {
919
+ kind: "ref",
920
+ nullable: true,
921
+ typeIndex: structInfo.typeIndex,
922
+ };
923
+ const rTmp = this.acquireTemp(readerW);
924
+ this.emitExpr(expr, readerW);
925
+ this.pushInstruction({ op: "local.set", index: rTmp });
926
+
927
+ const byteElemGo = { kind: "basic", name: "byte" };
928
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
929
+ const sliceW = {
930
+ kind: "ref",
931
+ nullable: true,
932
+ typeIndex: sliceInfo.typeIndex,
933
+ };
934
+ const pTmp = this.acquireTemp(sliceW);
935
+ this.emitExpr(args[0], sliceW);
936
+ this.pushInstruction({ op: "local.set", index: pTmp });
937
+
938
+ this._emitBytesReaderReadCore(rTmp, pTmp);
939
+ this.releaseTemp(pTmp, sliceW);
940
+ this.releaseTemp(rTmp, readerW);
941
+ }
942
+
943
+ _emitBytesReaderReadCore(rTmp, pTmp) {
944
+ this._emitReaderReadCore("bytes.Reader", rTmp, pTmp);
945
+ }
946
+
947
+ _emitBytesReaderLen(expr, targetWasmType) {
948
+ const structInfo = this.mod.getStructType("bytes.Reader");
949
+ const readerW = {
950
+ kind: "ref",
951
+ nullable: true,
952
+ typeIndex: structInfo.typeIndex,
953
+ };
954
+ const rTmp = this.acquireTemp(readerW);
955
+ this.emitExpr(expr, readerW);
956
+ this.pushInstruction({ op: "local.set", index: rTmp });
957
+
958
+ this._emitBytesReaderLenCore(rTmp, targetWasmType);
959
+ this.releaseTemp(rTmp, readerW);
960
+ }
961
+
962
+ _emitBytesReaderLenCore(rTmp, targetWasmType) {
963
+ this._emitReaderLenCore("bytes.Reader", rTmp, targetWasmType);
964
+ }
965
+
966
+ _emitBytesReaderReset(expr, args) {
967
+ const structInfo = this.mod.getStructType("bytes.Reader");
968
+ const readerW = {
969
+ kind: "ref",
970
+ nullable: true,
971
+ typeIndex: structInfo.typeIndex,
972
+ };
973
+ const rTmp = this.acquireTemp(readerW);
974
+ this.emitExpr(expr, readerW);
975
+ this.pushInstruction({ op: "local.set", index: rTmp });
976
+
977
+ const byteElemGo = { kind: "basic", name: "byte" };
978
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
979
+ const sliceW = {
980
+ kind: "ref",
981
+ nullable: true,
982
+ typeIndex: sliceInfo.typeIndex,
983
+ };
984
+ const bTmp = this.acquireTemp(sliceW);
985
+ this.emitExpr(args[0], sliceW);
986
+ this.pushInstruction({ op: "local.set", index: bTmp });
987
+
988
+ this._emitBytesReaderResetCore(rTmp, bTmp);
989
+ this.releaseTemp(bTmp, sliceW);
990
+ this.releaseTemp(rTmp, readerW);
991
+ }
992
+
993
+ _emitBytesReaderResetCore(rTmp, bTmp) {
994
+ const structInfo = this.mod.getStructType("bytes.Reader");
995
+ this.pushInstruction({ op: "local.get", index: rTmp });
996
+ this.pushInstruction({ op: "local.get", index: bTmp });
997
+ this.pushInstruction({
998
+ op: "struct.set",
999
+ typeIndex: structInfo.typeIndex,
1000
+ fieldIndex: 0,
1001
+ });
1002
+ this.pushInstruction({ op: "local.get", index: rTmp });
1003
+ this.pushInstruction({ op: "i64.const", value: 0n });
1004
+ this.pushInstruction({
1005
+ op: "struct.set",
1006
+ typeIndex: structInfo.typeIndex,
1007
+ fieldIndex: 1,
1008
+ });
1009
+ }
1010
+
1011
+ emitFprintCall(fn, call, _targetWasmType) {
1012
+ const wExpr = call.args[0];
1013
+ const strTmp = this.acquireTemp("externref");
1014
+ this._emitFprintFormatString(fn, call.args.slice(1));
1015
+ this.pushInstruction({ op: "local.set", index: strTmp });
1016
+
1017
+ const wType = wExpr._type;
1018
+ const targetName =
1019
+ wType?.name ?? (wType?.kind === "pointer" ? wType.base?.name : null);
1020
+ if (targetName === "strings.Builder") {
1021
+ // Builder.WriteString
1022
+ const builderInfo = this.mod.getStructType("strings.Builder");
1023
+ const builderW = {
1024
+ kind: "ref",
1025
+ nullable: true,
1026
+ typeIndex: builderInfo.typeIndex,
1027
+ };
1028
+ const bTmp = this.acquireTemp(builderW);
1029
+ this.emitExpr(wExpr, builderW);
1030
+ this.pushInstruction({ op: "local.set", index: bTmp });
1031
+ this._emitBuilderWriteStringCore(bTmp, strTmp);
1032
+ this.releaseTemp(bTmp, builderW);
1033
+ this.releaseTemp(strTmp, "externref");
1034
+ return;
1035
+ }
1036
+ if (targetName === "bytes.Buffer") {
1037
+ const bufInfo = this.mod.getStructType("bytes.Buffer");
1038
+ const bufW = {
1039
+ kind: "ref",
1040
+ nullable: true,
1041
+ typeIndex: bufInfo.typeIndex,
1042
+ };
1043
+ const bTmp = this.acquireTemp(bufW);
1044
+ this.emitExpr(wExpr, bufW);
1045
+ this.pushInstruction({ op: "local.set", index: bTmp });
1046
+ this._emitBufferWriteStringCore(bTmp, strTmp);
1047
+ this.releaseTemp(bTmp, bufW);
1048
+ this.releaseTemp(strTmp, "externref");
1049
+ return;
1050
+ }
1051
+
1052
+ this._emitWriterWrite(wExpr, strTmp);
1053
+ this.releaseTemp(strTmp, "externref");
1054
+ }
1055
+
1056
+ _emitFprintFormatString(fn, restArgs) {
1057
+ if (fn === "Fprintf") {
1058
+ const [format, ...rest] = restArgs;
1059
+ const temps = this._emitArgBuffer(rest);
1060
+ this.emitExpr(format, "externref");
1061
+ this._callStdlib("fmt_sprintf");
1062
+ this._releaseArgBuffer(temps);
1063
+ return;
1064
+ }
1065
+ const argc = restArgs.length;
1066
+ if (argc === 0) {
1067
+ const s = fn === "Fprintln" ? "\n" : "";
1068
+ const strIdx = this.mod.internString(s);
1069
+ this.pushInstruction({ op: "i32.const", value: strIdx });
1070
+ this.pushInstruction({
1071
+ op: "call",
1072
+ funcIndex: this.mod.getStringImportIndex(),
1073
+ });
1074
+ return;
1075
+ }
1076
+ const sep = fn === "Fprintln" ? " " : "";
1077
+ const suffix = fn === "Fprintln" ? "\n" : "";
1078
+ const fmt = Array(argc).fill("%v").join(sep) + suffix;
1079
+ const temps = this._emitArgBuffer(restArgs);
1080
+ const strIdx = this.mod.internString(fmt);
1081
+ this.pushInstruction({ op: "i32.const", value: strIdx });
1082
+ this.pushInstruction({
1083
+ op: "call",
1084
+ funcIndex: this.mod.getStringImportIndex(),
1085
+ });
1086
+ this._callStdlib("fmt_sprintf");
1087
+ this._releaseArgBuffer(temps);
1088
+ }
1089
+
1090
+ emitSscanCall(fn, call, _targetWasmType) {
1091
+ const strArg = call.args[0];
1092
+ const mode = fn === "Sscanln" ? 1 : 0;
1093
+ const ptrs = fn === "Sscanf" ? call.args.slice(2) : call.args.slice(1);
1094
+
1095
+ if (fn === "Sscanf") {
1096
+ this.emitExpr(strArg, "externref");
1097
+ this.emitExpr(call.args[1], "externref");
1098
+ this._callStdlib("fmt_sscanf_init");
1099
+ } else {
1100
+ this.emitExpr(strArg, "externref");
1101
+ this.pushInstruction({ op: "i32.const", value: mode });
1102
+ this._callStdlib("fmt_sscan_init");
1103
+ }
1104
+ const totTokensTmp = this.acquireTemp("i32");
1105
+ this.pushInstruction({ op: "local.set", index: totTokensTmp });
1106
+
1107
+ const nTmp = this.acquireTemp("i64");
1108
+ this.pushInstruction({ op: "i64.const", value: 0n });
1109
+ this.pushInstruction({ op: "local.set", index: nTmp });
1110
+
1111
+ for (let i = 0; i < ptrs.length; i++) {
1112
+ this._emitSscanAssignOne(ptrs[i], i, totTokensTmp, nTmp);
1113
+ }
1114
+
1115
+ // return (n: i64, err: anyref)
1116
+ this.pushInstruction({ op: "local.get", index: nTmp });
1117
+
1118
+ this._callStdlib("fmt_sscan_has_err");
1119
+ this.pushInstruction({ op: "if", blockType: "anyref" });
1120
+ this._callStdlib("fmt_sscan_err_msg");
1121
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1122
+ this.pushInstruction({
1123
+ op: "call",
1124
+ funcIndex: this.mod.resolveFuncIndex("__mk_error"),
1125
+ });
1126
+ this.pushInstruction("else");
1127
+ this.pushInstruction({ op: "local.get", index: nTmp });
1128
+ this.pushInstruction({ op: "i64.const", value: BigInt(ptrs.length) });
1129
+ this.pushInstruction("i64.lt_s");
1130
+ this.pushInstruction({ op: "if", blockType: "anyref" });
1131
+ const strIdx = this.mod.internString("unexpected EOF");
1132
+ this.pushInstruction({ op: "i32.const", value: strIdx });
1133
+ this.pushInstruction({
1134
+ op: "call",
1135
+ funcIndex: this.mod.getStringImportIndex(),
1136
+ });
1137
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1138
+ this.pushInstruction({
1139
+ op: "call",
1140
+ funcIndex: this.mod.resolveFuncIndex("__mk_error"),
1141
+ });
1142
+ this.pushInstruction("else");
1143
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1144
+ this.pushInstruction("end");
1145
+ this.pushInstruction("end");
1146
+
1147
+ this.releaseTemp(nTmp, "i64");
1148
+ this.releaseTemp(totTokensTmp, "i32");
1149
+ }
1150
+
1151
+ _emitSscanAssignOne(pExpr, tokenIdx, totTokensTmp, nTmp) {
1152
+ this.pushInstruction({ op: "i32.const", value: tokenIdx });
1153
+ this.pushInstruction({ op: "local.get", index: totTokensTmp });
1154
+ this.pushInstruction("i32.lt_s");
1155
+ this.pushInstruction({ op: "if", blockType: "void" });
1156
+
1157
+ this._callStdlib("fmt_sscan_has_err");
1158
+ this.pushInstruction({ op: "if", blockType: "void" });
1159
+ this.pushInstruction("else");
1160
+
1161
+ this._emitSscanWriteToken(pExpr, tokenIdx);
1162
+
1163
+ this._callStdlib("fmt_sscan_has_err");
1164
+ this.pushInstruction({ op: "if", blockType: "void" });
1165
+ this.pushInstruction("else");
1166
+ this.pushInstruction({ op: "local.get", index: nTmp });
1167
+ this.pushInstruction({ op: "i64.const", value: 1n });
1168
+ this.pushInstruction("i64.add");
1169
+ this.pushInstruction({ op: "local.set", index: nTmp });
1170
+ this.pushInstruction("end");
1171
+
1172
+ this.pushInstruction("end");
1173
+ this.pushInstruction("end");
1174
+ }
1175
+
1176
+ _emitSscanWriteToken(pExpr, tokenIdx) {
1177
+ const isAddressOf = pExpr.kind === "UnaryExpr" && pExpr.op === "&";
1178
+ const pType =
1179
+ pExpr._type ??
1180
+ (pExpr.kind === "Ident" ? this.resolveLocal(pExpr.name)?.goType : null) ??
1181
+ this._resolveExprGoType(pExpr);
1182
+ const pointeeType = pType?.base ?? pType;
1183
+ const targetNode = isAddressOf
1184
+ ? (pExpr.operand ?? pExpr.expr)
1185
+ : {
1186
+ kind: "UnaryExpr",
1187
+ op: "*",
1188
+ operand: { ...pExpr, _type: pType },
1189
+ _type: pointeeType,
1190
+ };
1191
+ const effectivePointee = targetNode._type ?? pointeeType;
1192
+ const wType = toWasmType(effectivePointee, this.mod.checker, this.mod);
1193
+
1194
+ this._emitAssignToTarget(targetNode, wType, effectivePointee, () => {
1195
+ this._emitSscanTokenValue(wType, effectivePointee, tokenIdx);
1196
+ });
1197
+ }
1198
+
1199
+ _emitSscanTokenValue(wType, pointeeType, tokenIdx) {
1200
+ this.pushInstruction({ op: "i32.const", value: tokenIdx });
1201
+ if (wType === "i64") {
1202
+ this._callStdlib("fmt_sscan_token_i64");
1203
+ return;
1204
+ }
1205
+ if (wType === "i32") {
1206
+ if (pointeeType?.name === "bool") {
1207
+ this._callStdlib("fmt_sscan_token_bool");
1208
+ } else {
1209
+ this._callStdlib("fmt_sscan_token_i64");
1210
+ this.pushInstruction("i32.wrap_i64");
1211
+ }
1212
+ return;
1213
+ }
1214
+ if (wType === "f64") {
1215
+ this._callStdlib("fmt_sscan_token_f64");
1216
+ return;
1217
+ }
1218
+ if (wType === "f32") {
1219
+ this._callStdlib("fmt_sscan_token_f64");
1220
+ this.pushInstruction("f32.demote_f64");
1221
+ return;
1222
+ }
1223
+ if (wType === "externref") {
1224
+ this._callStdlib("fmt_sscan_token_str");
1225
+ return;
1226
+ }
1227
+ this._callStdlib("fmt_sscan_token_str");
1228
+ }
1229
+
1230
+ emitIoHelper(fn) {
1231
+ const kind = fn._isIoHelper ?? fn._isPhase7Helper;
1232
+ switch (kind) {
1233
+ case "builder_write":
1234
+ this._emitHelperBuilderWrite(fn);
1235
+ return;
1236
+ case "builder_write_string":
1237
+ this._emitHelperBuilderWriteString(fn);
1238
+ return;
1239
+ case "buffer_write":
1240
+ this._emitHelperBufferWrite(fn);
1241
+ return;
1242
+ case "buffer_write_string":
1243
+ this._emitHelperBufferWriteString(fn);
1244
+ return;
1245
+ case "buffer_read":
1246
+ this._emitHelperBufferRead(fn);
1247
+ return;
1248
+ case "strings_reader_read":
1249
+ this._emitHelperStringsReaderRead(fn);
1250
+ return;
1251
+ case "strings_reader_len":
1252
+ this._emitHelperStringsReaderLen(fn);
1253
+ return;
1254
+ case "strings_reader_reset":
1255
+ this._emitHelperStringsReaderReset(fn);
1256
+ return;
1257
+ case "bytes_reader_read":
1258
+ this._emitHelperBytesReaderRead(fn);
1259
+ return;
1260
+ case "bytes_reader_len":
1261
+ this._emitHelperBytesReaderLen(fn);
1262
+ return;
1263
+ case "bytes_reader_reset":
1264
+ this._emitHelperBytesReaderReset(fn);
1265
+ return;
1266
+ case "discard_write":
1267
+ this._emitHelperDiscardWrite(fn);
1268
+ return;
1269
+ case "discard_write_string":
1270
+ this._emitHelperDiscardWriteString(fn);
1271
+ return;
1272
+ case "limited_reader_read":
1273
+ this._emitHelperLimitedReaderRead(fn);
1274
+ return;
1275
+ case "sha256_write":
1276
+ this._emitHelperSha256Write(fn);
1277
+ return;
1278
+ case "sha256_sum":
1279
+ this._emitHelperSha256Sum(fn);
1280
+ return;
1281
+ case "sha256_reset":
1282
+ this._emitHelperSha256Reset(fn);
1283
+ return;
1284
+ case "sha256_size":
1285
+ this._emitHelperSha256Size(fn);
1286
+ return;
1287
+ case "sha256_block_size":
1288
+ this._emitHelperSha256BlockSize(fn);
1289
+ return;
1290
+ default:
1291
+ throw new Error(`Unknown io helper: ${kind}`);
1292
+ }
1293
+ }
1294
+
1295
+ emitPhase7Helper(fn) {
1296
+ return this.emitIoHelper(fn);
1297
+ }
1298
+
1299
+ _emitHelperBuilderWrite(_fn) {
1300
+ this._emitBuilderWriteCore(0, 1);
1301
+ this.pushInstruction("return");
1302
+ }
1303
+
1304
+ _emitHelperBuilderWriteString(_fn) {
1305
+ this._emitBuilderWriteStringCore(0, 1);
1306
+ this.pushInstruction("return");
1307
+ }
1308
+
1309
+ _emitBuilderWriteCore(bTmp, pTmp) {
1310
+ const byteElemGo = { kind: "basic", name: "byte" };
1311
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
1312
+ const arrW = {
1313
+ kind: "ref",
1314
+ nullable: true,
1315
+ typeIndex: sliceInfo.arrInfo.typeIndex,
1316
+ };
1317
+
1318
+ const pArrTmp = this.acquireTemp(arrW);
1319
+ const pOffTmp = this.acquireTemp("i32");
1320
+ const pLenTmp = this.acquireTemp("i32");
1321
+ const pCapTmp = this.acquireTemp("i32");
1322
+ this._emitSliceUnpack(pTmp, sliceInfo, {
1323
+ arr: pArrTmp,
1324
+ off: pOffTmp,
1325
+ len: pLenTmp,
1326
+ cap: pCapTmp,
1327
+ });
1328
+ this.releaseTemp(pCapTmp, "i32");
1329
+
1330
+ this.pushInstruction({ op: "local.get", index: pLenTmp });
1331
+ this._callStdlib("bytes_to_str_init");
1332
+
1333
+ const kTmp = this.acquireTemp("i32");
1334
+ this.pushInstruction({ op: "i32.const", value: 0 });
1335
+ this.pushInstruction({ op: "local.set", index: kTmp });
1336
+
1337
+ this.pushInstruction({ op: "block", blockType: "void" });
1338
+ this.pushInstruction({ op: "loop", blockType: "void" });
1339
+ this.pushInstruction({ op: "local.get", index: kTmp });
1340
+ this.pushInstruction({ op: "local.get", index: pLenTmp });
1341
+ this.pushInstruction("i32.ge_s");
1342
+ this.pushInstruction({ op: "br_if", depth: 1 });
1343
+
1344
+ this.pushInstruction({ op: "local.get", index: pArrTmp });
1345
+ this.pushInstruction({ op: "local.get", index: pOffTmp });
1346
+ this.pushInstruction({ op: "local.get", index: kTmp });
1347
+ this.pushInstruction("i32.add");
1348
+ this.pushInstruction({
1349
+ op: "array.get",
1350
+ typeIndex: sliceInfo.arrInfo.typeIndex,
1351
+ });
1352
+ this._callStdlib("bytes_to_str_push");
1353
+
1354
+ this.pushInstruction({ op: "local.get", index: kTmp });
1355
+ this.pushInstruction({ op: "i32.const", value: 1 });
1356
+ this.pushInstruction("i32.add");
1357
+ this.pushInstruction({ op: "local.set", index: kTmp });
1358
+ this.pushInstruction({ op: "br", depth: 0 });
1359
+ this.pushInstruction("end");
1360
+ this.pushInstruction("end");
1361
+
1362
+ this._callStdlib("bytes_to_str_finish");
1363
+ const strTmp = this.acquireTemp("externref");
1364
+ this.pushInstruction({ op: "local.set", index: strTmp });
1365
+
1366
+ this._emitBuilderWriteStringCore(bTmp, strTmp);
1367
+ this.releaseTemp(strTmp, "externref");
1368
+ this.releaseTemp(kTmp, "i32");
1369
+ this.releaseTemp(pLenTmp, "i32");
1370
+ this.releaseTemp(pOffTmp, "i32");
1371
+ this.releaseTemp(pArrTmp, arrW);
1372
+ }
1373
+
1374
+ _emitBuilderWriteStringCore(bTmp, strTmp) {
1375
+ const structInfo = this.mod.getStructType("strings.Builder");
1376
+ const strGo = { kind: "basic", name: "string" };
1377
+ const sliceInfo = this.mod.getSliceType(strGo);
1378
+ const arrInfo = sliceInfo.arrInfo;
1379
+ const sliceW = {
1380
+ kind: "ref",
1381
+ nullable: true,
1382
+ typeIndex: sliceInfo.typeIndex,
1383
+ };
1384
+ const arrW = { kind: "ref", nullable: true, typeIndex: arrInfo.typeIndex };
1385
+
1386
+ const lenTmp = this.acquireTemp("i32");
1387
+ this.pushInstruction({ op: "local.get", index: strTmp });
1388
+ this.pushInstruction({
1389
+ op: "call",
1390
+ funcIndex: this.mod.getStringLenImportIndex(),
1391
+ });
1392
+ this.pushInstruction({ op: "local.set", index: lenTmp });
1393
+
1394
+ // copy check
1395
+ this.pushInstruction({ op: "local.get", index: bTmp });
1396
+ this.pushInstruction({
1397
+ op: "struct.get",
1398
+ typeIndex: structInfo.typeIndex,
1399
+ fieldIndex: 2,
1400
+ });
1401
+ this.pushInstruction("ref.is_null");
1402
+ this.pushInstruction({ op: "if", blockType: "void" });
1403
+ this.pushInstruction({ op: "local.get", index: bTmp });
1404
+ this.pushInstruction({ op: "local.get", index: bTmp });
1405
+ this.pushInstruction({
1406
+ op: "struct.set",
1407
+ typeIndex: structInfo.typeIndex,
1408
+ fieldIndex: 2,
1409
+ });
1410
+ this.pushInstruction("else");
1411
+ this.pushInstruction({ op: "local.get", index: bTmp });
1412
+ this.pushInstruction({
1413
+ op: "struct.get",
1414
+ typeIndex: structInfo.typeIndex,
1415
+ fieldIndex: 2,
1416
+ });
1417
+ this.pushInstruction({ op: "ref.cast", heapType: "eq" });
1418
+ this.pushInstruction({ op: "local.get", index: bTmp });
1419
+ this.pushInstruction("ref.eq");
1420
+ this.pushInstruction("i32.eqz");
1421
+ this.pushInstruction({ op: "if", blockType: "void" });
1422
+ this.emitPanic("strings: illegal use of non-zero Builder copied by value");
1423
+ this.pushInstruction("end");
1424
+ this.pushInstruction("end");
1425
+
1426
+ // append string to b._buf
1427
+ const oldSliceTmp = this.acquireTemp(sliceW);
1428
+ this.pushInstruction({ op: "local.get", index: bTmp });
1429
+ this.pushInstruction({
1430
+ op: "struct.get",
1431
+ typeIndex: structInfo.typeIndex,
1432
+ fieldIndex: 0,
1433
+ });
1434
+ this.pushInstruction({ op: "local.set", index: oldSliceTmp });
1435
+
1436
+ const oldArrTmp = this.acquireTemp(arrW);
1437
+ const oldOffTmp = this.acquireTemp("i32");
1438
+ const oldLenTmp = this.acquireTemp("i32");
1439
+ const oldCapTmp = this.acquireTemp("i32");
1440
+ this._emitSliceUnpack(oldSliceTmp, sliceInfo, {
1441
+ arr: oldArrTmp,
1442
+ off: oldOffTmp,
1443
+ len: oldLenTmp,
1444
+ cap: oldCapTmp,
1445
+ });
1446
+ this.releaseTemp(oldSliceTmp, sliceW);
1447
+
1448
+ const newArrTmp = this.acquireTemp(arrW);
1449
+ const newOffTmp = this.acquireTemp("i32");
1450
+ const newCapTmp = this.acquireTemp("i32");
1451
+ const newLenTmp = this.acquireTemp("i32");
1452
+ this.pushInstruction({ op: "local.get", index: oldLenTmp });
1453
+ this.pushInstruction({ op: "i32.const", value: 1 });
1454
+ this.pushInstruction("i32.add");
1455
+ this.pushInstruction({ op: "local.set", index: newLenTmp });
1456
+
1457
+ this._emitGrowSlice({
1458
+ arrInfo,
1459
+ elemGoType: strGo,
1460
+ oldArrTmp,
1461
+ oldOffTmp,
1462
+ oldLenTmp,
1463
+ oldCapTmp,
1464
+ newArrTmp,
1465
+ newOffTmp,
1466
+ newLenTmp,
1467
+ newCapTmp,
1468
+ });
1469
+
1470
+ this.pushInstruction({ op: "local.get", index: newArrTmp });
1471
+ this.pushInstruction({ op: "local.get", index: newOffTmp });
1472
+ this.pushInstruction({ op: "local.get", index: oldLenTmp });
1473
+ this.pushInstruction("i32.add");
1474
+ this.pushInstruction({ op: "local.get", index: strTmp });
1475
+ this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
1476
+
1477
+ this.pushInstruction({ op: "local.get", index: bTmp });
1478
+ this.pushInstruction({ op: "local.get", index: newArrTmp });
1479
+ this.pushInstruction({ op: "local.get", index: newOffTmp });
1480
+ this.pushInstruction({ op: "local.get", index: newLenTmp });
1481
+ this.pushInstruction({ op: "local.get", index: newCapTmp });
1482
+ this.pushInstruction({
1483
+ op: "struct.new",
1484
+ typeIndex: sliceInfo.typeIndex,
1485
+ });
1486
+ this.pushInstruction({
1487
+ op: "struct.set",
1488
+ typeIndex: structInfo.typeIndex,
1489
+ fieldIndex: 0,
1490
+ });
1491
+
1492
+ this.pushInstruction({ op: "local.get", index: bTmp });
1493
+ this.pushInstruction({ op: "local.get", index: bTmp });
1494
+ this.pushInstruction({
1495
+ op: "struct.get",
1496
+ typeIndex: structInfo.typeIndex,
1497
+ fieldIndex: 1,
1498
+ });
1499
+ this.pushInstruction({ op: "local.get", index: lenTmp });
1500
+ this.pushInstruction("i64.extend_i32_u");
1501
+ this.pushInstruction("i64.add");
1502
+ this.pushInstruction({
1503
+ op: "struct.set",
1504
+ typeIndex: structInfo.typeIndex,
1505
+ fieldIndex: 1,
1506
+ });
1507
+
1508
+ // return (len, nil)
1509
+ this.pushInstruction({ op: "local.get", index: lenTmp });
1510
+ this.pushInstruction("i64.extend_i32_u");
1511
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1512
+
1513
+ this.releaseTemp(newLenTmp, "i32");
1514
+ this.releaseTemp(newCapTmp, "i32");
1515
+ this.releaseTemp(newOffTmp, "i32");
1516
+ this.releaseTemp(newArrTmp, arrW);
1517
+ this.releaseTemp(oldCapTmp, "i32");
1518
+ this.releaseTemp(oldLenTmp, "i32");
1519
+ this.releaseTemp(oldOffTmp, "i32");
1520
+ this.releaseTemp(oldArrTmp, arrW);
1521
+ this.releaseTemp(lenTmp, "i32");
1522
+ }
1523
+
1524
+ _emitHelperBufferWrite(_fn) {
1525
+ this._emitBufferWriteCore(0, 1);
1526
+ this.pushInstruction("return");
1527
+ }
1528
+
1529
+ _emitHelperBufferWriteString(_fn) {
1530
+ this._emitBufferWriteStringCore(0, 1);
1531
+ this.pushInstruction("return");
1532
+ }
1533
+
1534
+ _emitBufferWriteCore(bTmp, pTmp, structName = "bytes.Buffer") {
1535
+ const structInfo = this.mod.getStructType(structName);
1536
+ const byteGo = { kind: "basic", name: "byte" };
1537
+ const sliceInfo = this.mod.getSliceType(byteGo);
1538
+ const sliceW = {
1539
+ kind: "ref",
1540
+ nullable: true,
1541
+ typeIndex: sliceInfo.typeIndex,
1542
+ };
1543
+ const arrW = {
1544
+ kind: "ref",
1545
+ nullable: true,
1546
+ typeIndex: sliceInfo.arrInfo.typeIndex,
1547
+ };
1548
+
1549
+ const bufSliceTmp = this.acquireTemp(sliceW);
1550
+ this.pushInstruction({ op: "local.get", index: bTmp });
1551
+ this.pushInstruction({
1552
+ op: "struct.get",
1553
+ typeIndex: structInfo.typeIndex,
1554
+ fieldIndex: 0,
1555
+ });
1556
+ this.pushInstruction({ op: "local.set", index: bufSliceTmp });
1557
+ this.pushInstruction({ op: "local.get", index: bufSliceTmp });
1558
+ this.pushInstruction("ref.is_null");
1559
+ this.pushInstruction({ op: "if", blockType: "void" });
1560
+ this.pushInstruction({
1561
+ op: "global.get",
1562
+ index: sliceInfo.emptyGlobalIndex,
1563
+ });
1564
+ this.pushInstruction({ op: "local.set", index: bufSliceTmp });
1565
+ this.pushInstruction("end");
1566
+
1567
+ const pArrTmp = this.acquireTemp(arrW);
1568
+ const pOffTmp = this.acquireTemp("i32");
1569
+ const pLenTmp = this.acquireTemp("i32");
1570
+ const pCapTmp = this.acquireTemp("i32");
1571
+ this._emitSliceUnpack(pTmp, sliceInfo, {
1572
+ arr: pArrTmp,
1573
+ off: pOffTmp,
1574
+ len: pLenTmp,
1575
+ cap: pCapTmp,
1576
+ });
1577
+ this.releaseTemp(pCapTmp, "i32");
1578
+
1579
+ this._emitAppendSliceBytes(bufSliceTmp, pTmp, pLenTmp, sliceInfo, arrW);
1580
+
1581
+ this.pushInstruction({ op: "local.get", index: bTmp });
1582
+ this.pushInstruction({ op: "local.get", index: bufSliceTmp });
1583
+ this.pushInstruction({
1584
+ op: "struct.set",
1585
+ typeIndex: structInfo.typeIndex,
1586
+ fieldIndex: 0,
1587
+ });
1588
+
1589
+ this.pushInstruction({ op: "local.get", index: pLenTmp });
1590
+ this.pushInstruction("i64.extend_i32_u");
1591
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1592
+
1593
+ this.releaseTemp(bufSliceTmp, sliceW);
1594
+ this.releaseTemp(pLenTmp, "i32");
1595
+ this.releaseTemp(pOffTmp, "i32");
1596
+ this.releaseTemp(pArrTmp, arrW);
1597
+ }
1598
+
1599
+ _emitBufferWriteStringCore(bTmp, strTmp) {
1600
+ const sliceW = {
1601
+ kind: "ref",
1602
+ nullable: true,
1603
+ typeIndex: this.mod.getSliceType({ kind: "basic", name: "byte" })
1604
+ .typeIndex,
1605
+ };
1606
+ const pTmp = this.acquireTemp(sliceW);
1607
+ this.pushInstruction({ op: "local.get", index: strTmp });
1608
+ this._emitStringToByteSlice({ elem: { kind: "basic", name: "byte" } });
1609
+ this.pushInstruction({ op: "local.set", index: pTmp });
1610
+
1611
+ this._emitBufferWriteCore(bTmp, pTmp);
1612
+ this.releaseTemp(pTmp, sliceW);
1613
+ }
1614
+
1615
+ _emitHelperBufferRead(_fn) {
1616
+ this._emitBufferReadCore(0, 1);
1617
+ this.pushInstruction("return");
1618
+ }
1619
+
1620
+ _emitBufferReadCore(bTmp, pTmp) {
1621
+ const structInfo = this.mod.getStructType("bytes.Buffer");
1622
+ const byteElemGo = { kind: "basic", name: "byte" };
1623
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
1624
+ const arrW = {
1625
+ kind: "ref",
1626
+ nullable: true,
1627
+ typeIndex: sliceInfo.arrInfo.typeIndex,
1628
+ };
1629
+ const sliceW = {
1630
+ kind: "ref",
1631
+ nullable: true,
1632
+ typeIndex: sliceInfo.typeIndex,
1633
+ };
1634
+
1635
+ const pArrTmp = this.acquireTemp(arrW);
1636
+ const pOffTmp = this.acquireTemp("i32");
1637
+ const pLenTmp = this.acquireTemp("i32");
1638
+ const pCapTmp = this.acquireTemp("i32");
1639
+ this._emitSliceUnpack(pTmp, sliceInfo, {
1640
+ arr: pArrTmp,
1641
+ off: pOffTmp,
1642
+ len: pLenTmp,
1643
+ cap: pCapTmp,
1644
+ });
1645
+ this.releaseTemp(pCapTmp, "i32");
1646
+
1647
+ const resNTmp = this.acquireTemp("i64");
1648
+ const resErrTmp = this.acquireTemp("anyref");
1649
+
1650
+ // Get b.buf (field 0)
1651
+ const bufSliceTmp = this.acquireTemp(sliceW);
1652
+ this.pushInstruction({ op: "local.get", index: bTmp });
1653
+ this.pushInstruction({
1654
+ op: "struct.get",
1655
+ typeIndex: structInfo.typeIndex,
1656
+ fieldIndex: 0,
1657
+ });
1658
+ this.pushInstruction({ op: "local.set", index: bufSliceTmp });
1659
+
1660
+ this.pushInstruction({ op: "local.get", index: bufSliceTmp });
1661
+ this.pushInstruction("ref.is_null");
1662
+ this.pushInstruction({ op: "if", blockType: "void" });
1663
+ this.pushInstruction({
1664
+ op: "global.get",
1665
+ index: sliceInfo.emptyGlobalIndex,
1666
+ });
1667
+ this.pushInstruction({ op: "local.set", index: bufSliceTmp });
1668
+ this.pushInstruction("end");
1669
+
1670
+ const srcArrTmp = this.acquireTemp(arrW);
1671
+ const srcOffTmp = this.acquireTemp("i32");
1672
+ const srcLenTmp = this.acquireTemp("i32");
1673
+ const srcCapTmp = this.acquireTemp("i32");
1674
+ this._emitSliceUnpack(bufSliceTmp, sliceInfo, {
1675
+ arr: srcArrTmp,
1676
+ off: srcOffTmp,
1677
+ len: srcLenTmp,
1678
+ cap: srcCapTmp,
1679
+ });
1680
+ this.releaseTemp(bufSliceTmp, sliceW);
1681
+
1682
+ // if srcLen == 0:
1683
+ // if pLen == 0: (0, nil) else: (0, io.EOF)
1684
+ this.pushInstruction({ op: "local.get", index: srcLenTmp });
1685
+ this.pushInstruction("i32.eqz");
1686
+ this.pushInstruction({ op: "if", blockType: "void" });
1687
+ this.pushInstruction({ op: "i64.const", value: 0n });
1688
+ this.pushInstruction({ op: "local.set", index: resNTmp });
1689
+ this.pushInstruction({ op: "local.get", index: pLenTmp });
1690
+ this.pushInstruction("i32.eqz");
1691
+ this.pushInstruction({ op: "if", blockType: "anyref" });
1692
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1693
+ this.pushInstruction("else");
1694
+ this.emitIoConst("EOF", "anyref");
1695
+ this.pushInstruction("end");
1696
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1697
+ this.pushInstruction("else");
1698
+
1699
+ // n = min(p.len, srcLen)
1700
+ const nTmp = this.acquireTemp("i32");
1701
+ this.pushInstruction({ op: "local.get", index: pLenTmp });
1702
+ this.pushInstruction({ op: "local.get", index: srcLenTmp });
1703
+ this.pushInstruction("i32.lt_s");
1704
+ this.pushInstruction({ op: "if", blockType: "i32" });
1705
+ this.pushInstruction({ op: "local.get", index: pLenTmp });
1706
+ this.pushInstruction("else");
1707
+ this.pushInstruction({ op: "local.get", index: srcLenTmp });
1708
+ this.pushInstruction("end");
1709
+ this.pushInstruction({ op: "local.set", index: nTmp });
1710
+
1711
+ // copy: pArr[pOff .. pOff + n] = srcArr[srcOff .. srcOff + n]
1712
+ this.pushInstruction({ op: "local.get", index: pArrTmp });
1713
+ this.pushInstruction({ op: "local.get", index: pOffTmp });
1714
+ this.pushInstruction({ op: "local.get", index: srcArrTmp });
1715
+ this.pushInstruction({ op: "local.get", index: srcOffTmp });
1716
+ this.pushInstruction({ op: "local.get", index: nTmp });
1717
+ this._emitArrayCopy(sliceInfo.arrInfo, byteElemGo);
1718
+
1719
+ // update b.buf: struct.new sliceInfo (srcArr, srcOff + n, srcLen - n, srcCap - n)
1720
+ this.pushInstruction({ op: "local.get", index: bTmp });
1721
+ this.pushInstruction({ op: "local.get", index: srcArrTmp });
1722
+ this.pushInstruction({ op: "local.get", index: srcOffTmp });
1723
+ this.pushInstruction({ op: "local.get", index: nTmp });
1724
+ this.pushInstruction("i32.add");
1725
+ this.pushInstruction({ op: "local.get", index: srcLenTmp });
1726
+ this.pushInstruction({ op: "local.get", index: nTmp });
1727
+ this.pushInstruction("i32.sub");
1728
+ this.pushInstruction({ op: "local.get", index: srcCapTmp });
1729
+ this.pushInstruction({ op: "local.get", index: nTmp });
1730
+ this.pushInstruction("i32.sub");
1731
+ this.pushInstruction({
1732
+ op: "struct.new",
1733
+ typeIndex: sliceInfo.typeIndex,
1734
+ });
1735
+ this.pushInstruction({
1736
+ op: "struct.set",
1737
+ typeIndex: structInfo.typeIndex,
1738
+ fieldIndex: 0,
1739
+ });
1740
+
1741
+ this.pushInstruction({ op: "local.get", index: nTmp });
1742
+ this.pushInstruction("i64.extend_i32_u");
1743
+ this.pushInstruction({ op: "local.set", index: resNTmp });
1744
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1745
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1746
+
1747
+ this.releaseTemp(nTmp, "i32");
1748
+ this.pushInstruction("end"); // end else
1749
+
1750
+ this.releaseTemp(srcCapTmp, "i32");
1751
+ this.releaseTemp(srcLenTmp, "i32");
1752
+ this.releaseTemp(srcOffTmp, "i32");
1753
+ this.releaseTemp(srcArrTmp, arrW);
1754
+
1755
+ this.pushInstruction({ op: "local.get", index: resNTmp });
1756
+ this.pushInstruction({ op: "local.get", index: resErrTmp });
1757
+
1758
+ this.releaseTemp(resErrTmp, "anyref");
1759
+ this.releaseTemp(resNTmp, "i64");
1760
+ this.releaseTemp(pLenTmp, "i32");
1761
+ this.releaseTemp(pOffTmp, "i32");
1762
+ this.releaseTemp(pArrTmp, arrW);
1763
+ }
1764
+
1765
+ _emitHelperStringsReaderRead(_fn) {
1766
+ this._emitStringsReaderReadCore(0, 1);
1767
+ this.pushInstruction("return");
1768
+ }
1769
+
1770
+ _emitHelperStringsReaderLen(_fn) {
1771
+ this._emitStringsReaderLenCore(0, "i64");
1772
+ this.pushInstruction("return");
1773
+ }
1774
+
1775
+ _emitHelperStringsReaderReset(_fn) {
1776
+ this._emitStringsReaderResetCore(0, 1);
1777
+ this.pushInstruction("return");
1778
+ }
1779
+
1780
+ _emitHelperBytesReaderRead(_fn) {
1781
+ this._emitBytesReaderReadCore(0, 1);
1782
+ this.pushInstruction("return");
1783
+ }
1784
+
1785
+ _emitHelperBytesReaderLen(_fn) {
1786
+ this._emitBytesReaderLenCore(0, "i64");
1787
+ this.pushInstruction("return");
1788
+ }
1789
+
1790
+ _emitHelperBytesReaderReset(_fn) {
1791
+ this._emitBytesReaderResetCore(0, 1);
1792
+ this.pushInstruction("return");
1793
+ }
1794
+
1795
+ _emitHelperDiscardWrite(_fn) {
1796
+ const byteElemGo = { kind: "basic", name: "byte" };
1797
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
1798
+ this.pushInstruction({ op: "local.get", index: 1 });
1799
+ this.pushInstruction({
1800
+ op: "struct.get",
1801
+ typeIndex: sliceInfo.typeIndex,
1802
+ fieldIndex: 2,
1803
+ });
1804
+ this.pushInstruction("i64.extend_i32_u");
1805
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1806
+ this.pushInstruction("return");
1807
+ }
1808
+
1809
+ _emitHelperDiscardWriteString(_fn) {
1810
+ this.pushInstruction({ op: "local.get", index: 1 });
1811
+ this.pushInstruction({
1812
+ op: "call",
1813
+ funcIndex: this.mod.getStringLenImportIndex(),
1814
+ });
1815
+ this.pushInstruction("i64.extend_i32_u");
1816
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1817
+ this.pushInstruction("return");
1818
+ }
1819
+
1820
+ _emitHelperLimitedReaderRead(_fn) {
1821
+ this._emitLimitedReaderReadCore(0, 1);
1822
+ this.pushInstruction("return");
1823
+ }
1824
+
1825
+ _emitLimitedReaderReadCore(lTmp, pTmp) {
1826
+ const structInfo = this.mod.getStructType("io.LimitedReader");
1827
+ const byteElemGo = { kind: "basic", name: "byte" };
1828
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
1829
+ const arrW = {
1830
+ kind: "ref",
1831
+ nullable: true,
1832
+ typeIndex: sliceInfo.arrInfo.typeIndex,
1833
+ };
1834
+
1835
+ // 1. Check if l.N <= 0
1836
+ this.pushInstruction({ op: "local.get", index: lTmp });
1837
+ this.pushInstruction({
1838
+ op: "struct.get",
1839
+ typeIndex: structInfo.typeIndex,
1840
+ fieldIndex: 1, // N
1841
+ });
1842
+ this.pushInstruction({ op: "i64.const", value: 0n });
1843
+ this.pushInstruction("i64.le_s");
1844
+ this.pushInstruction({ op: "if", blockType: "void" });
1845
+ this.pushInstruction({ op: "i64.const", value: 0n });
1846
+ this.emitIoConst("EOF", "anyref");
1847
+ this.pushInstruction("return");
1848
+ this.pushInstruction("end");
1849
+
1850
+ // 2. If int64(len(p)) > l.N, subslice p = p[0:l.N]
1851
+ const pArrTmp = this.acquireTemp(arrW);
1852
+ const pOffTmp = this.acquireTemp("i32");
1853
+ const pLenTmp = this.acquireTemp("i32");
1854
+ const pCapTmp = this.acquireTemp("i32");
1855
+ this._emitSliceUnpack(pTmp, sliceInfo, {
1856
+ arr: pArrTmp,
1857
+ off: pOffTmp,
1858
+ len: pLenTmp,
1859
+ cap: pCapTmp,
1860
+ });
1861
+
1862
+ this.pushInstruction({ op: "local.get", index: pLenTmp });
1863
+ this.pushInstruction("i64.extend_i32_u");
1864
+ this.pushInstruction({ op: "local.get", index: lTmp });
1865
+ this.pushInstruction({
1866
+ op: "struct.get",
1867
+ typeIndex: structInfo.typeIndex,
1868
+ fieldIndex: 1, // N
1869
+ });
1870
+ this.pushInstruction("i64.gt_s");
1871
+ this.pushInstruction({ op: "if", blockType: "void" });
1872
+ this.pushInstruction({ op: "local.get", index: lTmp });
1873
+ this.pushInstruction({
1874
+ op: "struct.get",
1875
+ typeIndex: structInfo.typeIndex,
1876
+ fieldIndex: 1,
1877
+ });
1878
+ this.pushInstruction("i32.wrap_i64");
1879
+ this.pushInstruction({ op: "local.set", index: pLenTmp });
1880
+ this.pushInstruction({ op: "local.get", index: pArrTmp });
1881
+ this.pushInstruction({ op: "local.get", index: pOffTmp });
1882
+ this.pushInstruction({ op: "local.get", index: pLenTmp });
1883
+ this.pushInstruction({ op: "local.get", index: pCapTmp });
1884
+ this.pushInstruction({
1885
+ op: "struct.new",
1886
+ typeIndex: sliceInfo.typeIndex,
1887
+ });
1888
+ this.pushInstruction({ op: "local.set", index: pTmp });
1889
+ this.pushInstruction("end");
1890
+
1891
+ this.releaseTemp(pCapTmp, "i32");
1892
+ this.releaseTemp(pLenTmp, "i32");
1893
+ this.releaseTemp(pOffTmp, "i32");
1894
+ this.releaseTemp(pArrTmp, arrW);
1895
+
1896
+ // 3. Call l.R.Read(p)
1897
+ this.pushInstruction({ op: "local.get", index: lTmp });
1898
+ this.pushInstruction({
1899
+ op: "struct.get",
1900
+ typeIndex: structInfo.typeIndex,
1901
+ fieldIndex: 0, // R
1902
+ });
1903
+ this.pushInstruction({ op: "local.get", index: pTmp });
1904
+
1905
+ const dispatchIdx = this.mod.resolveFuncIndex("__dispatch_io.Reader_Read");
1906
+ if (dispatchIdx !== null) {
1907
+ this.pushInstruction({ op: "call", funcIndex: dispatchIdx });
1908
+ } else {
1909
+ this.pushInstruction({ op: "i64.const", value: 0n });
1910
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1911
+ }
1912
+
1913
+ const resErrTmp = this.acquireTemp("anyref");
1914
+ const resNTmp = this.acquireTemp("i64");
1915
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1916
+ this.pushInstruction({ op: "local.set", index: resNTmp });
1917
+
1918
+ // 4. Update l.N -= n:
1919
+ this.pushInstruction({ op: "local.get", index: lTmp });
1920
+ this.pushInstruction({ op: "local.get", index: lTmp });
1921
+ this.pushInstruction({
1922
+ op: "struct.get",
1923
+ typeIndex: structInfo.typeIndex,
1924
+ fieldIndex: 1, // N
1925
+ });
1926
+ this.pushInstruction({ op: "local.get", index: resNTmp });
1927
+ this.pushInstruction("i64.sub");
1928
+ this.pushInstruction({
1929
+ op: "struct.set",
1930
+ typeIndex: structInfo.typeIndex,
1931
+ fieldIndex: 1, // N
1932
+ });
1933
+
1934
+ // 5. Return (n, err)
1935
+ this.pushInstruction({ op: "local.get", index: resNTmp });
1936
+ this.pushInstruction({ op: "local.get", index: resErrTmp });
1937
+ this.releaseTemp(resNTmp, "i64");
1938
+ this.releaseTemp(resErrTmp, "anyref");
1939
+ }
1940
+
1941
+ emitIoLimitedReaderMethodCall(method, recvExpr, args, _targetWasmType) {
1942
+ if (method === "Read") {
1943
+ const structInfo = this.mod.getStructType("io.LimitedReader");
1944
+ const lrW = {
1945
+ kind: "ref",
1946
+ nullable: true,
1947
+ typeIndex: structInfo.typeIndex,
1948
+ };
1949
+ const lTmp = this.acquireTemp(lrW);
1950
+ this.emitExpr(recvExpr, lrW);
1951
+ this.pushInstruction({ op: "local.set", index: lTmp });
1952
+
1953
+ const byteElemGo = { kind: "basic", name: "byte" };
1954
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
1955
+ const sliceW = {
1956
+ kind: "ref",
1957
+ nullable: true,
1958
+ typeIndex: sliceInfo.typeIndex,
1959
+ };
1960
+ const pTmp = this.acquireTemp(sliceW);
1961
+ this.emitExpr(args[0], sliceW);
1962
+ this.pushInstruction({ op: "local.set", index: pTmp });
1963
+
1964
+ this._emitLimitedReaderReadCore(lTmp, pTmp);
1965
+ this.releaseTemp(pTmp, sliceW);
1966
+ this.releaseTemp(lTmp, lrW);
1967
+ return;
1968
+ }
1969
+ throw new Error(`Unsupported io.LimitedReader method: ${method}`);
1970
+ }
1971
+
1972
+ _emitHelperSha256Write(_fn) {
1973
+ this._emitBufferWriteCore(0, 1, "sha256.digest");
1974
+ this.pushInstruction("return");
1975
+ }
1976
+
1977
+ _emitHelperSha256Reset(_fn) {
1978
+ const structInfo = this.mod.getStructType("sha256.digest");
1979
+ const byteGo = { kind: "basic", name: "byte" };
1980
+ const sliceInfo = this.mod.getSliceType(byteGo);
1981
+ this.pushInstruction({ op: "local.get", index: 0 });
1982
+ this.pushInstruction({
1983
+ op: "global.get",
1984
+ index: sliceInfo.emptyGlobalIndex,
1985
+ });
1986
+ this.pushInstruction({
1987
+ op: "struct.set",
1988
+ typeIndex: structInfo.typeIndex,
1989
+ fieldIndex: 0,
1990
+ });
1991
+ this.pushInstruction("return");
1992
+ }
1993
+
1994
+ _emitHelperSha256Size(_fn) {
1995
+ this.pushInstruction({ op: "i64.const", value: 32n });
1996
+ this.pushInstruction("return");
1997
+ }
1998
+
1999
+ _emitHelperSha256BlockSize(_fn) {
2000
+ this.pushInstruction({ op: "i64.const", value: 64n });
2001
+ this.pushInstruction("return");
2002
+ }
2003
+
2004
+ _emitHelperSha256Sum(_fn) {
2005
+ const structInfo = this.mod.getStructType("sha256.digest");
2006
+ const byteGo = { kind: "basic", name: "byte" };
2007
+ const sliceInfo = this.mod.getSliceType(byteGo);
2008
+ const arrInfo = sliceInfo.arrInfo;
2009
+ const sliceW = {
2010
+ kind: "ref",
2011
+ nullable: true,
2012
+ typeIndex: sliceInfo.typeIndex,
2013
+ };
2014
+ const arrW = { kind: "ref", nullable: true, typeIndex: arrInfo.typeIndex };
2015
+
2016
+ const bufSliceTmp = this.acquireTemp(sliceW);
2017
+ this.pushInstruction({ op: "local.get", index: 0 });
2018
+ this.pushInstruction({
2019
+ op: "struct.get",
2020
+ typeIndex: structInfo.typeIndex,
2021
+ fieldIndex: 0,
2022
+ });
2023
+ this.pushInstruction({ op: "local.set", index: bufSliceTmp });
2024
+
2025
+ this.pushInstruction({ op: "local.get", index: bufSliceTmp });
2026
+ this.pushInstruction("ref.is_null");
2027
+ this.pushInstruction({ op: "if", blockType: "void" });
2028
+ this.pushInstruction({
2029
+ op: "global.get",
2030
+ index: sliceInfo.emptyGlobalIndex,
2031
+ });
2032
+ this.pushInstruction({ op: "local.set", index: bufSliceTmp });
2033
+ this.pushInstruction("end");
2034
+
2035
+ const dArrTmp = this.acquireTemp(arrW);
2036
+ const dOffTmp = this.acquireTemp("i32");
2037
+ const dLenTmp = this.acquireTemp("i32");
2038
+ const dCapTmp = this.acquireTemp("i32");
2039
+ this._emitSliceUnpack(bufSliceTmp, sliceInfo, {
2040
+ arr: dArrTmp,
2041
+ off: dOffTmp,
2042
+ len: dLenTmp,
2043
+ cap: dCapTmp,
2044
+ });
2045
+ this.releaseTemp(dCapTmp, "i32");
2046
+
2047
+ this.pushInstruction({ op: "local.get", index: dLenTmp });
2048
+ this._callStdlib("raw_bytes_init");
2049
+
2050
+ const iLoc = this.acquireTemp("i32");
2051
+ this.pushInstruction({ op: "i32.const", value: 0 });
2052
+ this.pushInstruction({ op: "local.set", index: iLoc });
2053
+
2054
+ this.pushInstruction({ op: "block", blockType: "void" });
2055
+ this.pushInstruction({ op: "loop", blockType: "void" });
2056
+ this.pushInstruction({ op: "local.get", index: iLoc });
2057
+ this.pushInstruction({ op: "local.get", index: dLenTmp });
2058
+ this.pushInstruction("i32.ge_s");
2059
+ this.pushInstruction({ op: "br_if", depth: 1 });
2060
+
2061
+ this.pushInstruction({ op: "local.get", index: dArrTmp });
2062
+ this.pushInstruction({ op: "local.get", index: dOffTmp });
2063
+ this.pushInstruction({ op: "local.get", index: iLoc });
2064
+ this.pushInstruction("i32.add");
2065
+ this.pushInstruction({ op: "array.get", typeIndex: arrInfo.typeIndex });
2066
+ this._callStdlib("raw_bytes_push");
2067
+
2068
+ this.pushInstruction({ op: "local.get", index: iLoc });
2069
+ this.pushInstruction({ op: "i32.const", value: 1 });
2070
+ this.pushInstruction("i32.add");
2071
+ this.pushInstruction({ op: "local.set", index: iLoc });
2072
+ this.pushInstruction({ op: "br", depth: 0 });
2073
+ this.pushInstruction("end");
2074
+ this.pushInstruction("end");
2075
+
2076
+ this._callStdlib("crypto_sha256_sum");
2077
+ this.pushInstruction("drop");
2078
+
2079
+ const outArrTmp = this.acquireTemp(arrW);
2080
+ this.pushInstruction({ op: "i32.const", value: 32 });
2081
+ this.pushInstruction({
2082
+ op: "array.new_default",
2083
+ typeIndex: arrInfo.typeIndex,
2084
+ });
2085
+ this.pushInstruction({ op: "local.set", index: outArrTmp });
2086
+
2087
+ this.pushInstruction({ op: "i32.const", value: 0 });
2088
+ this.pushInstruction({ op: "local.set", index: iLoc });
2089
+
2090
+ this.pushInstruction({ op: "block", blockType: "void" });
2091
+ this.pushInstruction({ op: "loop", blockType: "void" });
2092
+ this.pushInstruction({ op: "local.get", index: iLoc });
2093
+ this.pushInstruction({ op: "i32.const", value: 32 });
2094
+ this.pushInstruction("i32.ge_s");
2095
+ this.pushInstruction({ op: "br_if", depth: 1 });
2096
+
2097
+ this.pushInstruction({ op: "local.get", index: outArrTmp });
2098
+ this.pushInstruction({ op: "local.get", index: iLoc });
2099
+ this.pushInstruction({ op: "local.get", index: iLoc });
2100
+ this._callStdlib("raw_bytes_get");
2101
+ this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
2102
+
2103
+ this.pushInstruction({ op: "local.get", index: iLoc });
2104
+ this.pushInstruction({ op: "i32.const", value: 1 });
2105
+ this.pushInstruction("i32.add");
2106
+ this.pushInstruction({ op: "local.set", index: iLoc });
2107
+ this.pushInstruction({ op: "br", depth: 0 });
2108
+ this.pushInstruction("end");
2109
+ this.pushInstruction("end");
2110
+
2111
+ const outSliceTmp = this.acquireTemp(sliceW);
2112
+ this.pushInstruction({ op: "local.get", index: outArrTmp });
2113
+ this.pushInstruction({ op: "i32.const", value: 0 });
2114
+ this.pushInstruction({ op: "i32.const", value: 32 });
2115
+ this.pushInstruction({ op: "i32.const", value: 32 });
2116
+ this.pushInstruction({
2117
+ op: "struct.new",
2118
+ typeIndex: sliceInfo.typeIndex,
2119
+ });
2120
+ this.pushInstruction({ op: "local.set", index: outSliceTmp });
2121
+
2122
+ this.pushInstruction({ op: "local.get", index: 1 });
2123
+ this.pushInstruction("ref.is_null");
2124
+ this.pushInstruction({ op: "if", blockType: "void" });
2125
+ this.pushInstruction({ op: "local.get", index: outSliceTmp });
2126
+ this.pushInstruction("return");
2127
+ this.pushInstruction("end");
2128
+
2129
+ this.pushInstruction({ op: "local.get", index: 1 });
2130
+ this.pushInstruction({
2131
+ op: "struct.get",
2132
+ typeIndex: sliceInfo.typeIndex,
2133
+ fieldIndex: 1,
2134
+ });
2135
+ this.pushInstruction("i32.eqz");
2136
+ this.pushInstruction({ op: "if", blockType: "void" });
2137
+ this.pushInstruction({ op: "local.get", index: outSliceTmp });
2138
+ this.pushInstruction("return");
2139
+ this.pushInstruction("end");
2140
+
2141
+ const countTmp = this.acquireTemp("i32");
2142
+ this.pushInstruction({ op: "i32.const", value: 32 });
2143
+ this.pushInstruction({ op: "local.set", index: countTmp });
2144
+ const bTmp = this.acquireTemp(sliceW);
2145
+ this.pushInstruction({ op: "local.get", index: 1 });
2146
+ this.pushInstruction({ op: "local.set", index: bTmp });
2147
+ this._emitAppendSliceBytes(bTmp, outSliceTmp, countTmp, sliceInfo, arrW);
2148
+ this.pushInstruction({ op: "local.get", index: bTmp });
2149
+ this.pushInstruction("return");
2150
+
2151
+ this.releaseTemp(bTmp, sliceW);
2152
+ this.releaseTemp(countTmp, "i32");
2153
+ this.releaseTemp(outSliceTmp, sliceW);
2154
+ this.releaseTemp(outArrTmp, arrW);
2155
+ this.releaseTemp(iLoc, "i32");
2156
+ this.releaseTemp(dLenTmp, "i32");
2157
+ this.releaseTemp(dOffTmp, "i32");
2158
+ this.releaseTemp(dArrTmp, arrW);
2159
+ this.releaseTemp(bufSliceTmp, sliceW);
2160
+ }
2161
+ }