gofront 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +13 -13
  2. package/package.json +8 -37
  3. package/src/backend/js/expressions.js +1341 -148
  4. package/src/backend/js/fmt-runtime.js +573 -0
  5. package/src/backend/js/index.js +375 -57
  6. package/src/backend/js/runtime.js +1460 -133
  7. package/src/backend/js/statements.js +900 -86
  8. package/src/backend/js/stdlib/bits.js +87 -14
  9. package/src/backend/js/stdlib/builder.js +41 -6
  10. package/src/backend/js/stdlib/bytes.js +253 -7
  11. package/src/backend/js/stdlib/errors.js +2 -1
  12. package/src/backend/js/stdlib/fmt.js +349 -10
  13. package/src/backend/js/stdlib/index.js +8 -3
  14. package/src/backend/js/stdlib/json.js +247 -52
  15. package/src/backend/js/stdlib/maps.js +0 -8
  16. package/src/backend/js/stdlib/math.js +17 -1
  17. package/src/backend/js/stdlib/simd.js +10 -0
  18. package/src/backend/js/stdlib/slices.js +36 -6
  19. package/src/backend/js/stdlib/strconv.js +10 -5
  20. package/src/backend/js/stdlib/strings.js +83 -4
  21. package/src/backend/js/stdlib/testing.js +7 -0
  22. package/src/backend/js/stdlib/time.js +79 -55
  23. package/src/backend/js/stdlib/unicode.js +1 -1
  24. package/src/backend/js/stdlib/utf8.js +1 -1
  25. package/src/backend/js/templ.js +38 -76
  26. package/src/backend/js/type-info.js +272 -0
  27. package/src/backend/shared/fmt-types.js +188 -0
  28. package/src/backend/wasm/boundary.js +436 -80
  29. package/src/backend/wasm/emit-builtins.js +303 -13
  30. package/src/backend/wasm/emit-exprs.js +1397 -203
  31. package/src/backend/wasm/emit-maps.js +61 -13
  32. package/src/backend/wasm/emit-stmts.js +1359 -164
  33. package/src/backend/wasm/emit.js +512 -77
  34. package/src/backend/wasm/encode.js +43 -13
  35. package/src/backend/wasm/globals.js +452 -0
  36. package/src/backend/wasm/index.js +194 -2489
  37. package/src/backend/wasm/method-expr.js +381 -0
  38. package/src/backend/wasm/module-emitter.js +2240 -0
  39. package/src/backend/wasm/monomorph.js +62 -4
  40. package/src/backend/wasm/prescan.js +397 -0
  41. package/src/backend/wasm/stdlib/bytes.js +1804 -127
  42. package/src/backend/wasm/stdlib/core.js +1574 -199
  43. package/src/backend/wasm/stdlib/index.js +0 -5
  44. package/src/backend/wasm/stdlib/io.js +1567 -150
  45. package/src/backend/wasm/stdlib/packages.js +2 -0
  46. package/src/backend/wasm/stdlib/simd.js +293 -28
  47. package/src/backend/wasm/stdlib/time.js +1041 -12
  48. package/src/backend/wasm/types.js +200 -15
  49. package/src/backend/wasm/variadic.js +93 -0
  50. package/src/backend/wasm/wat.js +47 -20
  51. package/src/{cli-core.js → cli/cli-core.js} +236 -10
  52. package/src/{test-runner.js → cli/test-runner.js} +332 -39
  53. package/src/{vendor.js → cli/vendor.js} +3 -4
  54. package/src/compiler.js +107 -269
  55. package/src/index.js +15 -169
  56. package/src/{lexer.js → lexer/lexer.js} +102 -55
  57. package/src/{tokens.js → lexer/tokens.js} +1 -0
  58. package/src/link/sourcemap.js +97 -0
  59. package/src/link/stdlib.js +515 -0
  60. package/src/link/wasm.js +294 -0
  61. package/src/lower/bounds.js +394 -0
  62. package/src/lower/boxing.js +1 -1
  63. package/src/lower/captures.js +176 -32
  64. package/src/lower/index.js +26 -18
  65. package/src/lower/json-codecs.js +1398 -0
  66. package/src/lower/ownership.js +22 -1
  67. package/src/lower/range.js +86 -1
  68. package/src/lower/reachability.js +132 -0
  69. package/src/parser/declarations.js +58 -13
  70. package/src/parser/expressions.js +29 -7
  71. package/src/parser/index.js +2 -1
  72. package/src/parser/statements.js +37 -22
  73. package/src/{templ-parser.js → parser/templ.js} +138 -15
  74. package/src/parser/types.js +69 -9
  75. package/src/resolver.js +22 -1
  76. package/src/typechecker/assignability.js +176 -17
  77. package/src/typechecker/const-fold.js +356 -0
  78. package/src/typechecker/constants.js +256 -0
  79. package/src/typechecker/expressions.js +931 -122
  80. package/src/typechecker/index.js +459 -67
  81. package/src/typechecker/init-order.js +330 -0
  82. package/src/typechecker/resolve.js +451 -56
  83. package/src/typechecker/statements.js +90 -9
  84. package/src/typechecker/stdlib/core.js +333 -55
  85. package/src/typechecker/stdlib/excluded.js +898 -0
  86. package/src/typechecker/stdlib/extended.js +322 -26
  87. package/src/typechecker/{stdlib.js → stdlib/index.js} +5 -5
  88. package/src/typechecker/stdlib/simd.js +65 -15
  89. package/src/typechecker/termination.js +1 -1
  90. package/src/typechecker/types.js +149 -25
  91. package/stdlib/bytes/iter.go +192 -0
  92. package/stdlib/bytes/search.go +240 -0
  93. package/stdlib/bytes/split.go +218 -0
  94. package/stdlib/cmp/cmp.go +65 -0
  95. package/stdlib/encoding/json/errors.go +31 -0
  96. package/stdlib/encoding/json/indent.go +71 -0
  97. package/stdlib/encoding/json/number.go +12 -0
  98. package/stdlib/encoding/json/stream.go +173 -0
  99. package/stdlib/errors/overlay.go +12 -0
  100. package/stdlib/hash/hash.go +53 -0
  101. package/stdlib/internal/jsonrt/dec.go +738 -0
  102. package/stdlib/internal/jsonrt/enc.go +366 -0
  103. package/stdlib/internal/jsonrt/indent.go +135 -0
  104. package/stdlib/internal/jsonrt/number.go +27 -0
  105. package/stdlib/internal/jsonrt/reader.go +73 -0
  106. package/stdlib/internal/jsonrt/scanner.go +649 -0
  107. package/stdlib/io/io.go +346 -0
  108. package/stdlib/iter/iter.go +18 -0
  109. package/stdlib/maps/iter.go +65 -0
  110. package/stdlib/math/extra.go +270 -0
  111. package/stdlib/slices/extra.go +73 -0
  112. package/stdlib/slices/iter.go +113 -0
  113. package/stdlib/sort/sort.go +561 -0
  114. package/stdlib/strconv/quote.go +341 -0
  115. package/stdlib/strings/extra.go +35 -0
  116. package/stdlib/strings/iter.go +122 -0
  117. package/stdlib/sync/extra.go +105 -0
  118. package/stdlib/unicode/unicode.go +112 -0
  119. package/stdlib/unicode/utf8/bytes.go +239 -0
  120. package/src/backend/wasm/const-fold.js +0 -205
  121. package/src/backend/wasm/emit-stdlib.js +0 -13
  122. /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
  123. /package/src/{colors.js → cli/colors.js} +0 -0
  124. /package/src/{dev-server.js → cli/dev-server.js} +0 -0
  125. /package/src/{minifier.js → cli/minifier.js} +0 -0
  126. /package/src/{project-config.js → cli/project-config.js} +0 -0
  127. /package/src/{pwa.js → cli/pwa.js} +0 -0
  128. /package/src/{templ-lexer.js → lexer/templ-lexer.js} +0 -0
@@ -11,6 +11,42 @@ export class IoEmitter {
11
11
  );
12
12
  }
13
13
 
14
+ _isOsConst(expr) {
15
+ return (
16
+ this._isPkgExpr(expr, "os") &&
17
+ (expr.field === "Stdout" ||
18
+ expr.field === "Stderr" ||
19
+ expr.field === "Stdin")
20
+ );
21
+ }
22
+
23
+ emitOsConst(field, targetWasmType) {
24
+ const gIdx = this.mod.getOsGlobalIndex(field);
25
+ const fileInfo = this.mod.getStructType("os.File");
26
+ const fd = field === "Stdout" ? 1 : field === "Stderr" ? 2 : 0;
27
+ this.pushInstruction({ op: "global.get", index: gIdx });
28
+ this.pushInstruction("ref.is_null");
29
+ this.pushInstruction({ op: "if", blockType: "void" });
30
+ if (fileInfo) {
31
+ this.pushInstruction({ op: "i64.const", value: BigInt(fd) });
32
+ this.pushInstruction({
33
+ op: "struct.new",
34
+ typeIndex: fileInfo.typeIndex,
35
+ });
36
+ } else {
37
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
38
+ }
39
+ this.pushInstruction({ op: "global.set", index: gIdx });
40
+ this.pushInstruction("end");
41
+ this.pushInstruction({ op: "global.get", index: gIdx });
42
+ if (fileInfo && targetWasmType && targetWasmType !== "anyref") {
43
+ this.pushInstruction({
44
+ op: "ref.cast",
45
+ typeIndex: fileInfo.typeIndex,
46
+ });
47
+ }
48
+ }
49
+
14
50
  emitIoConst(field, _targetWasmType) {
15
51
  if (field === "EOF") {
16
52
  this._emitLazyErrorGlobal(this.mod.getIoErrGlobalIndex("EOF"), "EOF");
@@ -88,6 +124,13 @@ export class IoEmitter {
88
124
  this.pushInstruction({ op: "local.set", index: bTmp });
89
125
  this._emitBuilderWriteStringCore(bTmp, strTmp);
90
126
  this.releaseTemp(bTmp, builderW);
127
+ this.pushInstruction({ op: "local.get", index: strTmp });
128
+ this.pushInstruction({
129
+ op: "call",
130
+ funcIndex: this.mod.getStringLenImportIndex(),
131
+ });
132
+ this.pushInstruction("i64.extend_i32_u");
133
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
91
134
  return;
92
135
  }
93
136
  if (targetName === "bytes.Buffer") {
@@ -102,6 +145,25 @@ export class IoEmitter {
102
145
  this.pushInstruction({ op: "local.set", index: bTmp });
103
146
  this._emitBufferWriteStringCore(bTmp, strTmp);
104
147
  this.releaseTemp(bTmp, bufW);
148
+ this.pushInstruction({ op: "local.get", index: strTmp });
149
+ this.pushInstruction({
150
+ op: "call",
151
+ funcIndex: this.mod.getStringLenImportIndex(),
152
+ });
153
+ this.pushInstruction("i64.extend_i32_u");
154
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
155
+ return;
156
+ }
157
+ if (targetName === "os.File") {
158
+ this.pushInstruction({ op: "local.get", index: strTmp });
159
+ this._callStdlib("fmt_print_raw");
160
+ this.pushInstruction({ op: "local.get", index: strTmp });
161
+ this.pushInstruction({
162
+ op: "call",
163
+ funcIndex: this.mod.getStringLenImportIndex(),
164
+ });
165
+ this.pushInstruction("i64.extend_i32_u");
166
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
105
167
  return;
106
168
  }
107
169
 
@@ -577,6 +639,9 @@ export class IoEmitter {
577
639
  this.emitExpr(call.args[0], "externref");
578
640
  this._emitStringToByteSlice({ elem: { kind: "basic", name: "byte" } });
579
641
  this.pushInstruction({ op: "i64.const", value: 0n });
642
+ if (structInfo.fields.length > 2) {
643
+ this.pushInstruction({ op: "i64.const", value: -1n });
644
+ }
580
645
  this.pushInstruction({
581
646
  op: "struct.new",
582
647
  typeIndex: structInfo.typeIndex,
@@ -594,6 +659,9 @@ export class IoEmitter {
594
659
  };
595
660
  this.emitExpr(call.args[0], sliceW);
596
661
  this.pushInstruction({ op: "i64.const", value: 0n });
662
+ if (structInfo.fields.length > 2) {
663
+ this.pushInstruction({ op: "i64.const", value: -1n });
664
+ }
597
665
  this.pushInstruction({
598
666
  op: "struct.new",
599
667
  typeIndex: structInfo.typeIndex,
@@ -613,6 +681,38 @@ export class IoEmitter {
613
681
  this._emitStringsReaderReset(expr, args);
614
682
  return;
615
683
  }
684
+ if (method === "ReadAt") {
685
+ this._emitReaderReadAt(expr, args, "strings.Reader");
686
+ return;
687
+ }
688
+ if (method === "ReadByte") {
689
+ this._emitReaderReadByte(expr, "strings.Reader");
690
+ return;
691
+ }
692
+ if (method === "UnreadByte") {
693
+ this._emitReaderUnreadByte(expr, "strings.Reader");
694
+ return;
695
+ }
696
+ if (method === "ReadRune") {
697
+ this._emitReaderReadRune(expr, "strings.Reader");
698
+ return;
699
+ }
700
+ if (method === "UnreadRune") {
701
+ this._emitReaderUnreadRune(expr, "strings.Reader");
702
+ return;
703
+ }
704
+ if (method === "Seek") {
705
+ this._emitReaderSeek(expr, args, "strings.Reader");
706
+ return;
707
+ }
708
+ if (method === "Size") {
709
+ this._emitReaderSize(expr, targetWasmType, "strings.Reader");
710
+ return;
711
+ }
712
+ if (method === "WriteTo") {
713
+ this._emitReaderWriteTo(expr, args, "strings.Reader");
714
+ return;
715
+ }
616
716
  throw new Error(`Unsupported strings.Reader method: ${method}`);
617
717
  }
618
718
 
@@ -769,6 +869,16 @@ export class IoEmitter {
769
869
  fieldIndex: 1,
770
870
  });
771
871
 
872
+ if (structInfo.fields.length > 2) {
873
+ this.pushInstruction({ op: "local.get", index: rTmp });
874
+ this.pushInstruction({ op: "i64.const", value: -1n });
875
+ this.pushInstruction({
876
+ op: "struct.set",
877
+ typeIndex: structInfo.typeIndex,
878
+ fieldIndex: 2,
879
+ });
880
+ }
881
+
772
882
  this.pushInstruction({ op: "local.get", index: nTmp });
773
883
  this.pushInstruction("i64.extend_i32_u");
774
884
  this.pushInstruction({ op: "local.set", index: resNTmp });
@@ -895,6 +1005,15 @@ export class IoEmitter {
895
1005
  typeIndex: structInfo.typeIndex,
896
1006
  fieldIndex: 1,
897
1007
  });
1008
+ if (structInfo.fields.length > 2) {
1009
+ this.pushInstruction({ op: "local.get", index: rTmp });
1010
+ this.pushInstruction({ op: "i64.const", value: -1n });
1011
+ this.pushInstruction({
1012
+ op: "struct.set",
1013
+ typeIndex: structInfo.typeIndex,
1014
+ fieldIndex: 2,
1015
+ });
1016
+ }
898
1017
  }
899
1018
 
900
1019
  emitBytesReaderMethodCall(method, expr, args, targetWasmType) {
@@ -910,6 +1029,38 @@ export class IoEmitter {
910
1029
  this._emitBytesReaderReset(expr, args);
911
1030
  return;
912
1031
  }
1032
+ if (method === "ReadAt") {
1033
+ this._emitReaderReadAt(expr, args, "bytes.Reader");
1034
+ return;
1035
+ }
1036
+ if (method === "ReadByte") {
1037
+ this._emitReaderReadByte(expr, "bytes.Reader");
1038
+ return;
1039
+ }
1040
+ if (method === "UnreadByte") {
1041
+ this._emitReaderUnreadByte(expr, "bytes.Reader");
1042
+ return;
1043
+ }
1044
+ if (method === "ReadRune") {
1045
+ this._emitReaderReadRune(expr, "bytes.Reader");
1046
+ return;
1047
+ }
1048
+ if (method === "UnreadRune") {
1049
+ this._emitReaderUnreadRune(expr, "bytes.Reader");
1050
+ return;
1051
+ }
1052
+ if (method === "Seek") {
1053
+ this._emitReaderSeek(expr, args, "bytes.Reader");
1054
+ return;
1055
+ }
1056
+ if (method === "Size") {
1057
+ this._emitReaderSize(expr, targetWasmType, "bytes.Reader");
1058
+ return;
1059
+ }
1060
+ if (method === "WriteTo") {
1061
+ this._emitReaderWriteTo(expr, args, "bytes.Reader");
1062
+ return;
1063
+ }
913
1064
  throw new Error(`Unsupported bytes.Reader method: ${method}`);
914
1065
  }
915
1066
 
@@ -1006,129 +1157,19 @@ export class IoEmitter {
1006
1157
  typeIndex: structInfo.typeIndex,
1007
1158
  fieldIndex: 1,
1008
1159
  });
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 });
1160
+ if (structInfo.fields.length > 2) {
1161
+ this.pushInstruction({ op: "local.get", index: rTmp });
1162
+ this.pushInstruction({ op: "i64.const", value: -1n });
1070
1163
  this.pushInstruction({
1071
- op: "call",
1072
- funcIndex: this.mod.getStringImportIndex(),
1164
+ op: "struct.set",
1165
+ typeIndex: structInfo.typeIndex,
1166
+ fieldIndex: 2,
1073
1167
  });
1074
- return;
1075
1168
  }
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
1169
  }
1089
1170
 
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");
1171
+ _emitNewError(msg) {
1172
+ const strIdx = this.mod.internString(msg);
1132
1173
  this.pushInstruction({ op: "i32.const", value: strIdx });
1133
1174
  this.pushInstruction({
1134
1175
  op: "call",
@@ -1139,45 +1180,1341 @@ export class IoEmitter {
1139
1180
  op: "call",
1140
1181
  funcIndex: this.mod.resolveFuncIndex("__mk_error"),
1141
1182
  });
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
1183
  }
1150
1184
 
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" });
1185
+ _emitReaderReadAt(expr, args, typeName) {
1186
+ const structInfo = this.mod.getStructType(typeName);
1187
+ const readerW = {
1188
+ kind: "ref",
1189
+ nullable: true,
1190
+ typeIndex: structInfo.typeIndex,
1191
+ };
1192
+ const rTmp = this.acquireTemp(readerW);
1193
+ this.emitExpr(expr, readerW);
1194
+ this.pushInstruction({ op: "local.set", index: rTmp });
1156
1195
 
1157
- this._callStdlib("fmt_sscan_has_err");
1158
- this.pushInstruction({ op: "if", blockType: "void" });
1159
- this.pushInstruction("else");
1196
+ const byteElemGo = { kind: "basic", name: "byte" };
1197
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
1198
+ const arrW = {
1199
+ kind: "ref",
1200
+ nullable: true,
1201
+ typeIndex: sliceInfo.arrInfo.typeIndex,
1202
+ };
1203
+ const sliceW = {
1204
+ kind: "ref",
1205
+ nullable: true,
1206
+ typeIndex: sliceInfo.typeIndex,
1207
+ };
1160
1208
 
1161
- this._emitSscanWriteToken(pExpr, tokenIdx);
1209
+ const pTmp = this.acquireTemp(sliceW);
1210
+ this.emitExpr(args[0], sliceW);
1211
+ this.pushInstruction({ op: "local.set", index: pTmp });
1162
1212
 
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");
1213
+ const offTmp = this.acquireTemp("i64");
1214
+ this.emitExpr(args[1], "i64");
1215
+ this.pushInstruction({ op: "local.set", index: offTmp });
1171
1216
 
1172
- this.pushInstruction("end");
1173
- this.pushInstruction("end");
1174
- }
1217
+ const pArrTmp = this.acquireTemp(arrW);
1218
+ const pOffTmp = this.acquireTemp("i32");
1219
+ const pLenTmp = this.acquireTemp("i32");
1220
+ const pCapTmp = this.acquireTemp("i32");
1221
+ this._emitSliceUnpack(pTmp, sliceInfo, {
1222
+ arr: pArrTmp,
1223
+ off: pOffTmp,
1224
+ len: pLenTmp,
1225
+ cap: pCapTmp,
1226
+ });
1227
+ this.releaseTemp(pCapTmp, "i32");
1175
1228
 
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) ??
1229
+ const srcSliceTmp = this.acquireTemp(sliceW);
1230
+ this.pushInstruction({ op: "local.get", index: rTmp });
1231
+ this.pushInstruction({
1232
+ op: "struct.get",
1233
+ typeIndex: structInfo.typeIndex,
1234
+ fieldIndex: 0,
1235
+ });
1236
+ this.pushInstruction({ op: "local.set", index: srcSliceTmp });
1237
+
1238
+ const srcArrTmp = this.acquireTemp(arrW);
1239
+ const srcOffTmp = this.acquireTemp("i32");
1240
+ const srcLenTmp = this.acquireTemp("i32");
1241
+ const srcCapTmp = this.acquireTemp("i32");
1242
+ this._emitSliceUnpack(srcSliceTmp, sliceInfo, {
1243
+ arr: srcArrTmp,
1244
+ off: srcOffTmp,
1245
+ len: srcLenTmp,
1246
+ cap: srcCapTmp,
1247
+ });
1248
+ this.releaseTemp(srcCapTmp, "i32");
1249
+ this.releaseTemp(srcSliceTmp, sliceW);
1250
+
1251
+ const resNTmp = this.acquireTemp("i64");
1252
+ const resErrTmp = this.acquireTemp("anyref");
1253
+
1254
+ // if off < 0: return (0, errors.New("<typeName>.ReadAt: negative offset"))
1255
+ this.pushInstruction({ op: "local.get", index: offTmp });
1256
+ this.pushInstruction({ op: "i64.const", value: 0n });
1257
+ this.pushInstruction("i64.lt_s");
1258
+ this.pushInstruction({ op: "if", blockType: "void" });
1259
+ this.pushInstruction({ op: "i64.const", value: 0n });
1260
+ this.pushInstruction({ op: "local.set", index: resNTmp });
1261
+ this._emitNewError(`${typeName}.ReadAt: negative offset`);
1262
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1263
+ this.pushInstruction("else");
1264
+
1265
+ // if off >= srcLen: return (0, io.EOF)
1266
+ this.pushInstruction({ op: "local.get", index: offTmp });
1267
+ this.pushInstruction({ op: "local.get", index: srcLenTmp });
1268
+ this.pushInstruction("i64.extend_i32_u");
1269
+ this.pushInstruction("i64.ge_s");
1270
+ this.pushInstruction({ op: "if", blockType: "void" });
1271
+ this.pushInstruction({ op: "i64.const", value: 0n });
1272
+ this.pushInstruction({ op: "local.set", index: resNTmp });
1273
+ this.emitIoConst("EOF", "anyref");
1274
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1275
+ this.pushInstruction("else");
1276
+
1277
+ // avail = srcLen - int(off)
1278
+ const availTmp = this.acquireTemp("i32");
1279
+ this.pushInstruction({ op: "local.get", index: srcLenTmp });
1280
+ this.pushInstruction({ op: "local.get", index: offTmp });
1281
+ this.pushInstruction("i32.wrap_i64");
1282
+ this.pushInstruction("i32.sub");
1283
+ this.pushInstruction({ op: "local.set", index: availTmp });
1284
+
1285
+ // n = min(pLen, avail)
1286
+ const nTmp = this.acquireTemp("i32");
1287
+ this.pushInstruction({ op: "local.get", index: pLenTmp });
1288
+ this.pushInstruction({ op: "local.get", index: availTmp });
1289
+ this.pushInstruction("i32.lt_s");
1290
+ this.pushInstruction({ op: "if", blockType: "i32" });
1291
+ this.pushInstruction({ op: "local.get", index: pLenTmp });
1292
+ this.pushInstruction("else");
1293
+ this.pushInstruction({ op: "local.get", index: availTmp });
1294
+ this.pushInstruction("end");
1295
+ this.pushInstruction({ op: "local.set", index: nTmp });
1296
+
1297
+ // copy bytes: pArr[pOff] = srcArr[srcOff + off]
1298
+ this.pushInstruction({ op: "local.get", index: pArrTmp });
1299
+ this.pushInstruction({ op: "local.get", index: pOffTmp });
1300
+ this.pushInstruction({ op: "local.get", index: srcArrTmp });
1301
+ this.pushInstruction({ op: "local.get", index: srcOffTmp });
1302
+ this.pushInstruction({ op: "local.get", index: offTmp });
1303
+ this.pushInstruction("i32.wrap_i64");
1304
+ this.pushInstruction("i32.add");
1305
+ this.pushInstruction({ op: "local.get", index: nTmp });
1306
+ this._emitArrayCopy(sliceInfo.arrInfo, byteElemGo);
1307
+
1308
+ this.pushInstruction({ op: "local.get", index: nTmp });
1309
+ this.pushInstruction("i64.extend_i32_u");
1310
+ this.pushInstruction({ op: "local.set", index: resNTmp });
1311
+
1312
+ // if n < pLen: io.EOF else nil
1313
+ this.pushInstruction({ op: "local.get", index: nTmp });
1314
+ this.pushInstruction({ op: "local.get", index: pLenTmp });
1315
+ this.pushInstruction("i32.lt_s");
1316
+ this.pushInstruction({ op: "if", blockType: "anyref" });
1317
+ this.emitIoConst("EOF", "anyref");
1318
+ this.pushInstruction("else");
1319
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1320
+ this.pushInstruction("end");
1321
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1322
+
1323
+ this.releaseTemp(nTmp, "i32");
1324
+ this.releaseTemp(availTmp, "i32");
1325
+ this.pushInstruction("end");
1326
+ this.pushInstruction("end");
1327
+
1328
+ this.pushInstruction({ op: "local.get", index: resNTmp });
1329
+ this.pushInstruction({ op: "local.get", index: resErrTmp });
1330
+
1331
+ this.releaseTemp(resErrTmp, "anyref");
1332
+ this.releaseTemp(resNTmp, "i64");
1333
+ this.releaseTemp(srcLenTmp, "i32");
1334
+ this.releaseTemp(srcOffTmp, "i32");
1335
+ this.releaseTemp(srcArrTmp, arrW);
1336
+ this.releaseTemp(pLenTmp, "i32");
1337
+ this.releaseTemp(pOffTmp, "i32");
1338
+ this.releaseTemp(pArrTmp, arrW);
1339
+ this.releaseTemp(offTmp, "i64");
1340
+ this.releaseTemp(pTmp, sliceW);
1341
+ this.releaseTemp(rTmp, readerW);
1342
+ }
1343
+
1344
+ _emitReaderReadByte(expr, typeName) {
1345
+ const structInfo = this.mod.getStructType(typeName);
1346
+ const readerW = {
1347
+ kind: "ref",
1348
+ nullable: true,
1349
+ typeIndex: structInfo.typeIndex,
1350
+ };
1351
+ const rTmp = this.acquireTemp(readerW);
1352
+ this.emitExpr(expr, readerW);
1353
+ this.pushInstruction({ op: "local.set", index: rTmp });
1354
+
1355
+ const byteElemGo = { kind: "basic", name: "byte" };
1356
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
1357
+ const arrW = {
1358
+ kind: "ref",
1359
+ nullable: true,
1360
+ typeIndex: sliceInfo.arrInfo.typeIndex,
1361
+ };
1362
+ const sliceW = {
1363
+ kind: "ref",
1364
+ nullable: true,
1365
+ typeIndex: sliceInfo.typeIndex,
1366
+ };
1367
+
1368
+ const srcSliceTmp = this.acquireTemp(sliceW);
1369
+ this.pushInstruction({ op: "local.get", index: rTmp });
1370
+ this.pushInstruction({
1371
+ op: "struct.get",
1372
+ typeIndex: structInfo.typeIndex,
1373
+ fieldIndex: 0,
1374
+ });
1375
+ this.pushInstruction({ op: "local.set", index: srcSliceTmp });
1376
+
1377
+ const srcArrTmp = this.acquireTemp(arrW);
1378
+ const srcOffTmp = this.acquireTemp("i32");
1379
+ const srcLenTmp = this.acquireTemp("i32");
1380
+ const srcCapTmp = this.acquireTemp("i32");
1381
+ this._emitSliceUnpack(srcSliceTmp, sliceInfo, {
1382
+ arr: srcArrTmp,
1383
+ off: srcOffTmp,
1384
+ len: srcLenTmp,
1385
+ cap: srcCapTmp,
1386
+ });
1387
+ this.releaseTemp(srcCapTmp, "i32");
1388
+ this.releaseTemp(srcSliceTmp, sliceW);
1389
+
1390
+ const posTmp = this.acquireTemp("i64");
1391
+ this.pushInstruction({ op: "local.get", index: rTmp });
1392
+ this.pushInstruction({
1393
+ op: "struct.get",
1394
+ typeIndex: structInfo.typeIndex,
1395
+ fieldIndex: 1,
1396
+ });
1397
+ this.pushInstruction({ op: "local.set", index: posTmp });
1398
+
1399
+ const resByteTmp = this.acquireTemp("i32");
1400
+ const resErrTmp = this.acquireTemp("anyref");
1401
+
1402
+ this.pushInstruction({ op: "local.get", index: posTmp });
1403
+ this.pushInstruction({ op: "local.get", index: srcLenTmp });
1404
+ this.pushInstruction("i64.extend_i32_u");
1405
+ this.pushInstruction("i64.ge_s");
1406
+ this.pushInstruction({ op: "if", blockType: "void" });
1407
+ this.pushInstruction({ op: "i32.const", value: 0 });
1408
+ this.pushInstruction({ op: "local.set", index: resByteTmp });
1409
+ this.emitIoConst("EOF", "anyref");
1410
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1411
+ this.pushInstruction("else");
1412
+
1413
+ this.pushInstruction({ op: "local.get", index: srcArrTmp });
1414
+ this.pushInstruction({ op: "local.get", index: srcOffTmp });
1415
+ this.pushInstruction({ op: "local.get", index: posTmp });
1416
+ this.pushInstruction("i32.wrap_i64");
1417
+ this.pushInstruction("i32.add");
1418
+ this.pushInstruction({
1419
+ op: "array.get",
1420
+ typeIndex: sliceInfo.arrInfo.typeIndex,
1421
+ });
1422
+ this.pushInstruction({ op: "local.set", index: resByteTmp });
1423
+
1424
+ this.pushInstruction({ op: "local.get", index: rTmp });
1425
+ this.pushInstruction({ op: "local.get", index: posTmp });
1426
+ this.pushInstruction({ op: "i64.const", value: 1n });
1427
+ this.pushInstruction("i64.add");
1428
+ this.pushInstruction({
1429
+ op: "struct.set",
1430
+ typeIndex: structInfo.typeIndex,
1431
+ fieldIndex: 1,
1432
+ });
1433
+
1434
+ if (structInfo.fields.length > 2) {
1435
+ this.pushInstruction({ op: "local.get", index: rTmp });
1436
+ this.pushInstruction({ op: "i64.const", value: -1n });
1437
+ this.pushInstruction({
1438
+ op: "struct.set",
1439
+ typeIndex: structInfo.typeIndex,
1440
+ fieldIndex: 2,
1441
+ });
1442
+ }
1443
+
1444
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1445
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1446
+ this.pushInstruction("end");
1447
+
1448
+ this.pushInstruction({ op: "local.get", index: resByteTmp });
1449
+ this.pushInstruction({ op: "local.get", index: resErrTmp });
1450
+
1451
+ this.releaseTemp(resErrTmp, "anyref");
1452
+ this.releaseTemp(resByteTmp, "i32");
1453
+ this.releaseTemp(posTmp, "i64");
1454
+ this.releaseTemp(srcLenTmp, "i32");
1455
+ this.releaseTemp(srcOffTmp, "i32");
1456
+ this.releaseTemp(srcArrTmp, arrW);
1457
+ this.releaseTemp(rTmp, readerW);
1458
+ }
1459
+
1460
+ _emitReaderUnreadByte(expr, typeName) {
1461
+ const structInfo = this.mod.getStructType(typeName);
1462
+ const readerW = {
1463
+ kind: "ref",
1464
+ nullable: true,
1465
+ typeIndex: structInfo.typeIndex,
1466
+ };
1467
+ const rTmp = this.acquireTemp(readerW);
1468
+ this.emitExpr(expr, readerW);
1469
+ this.pushInstruction({ op: "local.set", index: rTmp });
1470
+
1471
+ const posTmp = this.acquireTemp("i64");
1472
+ this.pushInstruction({ op: "local.get", index: rTmp });
1473
+ this.pushInstruction({
1474
+ op: "struct.get",
1475
+ typeIndex: structInfo.typeIndex,
1476
+ fieldIndex: 1,
1477
+ });
1478
+ this.pushInstruction({ op: "local.set", index: posTmp });
1479
+
1480
+ const resErrTmp = this.acquireTemp("anyref");
1481
+
1482
+ this.pushInstruction({ op: "local.get", index: posTmp });
1483
+ this.pushInstruction({ op: "i64.const", value: 0n });
1484
+ this.pushInstruction("i64.le_s");
1485
+ this.pushInstruction({ op: "if", blockType: "void" });
1486
+ const targetKind = typeName.startsWith("strings") ? "string" : "slice";
1487
+ this._emitNewError(`${typeName}.UnreadByte: at beginning of ${targetKind}`);
1488
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1489
+ this.pushInstruction("else");
1490
+
1491
+ this.pushInstruction({ op: "local.get", index: rTmp });
1492
+ this.pushInstruction({ op: "local.get", index: posTmp });
1493
+ this.pushInstruction({ op: "i64.const", value: 1n });
1494
+ this.pushInstruction("i64.sub");
1495
+ this.pushInstruction({
1496
+ op: "struct.set",
1497
+ typeIndex: structInfo.typeIndex,
1498
+ fieldIndex: 1,
1499
+ });
1500
+
1501
+ if (structInfo.fields.length > 2) {
1502
+ this.pushInstruction({ op: "local.get", index: rTmp });
1503
+ this.pushInstruction({ op: "i64.const", value: -1n });
1504
+ this.pushInstruction({
1505
+ op: "struct.set",
1506
+ typeIndex: structInfo.typeIndex,
1507
+ fieldIndex: 2,
1508
+ });
1509
+ }
1510
+
1511
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1512
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1513
+ this.pushInstruction("end");
1514
+
1515
+ this.pushInstruction({ op: "local.get", index: resErrTmp });
1516
+
1517
+ this.releaseTemp(resErrTmp, "anyref");
1518
+ this.releaseTemp(posTmp, "i64");
1519
+ this.releaseTemp(rTmp, readerW);
1520
+ }
1521
+
1522
+ _emitReaderReadRune(expr, typeName) {
1523
+ const structInfo = this.mod.getStructType(typeName);
1524
+ const readerW = {
1525
+ kind: "ref",
1526
+ nullable: true,
1527
+ typeIndex: structInfo.typeIndex,
1528
+ };
1529
+ const rTmp = this.acquireTemp(readerW);
1530
+ this.emitExpr(expr, readerW);
1531
+ this.pushInstruction({ op: "local.set", index: rTmp });
1532
+
1533
+ const byteElemGo = { kind: "basic", name: "byte" };
1534
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
1535
+ const arrW = {
1536
+ kind: "ref",
1537
+ nullable: true,
1538
+ typeIndex: sliceInfo.arrInfo.typeIndex,
1539
+ };
1540
+ const sliceW = {
1541
+ kind: "ref",
1542
+ nullable: true,
1543
+ typeIndex: sliceInfo.typeIndex,
1544
+ };
1545
+
1546
+ const srcSliceTmp = this.acquireTemp(sliceW);
1547
+ this.pushInstruction({ op: "local.get", index: rTmp });
1548
+ this.pushInstruction({
1549
+ op: "struct.get",
1550
+ typeIndex: structInfo.typeIndex,
1551
+ fieldIndex: 0,
1552
+ });
1553
+ this.pushInstruction({ op: "local.set", index: srcSliceTmp });
1554
+
1555
+ const srcArrTmp = this.acquireTemp(arrW);
1556
+ const srcOffTmp = this.acquireTemp("i32");
1557
+ const srcLenTmp = this.acquireTemp("i32");
1558
+ const srcCapTmp = this.acquireTemp("i32");
1559
+ this._emitSliceUnpack(srcSliceTmp, sliceInfo, {
1560
+ arr: srcArrTmp,
1561
+ off: srcOffTmp,
1562
+ len: srcLenTmp,
1563
+ cap: srcCapTmp,
1564
+ });
1565
+ this.releaseTemp(srcCapTmp, "i32");
1566
+ this.releaseTemp(srcSliceTmp, sliceW);
1567
+
1568
+ const posTmp = this.acquireTemp("i64");
1569
+ this.pushInstruction({ op: "local.get", index: rTmp });
1570
+ this.pushInstruction({
1571
+ op: "struct.get",
1572
+ typeIndex: structInfo.typeIndex,
1573
+ fieldIndex: 1,
1574
+ });
1575
+ this.pushInstruction({ op: "local.set", index: posTmp });
1576
+
1577
+ const resRuneTmp = this.acquireTemp("i32");
1578
+ const resSizeTmp = this.acquireTemp("i64");
1579
+ const resErrTmp = this.acquireTemp("anyref");
1580
+
1581
+ this.pushInstruction({ op: "local.get", index: posTmp });
1582
+ this.pushInstruction({ op: "local.get", index: srcLenTmp });
1583
+ this.pushInstruction("i64.extend_i32_u");
1584
+ this.pushInstruction("i64.ge_s");
1585
+ this.pushInstruction({ op: "if", blockType: "void" });
1586
+ if (structInfo.fields.length > 2) {
1587
+ this.pushInstruction({ op: "local.get", index: rTmp });
1588
+ this.pushInstruction({ op: "i64.const", value: -1n });
1589
+ this.pushInstruction({
1590
+ op: "struct.set",
1591
+ typeIndex: structInfo.typeIndex,
1592
+ fieldIndex: 2,
1593
+ });
1594
+ }
1595
+ this.pushInstruction({ op: "i32.const", value: 0 });
1596
+ this.pushInstruction({ op: "local.set", index: resRuneTmp });
1597
+ this.pushInstruction({ op: "i64.const", value: 0n });
1598
+ this.pushInstruction({ op: "local.set", index: resSizeTmp });
1599
+ this.emitIoConst("EOF", "anyref");
1600
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1601
+ this.pushInstruction("else");
1602
+
1603
+ const cpTmp = this.acquireTemp("i32");
1604
+ const runeLenTmp = this.acquireTemp("i32");
1605
+ const posI32Tmp = this.acquireTemp("i32");
1606
+ this.pushInstruction({ op: "local.get", index: posTmp });
1607
+ this.pushInstruction("i32.wrap_i64");
1608
+ this.pushInstruction({ op: "local.set", index: posI32Tmp });
1609
+
1610
+ this._emitDecodeUtf8Rune({
1611
+ arrTmp: srcArrTmp,
1612
+ offTmp: srcOffTmp,
1613
+ idxTmp: posI32Tmp,
1614
+ lenTmp: srcLenTmp,
1615
+ outRuneTmp: cpTmp,
1616
+ outLenTmp: runeLenTmp,
1617
+ arrTypeIndex: sliceInfo.arrInfo.typeIndex,
1618
+ });
1619
+
1620
+ if (structInfo.fields.length > 2) {
1621
+ this.pushInstruction({ op: "local.get", index: rTmp });
1622
+ this.pushInstruction({ op: "local.get", index: posTmp });
1623
+ this.pushInstruction({
1624
+ op: "struct.set",
1625
+ typeIndex: structInfo.typeIndex,
1626
+ fieldIndex: 2,
1627
+ });
1628
+ }
1629
+
1630
+ this.pushInstruction({ op: "local.get", index: rTmp });
1631
+ this.pushInstruction({ op: "local.get", index: posTmp });
1632
+ this.pushInstruction({ op: "local.get", index: runeLenTmp });
1633
+ this.pushInstruction("i64.extend_i32_u");
1634
+ this.pushInstruction("i64.add");
1635
+ this.pushInstruction({
1636
+ op: "struct.set",
1637
+ typeIndex: structInfo.typeIndex,
1638
+ fieldIndex: 1,
1639
+ });
1640
+
1641
+ this.pushInstruction({ op: "local.get", index: cpTmp });
1642
+ this.pushInstruction({ op: "local.set", index: resRuneTmp });
1643
+ this.pushInstruction({ op: "local.get", index: runeLenTmp });
1644
+ this.pushInstruction("i64.extend_i32_u");
1645
+ this.pushInstruction({ op: "local.set", index: resSizeTmp });
1646
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1647
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1648
+
1649
+ this.releaseTemp(posI32Tmp, "i32");
1650
+ this.releaseTemp(runeLenTmp, "i32");
1651
+ this.releaseTemp(cpTmp, "i32");
1652
+ this.pushInstruction("end");
1653
+
1654
+ this.pushInstruction({ op: "local.get", index: resRuneTmp });
1655
+ this.pushInstruction({ op: "local.get", index: resSizeTmp });
1656
+ this.pushInstruction({ op: "local.get", index: resErrTmp });
1657
+
1658
+ this.releaseTemp(resErrTmp, "anyref");
1659
+ this.releaseTemp(resSizeTmp, "i64");
1660
+ this.releaseTemp(resRuneTmp, "i32");
1661
+ this.releaseTemp(posTmp, "i64");
1662
+ this.releaseTemp(srcLenTmp, "i32");
1663
+ this.releaseTemp(srcOffTmp, "i32");
1664
+ this.releaseTemp(srcArrTmp, arrW);
1665
+ this.releaseTemp(rTmp, readerW);
1666
+ }
1667
+
1668
+ _emitReaderUnreadRune(expr, typeName) {
1669
+ const structInfo = this.mod.getStructType(typeName);
1670
+ const readerW = {
1671
+ kind: "ref",
1672
+ nullable: true,
1673
+ typeIndex: structInfo.typeIndex,
1674
+ };
1675
+ const rTmp = this.acquireTemp(readerW);
1676
+ this.emitExpr(expr, readerW);
1677
+ this.pushInstruction({ op: "local.set", index: rTmp });
1678
+
1679
+ const prevTmp = this.acquireTemp("i64");
1680
+ if (structInfo.fields.length > 2) {
1681
+ this.pushInstruction({ op: "local.get", index: rTmp });
1682
+ this.pushInstruction({
1683
+ op: "struct.get",
1684
+ typeIndex: structInfo.typeIndex,
1685
+ fieldIndex: 2,
1686
+ });
1687
+ this.pushInstruction({ op: "local.set", index: prevTmp });
1688
+ } else {
1689
+ this.pushInstruction({ op: "i64.const", value: -1n });
1690
+ this.pushInstruction({ op: "local.set", index: prevTmp });
1691
+ }
1692
+
1693
+ const posTmp = this.acquireTemp("i64");
1694
+ this.pushInstruction({ op: "local.get", index: rTmp });
1695
+ this.pushInstruction({
1696
+ op: "struct.get",
1697
+ typeIndex: structInfo.typeIndex,
1698
+ fieldIndex: 1,
1699
+ });
1700
+ this.pushInstruction({ op: "local.set", index: posTmp });
1701
+
1702
+ const resErrTmp = this.acquireTemp("anyref");
1703
+
1704
+ this.pushInstruction({ op: "local.get", index: prevTmp });
1705
+ this.pushInstruction({ op: "i64.const", value: 0n });
1706
+ this.pushInstruction("i64.lt_s");
1707
+ this.pushInstruction({ op: "local.get", index: prevTmp });
1708
+ this.pushInstruction({ op: "local.get", index: posTmp });
1709
+ this.pushInstruction("i64.ge_s");
1710
+ this.pushInstruction("i32.or");
1711
+ this.pushInstruction({ op: "if", blockType: "void" });
1712
+ this._emitNewError(
1713
+ `${typeName}.UnreadRune: previous operation was not ReadRune`,
1714
+ );
1715
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1716
+ this.pushInstruction("else");
1717
+
1718
+ this.pushInstruction({ op: "local.get", index: rTmp });
1719
+ this.pushInstruction({ op: "local.get", index: prevTmp });
1720
+ this.pushInstruction({
1721
+ op: "struct.set",
1722
+ typeIndex: structInfo.typeIndex,
1723
+ fieldIndex: 1,
1724
+ });
1725
+
1726
+ if (structInfo.fields.length > 2) {
1727
+ this.pushInstruction({ op: "local.get", index: rTmp });
1728
+ this.pushInstruction({ op: "i64.const", value: -1n });
1729
+ this.pushInstruction({
1730
+ op: "struct.set",
1731
+ typeIndex: structInfo.typeIndex,
1732
+ fieldIndex: 2,
1733
+ });
1734
+ }
1735
+
1736
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1737
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1738
+ this.pushInstruction("end");
1739
+
1740
+ this.pushInstruction({ op: "local.get", index: resErrTmp });
1741
+
1742
+ this.releaseTemp(resErrTmp, "anyref");
1743
+ this.releaseTemp(posTmp, "i64");
1744
+ this.releaseTemp(prevTmp, "i64");
1745
+ this.releaseTemp(rTmp, readerW);
1746
+ }
1747
+
1748
+ _emitReaderSeek(expr, args, typeName) {
1749
+ const structInfo = this.mod.getStructType(typeName);
1750
+ const readerW = {
1751
+ kind: "ref",
1752
+ nullable: true,
1753
+ typeIndex: structInfo.typeIndex,
1754
+ };
1755
+ const rTmp = this.acquireTemp(readerW);
1756
+ this.emitExpr(expr, readerW);
1757
+ this.pushInstruction({ op: "local.set", index: rTmp });
1758
+
1759
+ const offTmp = this.acquireTemp("i64");
1760
+ this.emitExpr(args[0], "i64");
1761
+ this.pushInstruction({ op: "local.set", index: offTmp });
1762
+
1763
+ const whenceTmp = this.acquireTemp("i32");
1764
+ this._emitI32Arg(args[1]);
1765
+ this.pushInstruction({ op: "local.set", index: whenceTmp });
1766
+
1767
+ const byteElemGo = { kind: "basic", name: "byte" };
1768
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
1769
+ const sliceW = {
1770
+ kind: "ref",
1771
+ nullable: true,
1772
+ typeIndex: sliceInfo.typeIndex,
1773
+ };
1774
+
1775
+ const srcSliceTmp = this.acquireTemp(sliceW);
1776
+ this.pushInstruction({ op: "local.get", index: rTmp });
1777
+ this.pushInstruction({
1778
+ op: "struct.get",
1779
+ typeIndex: structInfo.typeIndex,
1780
+ fieldIndex: 0,
1781
+ });
1782
+ this.pushInstruction({ op: "local.set", index: srcSliceTmp });
1783
+
1784
+ const srcLenTmp = this.acquireTemp("i32");
1785
+ this.pushInstruction({ op: "local.get", index: srcSliceTmp });
1786
+ this.pushInstruction({
1787
+ op: "struct.get",
1788
+ typeIndex: sliceInfo.typeIndex,
1789
+ fieldIndex: 2,
1790
+ });
1791
+ this.pushInstruction({ op: "local.set", index: srcLenTmp });
1792
+ this.releaseTemp(srcSliceTmp, sliceW);
1793
+
1794
+ const posTmp = this.acquireTemp("i64");
1795
+ this.pushInstruction({ op: "local.get", index: rTmp });
1796
+ this.pushInstruction({
1797
+ op: "struct.get",
1798
+ typeIndex: structInfo.typeIndex,
1799
+ fieldIndex: 1,
1800
+ });
1801
+ this.pushInstruction({ op: "local.set", index: posTmp });
1802
+
1803
+ const newPosTmp = this.acquireTemp("i64");
1804
+ const resErrTmp = this.acquireTemp("anyref");
1805
+
1806
+ this.pushInstruction({ op: "local.get", index: whenceTmp });
1807
+ this.pushInstruction({ op: "i32.const", value: 0 });
1808
+ this.pushInstruction("i32.eq");
1809
+ this.pushInstruction({ op: "if", blockType: "void" });
1810
+ this.pushInstruction({ op: "local.get", index: offTmp });
1811
+ this.pushInstruction({ op: "local.set", index: newPosTmp });
1812
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1813
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1814
+ this.pushInstruction("else");
1815
+
1816
+ this.pushInstruction({ op: "local.get", index: whenceTmp });
1817
+ this.pushInstruction({ op: "i32.const", value: 1 });
1818
+ this.pushInstruction("i32.eq");
1819
+ this.pushInstruction({ op: "if", blockType: "void" });
1820
+ this.pushInstruction({ op: "local.get", index: posTmp });
1821
+ this.pushInstruction({ op: "local.get", index: offTmp });
1822
+ this.pushInstruction("i64.add");
1823
+ this.pushInstruction({ op: "local.set", index: newPosTmp });
1824
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1825
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1826
+ this.pushInstruction("else");
1827
+
1828
+ this.pushInstruction({ op: "local.get", index: whenceTmp });
1829
+ this.pushInstruction({ op: "i32.const", value: 2 });
1830
+ this.pushInstruction("i32.eq");
1831
+ this.pushInstruction({ op: "if", blockType: "void" });
1832
+ this.pushInstruction({ op: "local.get", index: srcLenTmp });
1833
+ this.pushInstruction("i64.extend_i32_u");
1834
+ this.pushInstruction({ op: "local.get", index: offTmp });
1835
+ this.pushInstruction("i64.add");
1836
+ this.pushInstruction({ op: "local.set", index: newPosTmp });
1837
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1838
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1839
+ this.pushInstruction("else");
1840
+
1841
+ this.pushInstruction({ op: "i64.const", value: 0n });
1842
+ this.pushInstruction({ op: "local.set", index: newPosTmp });
1843
+ this._emitNewError(`${typeName}.Seek: invalid whence`);
1844
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1845
+ this.pushInstruction("end");
1846
+ this.pushInstruction("end");
1847
+ this.pushInstruction("end");
1848
+
1849
+ this.pushInstruction({ op: "local.get", index: resErrTmp });
1850
+ this.pushInstruction("ref.is_null");
1851
+ this.pushInstruction({ op: "if", blockType: "void" });
1852
+ this.pushInstruction({ op: "local.get", index: newPosTmp });
1853
+ this.pushInstruction({ op: "i64.const", value: 0n });
1854
+ this.pushInstruction("i64.lt_s");
1855
+ this.pushInstruction({ op: "if", blockType: "void" });
1856
+ this.pushInstruction({ op: "i64.const", value: 0n });
1857
+ this.pushInstruction({ op: "local.set", index: newPosTmp });
1858
+ this._emitNewError(`${typeName}.Seek: negative position`);
1859
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
1860
+ this.pushInstruction("else");
1861
+ this.pushInstruction({ op: "local.get", index: rTmp });
1862
+ this.pushInstruction({ op: "local.get", index: newPosTmp });
1863
+ this.pushInstruction({
1864
+ op: "struct.set",
1865
+ typeIndex: structInfo.typeIndex,
1866
+ fieldIndex: 1,
1867
+ });
1868
+ if (structInfo.fields.length > 2) {
1869
+ this.pushInstruction({ op: "local.get", index: rTmp });
1870
+ this.pushInstruction({ op: "i64.const", value: -1n });
1871
+ this.pushInstruction({
1872
+ op: "struct.set",
1873
+ typeIndex: structInfo.typeIndex,
1874
+ fieldIndex: 2,
1875
+ });
1876
+ }
1877
+ this.pushInstruction("end");
1878
+ this.pushInstruction("end");
1879
+
1880
+ this.pushInstruction({ op: "local.get", index: newPosTmp });
1881
+ this.pushInstruction({ op: "local.get", index: resErrTmp });
1882
+
1883
+ this.releaseTemp(resErrTmp, "anyref");
1884
+ this.releaseTemp(newPosTmp, "i64");
1885
+ this.releaseTemp(posTmp, "i64");
1886
+ this.releaseTemp(srcLenTmp, "i32");
1887
+ this.releaseTemp(whenceTmp, "i32");
1888
+ this.releaseTemp(offTmp, "i64");
1889
+ this.releaseTemp(rTmp, readerW);
1890
+ }
1891
+
1892
+ _emitReaderSize(expr, targetWasmType, typeName) {
1893
+ const structInfo = this.mod.getStructType(typeName);
1894
+ const readerW = {
1895
+ kind: "ref",
1896
+ nullable: true,
1897
+ typeIndex: structInfo.typeIndex,
1898
+ };
1899
+ const rTmp = this.acquireTemp(readerW);
1900
+ this.emitExpr(expr, readerW);
1901
+ this.pushInstruction({ op: "local.set", index: rTmp });
1902
+
1903
+ const byteElemGo = { kind: "basic", name: "byte" };
1904
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
1905
+ const sliceW = {
1906
+ kind: "ref",
1907
+ nullable: true,
1908
+ typeIndex: sliceInfo.typeIndex,
1909
+ };
1910
+
1911
+ const srcSliceTmp = this.acquireTemp(sliceW);
1912
+ this.pushInstruction({ op: "local.get", index: rTmp });
1913
+ this.pushInstruction({
1914
+ op: "struct.get",
1915
+ typeIndex: structInfo.typeIndex,
1916
+ fieldIndex: 0,
1917
+ });
1918
+ this.pushInstruction({ op: "local.set", index: srcSliceTmp });
1919
+
1920
+ this.pushInstruction({ op: "local.get", index: srcSliceTmp });
1921
+ this.pushInstruction({
1922
+ op: "struct.get",
1923
+ typeIndex: sliceInfo.typeIndex,
1924
+ fieldIndex: 2,
1925
+ });
1926
+ this.pushInstruction("i64.extend_i32_u");
1927
+
1928
+ if ((targetWasmType ?? "i64") === "i32") {
1929
+ this.pushInstruction("i32.wrap_i64");
1930
+ }
1931
+
1932
+ this.releaseTemp(srcSliceTmp, sliceW);
1933
+ this.releaseTemp(rTmp, readerW);
1934
+ }
1935
+
1936
+ _emitReaderWriteTo(expr, args, typeName) {
1937
+ const structInfo = this.mod.getStructType(typeName);
1938
+ const readerW = {
1939
+ kind: "ref",
1940
+ nullable: true,
1941
+ typeIndex: structInfo.typeIndex,
1942
+ };
1943
+ const rTmp = this.acquireTemp(readerW);
1944
+ this.emitExpr(expr, readerW);
1945
+ this.pushInstruction({ op: "local.set", index: rTmp });
1946
+
1947
+ const wTmp = this.acquireTemp("anyref");
1948
+ this.emitExpr(args[0], "anyref");
1949
+ this.pushInstruction({ op: "local.set", index: wTmp });
1950
+
1951
+ const byteElemGo = { kind: "basic", name: "byte" };
1952
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
1953
+ const arrW = {
1954
+ kind: "ref",
1955
+ nullable: true,
1956
+ typeIndex: sliceInfo.arrInfo.typeIndex,
1957
+ };
1958
+ const sliceW = {
1959
+ kind: "ref",
1960
+ nullable: true,
1961
+ typeIndex: sliceInfo.typeIndex,
1962
+ };
1963
+
1964
+ const srcSliceTmp = this.acquireTemp(sliceW);
1965
+ this.pushInstruction({ op: "local.get", index: rTmp });
1966
+ this.pushInstruction({
1967
+ op: "struct.get",
1968
+ typeIndex: structInfo.typeIndex,
1969
+ fieldIndex: 0,
1970
+ });
1971
+ this.pushInstruction({ op: "local.set", index: srcSliceTmp });
1972
+
1973
+ const srcArrTmp = this.acquireTemp(arrW);
1974
+ const srcOffTmp = this.acquireTemp("i32");
1975
+ const srcLenTmp = this.acquireTemp("i32");
1976
+ const srcCapTmp = this.acquireTemp("i32");
1977
+ this._emitSliceUnpack(srcSliceTmp, sliceInfo, {
1978
+ arr: srcArrTmp,
1979
+ off: srcOffTmp,
1980
+ len: srcLenTmp,
1981
+ cap: srcCapTmp,
1982
+ });
1983
+ this.releaseTemp(srcSliceTmp, sliceW);
1984
+
1985
+ const posTmp = this.acquireTemp("i64");
1986
+ this.pushInstruction({ op: "local.get", index: rTmp });
1987
+ this.pushInstruction({
1988
+ op: "struct.get",
1989
+ typeIndex: structInfo.typeIndex,
1990
+ fieldIndex: 1,
1991
+ });
1992
+ this.pushInstruction({ op: "local.set", index: posTmp });
1993
+
1994
+ const resNTmp = this.acquireTemp("i64");
1995
+ const resErrTmp = this.acquireTemp("anyref");
1996
+
1997
+ this.pushInstruction({ op: "local.get", index: posTmp });
1998
+ this.pushInstruction({ op: "local.get", index: srcLenTmp });
1999
+ this.pushInstruction("i64.extend_i32_u");
2000
+ this.pushInstruction("i64.ge_s");
2001
+ this.pushInstruction({ op: "if", blockType: "void" });
2002
+ this.pushInstruction({ op: "i64.const", value: 0n });
2003
+ this.pushInstruction({ op: "local.set", index: resNTmp });
2004
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
2005
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
2006
+ this.pushInstruction("else");
2007
+
2008
+ const remLenTmp = this.acquireTemp("i32");
2009
+ this.pushInstruction({ op: "local.get", index: srcLenTmp });
2010
+ this.pushInstruction({ op: "local.get", index: posTmp });
2011
+ this.pushInstruction("i32.wrap_i64");
2012
+ this.pushInstruction("i32.sub");
2013
+ this.pushInstruction({ op: "local.set", index: remLenTmp });
2014
+
2015
+ const subsliceTmp = this.acquireTemp(sliceW);
2016
+ this.pushInstruction({ op: "local.get", index: srcArrTmp });
2017
+ this.pushInstruction({ op: "local.get", index: srcOffTmp });
2018
+ this.pushInstruction({ op: "local.get", index: posTmp });
2019
+ this.pushInstruction("i32.wrap_i64");
2020
+ this.pushInstruction("i32.add");
2021
+ this.pushInstruction({ op: "local.get", index: remLenTmp });
2022
+ this.pushInstruction({ op: "local.get", index: srcCapTmp });
2023
+ this.pushInstruction({ op: "local.get", index: posTmp });
2024
+ this.pushInstruction("i32.wrap_i64");
2025
+ this.pushInstruction("i32.sub");
2026
+ this.pushInstruction({
2027
+ op: "struct.new",
2028
+ typeIndex: sliceInfo.typeIndex,
2029
+ });
2030
+ this.pushInstruction({ op: "local.set", index: subsliceTmp });
2031
+
2032
+ const dispatchWriteIdx = this.mod.resolveFuncIndex(
2033
+ "__dispatch_io.Writer_Write",
2034
+ );
2035
+ this.pushInstruction({ op: "local.get", index: wTmp });
2036
+ this.pushInstruction({ op: "local.get", index: subsliceTmp });
2037
+ if (dispatchWriteIdx !== null) {
2038
+ this.pushInstruction({ op: "call", funcIndex: dispatchWriteIdx });
2039
+ } else {
2040
+ this.pushInstruction({ op: "i64.const", value: 0n });
2041
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
2042
+ }
2043
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
2044
+ this.pushInstruction({ op: "local.set", index: resNTmp });
2045
+
2046
+ this.pushInstruction({ op: "local.get", index: rTmp });
2047
+ this.pushInstruction({ op: "local.get", index: posTmp });
2048
+ this.pushInstruction({ op: "local.get", index: resNTmp });
2049
+ this.pushInstruction("i64.add");
2050
+ this.pushInstruction({
2051
+ op: "struct.set",
2052
+ typeIndex: structInfo.typeIndex,
2053
+ fieldIndex: 1,
2054
+ });
2055
+
2056
+ if (structInfo.fields.length > 2) {
2057
+ this.pushInstruction({ op: "local.get", index: rTmp });
2058
+ this.pushInstruction({ op: "i64.const", value: -1n });
2059
+ this.pushInstruction({
2060
+ op: "struct.set",
2061
+ typeIndex: structInfo.typeIndex,
2062
+ fieldIndex: 2,
2063
+ });
2064
+ }
2065
+
2066
+ this.releaseTemp(subsliceTmp, sliceW);
2067
+ this.releaseTemp(remLenTmp, "i32");
2068
+ this.pushInstruction("end");
2069
+
2070
+ this.pushInstruction({ op: "local.get", index: resNTmp });
2071
+ this.pushInstruction({ op: "local.get", index: resErrTmp });
2072
+
2073
+ this.releaseTemp(resErrTmp, "anyref");
2074
+ this.releaseTemp(resNTmp, "i64");
2075
+ this.releaseTemp(posTmp, "i64");
2076
+ this.releaseTemp(srcCapTmp, "i32");
2077
+ this.releaseTemp(srcLenTmp, "i32");
2078
+ this.releaseTemp(srcOffTmp, "i32");
2079
+ this.releaseTemp(srcArrTmp, arrW);
2080
+ this.releaseTemp(wTmp, "anyref");
2081
+ this.releaseTemp(rTmp, readerW);
2082
+ }
2083
+
2084
+ emitFprintCall(fn, call, _targetWasmType) {
2085
+ const wExpr = call.args[0];
2086
+ const strTmp = this.acquireTemp("externref");
2087
+ this._emitFprintFormatString(fn, call.args.slice(1));
2088
+ this.pushInstruction({ op: "local.set", index: strTmp });
2089
+
2090
+ const wType = wExpr._type;
2091
+ const targetName =
2092
+ wType?.name ?? (wType?.kind === "pointer" ? wType.base?.name : null);
2093
+ if (targetName === "strings.Builder") {
2094
+ // Builder.WriteString
2095
+ const builderInfo = this.mod.getStructType("strings.Builder");
2096
+ const builderW = {
2097
+ kind: "ref",
2098
+ nullable: true,
2099
+ typeIndex: builderInfo.typeIndex,
2100
+ };
2101
+ const bTmp = this.acquireTemp(builderW);
2102
+ this.emitExpr(wExpr, builderW);
2103
+ this.pushInstruction({ op: "local.set", index: bTmp });
2104
+ this._emitBuilderWriteStringCore(bTmp, strTmp);
2105
+ this.releaseTemp(bTmp, builderW);
2106
+ this.pushInstruction({ op: "local.get", index: strTmp });
2107
+ this.pushInstruction({
2108
+ op: "call",
2109
+ funcIndex: this.mod.getStringLenImportIndex(),
2110
+ });
2111
+ this.pushInstruction("i64.extend_i32_u");
2112
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
2113
+ this.releaseTemp(strTmp, "externref");
2114
+ return;
2115
+ }
2116
+ if (targetName === "bytes.Buffer") {
2117
+ const bufInfo = this.mod.getStructType("bytes.Buffer");
2118
+ const bufW = {
2119
+ kind: "ref",
2120
+ nullable: true,
2121
+ typeIndex: bufInfo.typeIndex,
2122
+ };
2123
+ const bTmp = this.acquireTemp(bufW);
2124
+ this.emitExpr(wExpr, bufW);
2125
+ this.pushInstruction({ op: "local.set", index: bTmp });
2126
+ this._emitBufferWriteStringCore(bTmp, strTmp);
2127
+ this.releaseTemp(bTmp, bufW);
2128
+ this.pushInstruction({ op: "local.get", index: strTmp });
2129
+ this.pushInstruction({
2130
+ op: "call",
2131
+ funcIndex: this.mod.getStringLenImportIndex(),
2132
+ });
2133
+ this.pushInstruction("i64.extend_i32_u");
2134
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
2135
+ this.releaseTemp(strTmp, "externref");
2136
+ return;
2137
+ }
2138
+
2139
+ this._emitWriterWrite(wExpr, strTmp);
2140
+ this.releaseTemp(strTmp, "externref");
2141
+ }
2142
+
2143
+ _emitFprintFormatString(fn, restArgs) {
2144
+ if (fn === "Fprintf") {
2145
+ const [format, ...rest] = restArgs;
2146
+ const temps = this._emitArgBuffer(
2147
+ rest,
2148
+ false,
2149
+ this._fmtNeedsTypes(format, rest),
2150
+ );
2151
+ this.emitExpr(format, "externref");
2152
+ this._callStdlib("fmt_sprintf");
2153
+ this._releaseArgBuffer(temps);
2154
+ return;
2155
+ }
2156
+ const argc = restArgs.length;
2157
+ if (argc === 0) {
2158
+ const s = fn === "Fprintln" ? "\n" : "";
2159
+ const strIdx = this.mod.internString(s);
2160
+ this.pushInstruction({ op: "i32.const", value: strIdx });
2161
+ this.pushInstruction({
2162
+ op: "call",
2163
+ funcIndex: this.mod.getStringImportIndex(),
2164
+ });
2165
+ return;
2166
+ }
2167
+ const sep = fn === "Fprintln" ? " " : "";
2168
+ const suffix = fn === "Fprintln" ? "\n" : "";
2169
+ const fmt = Array(argc).fill("%v").join(sep) + suffix;
2170
+ const temps = this._emitArgBuffer(restArgs);
2171
+ const strIdx = this.mod.internString(fmt);
2172
+ this.pushInstruction({ op: "i32.const", value: strIdx });
2173
+ this.pushInstruction({
2174
+ op: "call",
2175
+ funcIndex: this.mod.getStringImportIndex(),
2176
+ });
2177
+ this._callStdlib("fmt_sprintf");
2178
+ this._releaseArgBuffer(temps);
2179
+ }
2180
+
2181
+ emitSscanCall(fn, call, _targetWasmType) {
2182
+ const strArg = call.args[0];
2183
+ const mode = fn === "Sscanln" ? 1 : 0;
2184
+ const ptrs = fn === "Sscanf" ? call.args.slice(2) : call.args.slice(1);
2185
+
2186
+ if (fn === "Sscanf") {
2187
+ this.emitExpr(strArg, "externref");
2188
+ this.emitExpr(call.args[1], "externref");
2189
+ this._callStdlib("fmt_sscanf_init");
2190
+ } else {
2191
+ this.emitExpr(strArg, "externref");
2192
+ this.pushInstruction({ op: "i32.const", value: mode });
2193
+ this._callStdlib("fmt_sscan_init");
2194
+ }
2195
+ const totTokensTmp = this.acquireTemp("i32");
2196
+ this.pushInstruction({ op: "local.set", index: totTokensTmp });
2197
+
2198
+ const nTmp = this.acquireTemp("i64");
2199
+ this.pushInstruction({ op: "i64.const", value: 0n });
2200
+ this.pushInstruction({ op: "local.set", index: nTmp });
2201
+
2202
+ const isSpread = ptrs.length === 1 && (ptrs[0]._spread || ptrs[0].ellipsis);
2203
+ const sliceLenTmp = isSpread ? this.acquireTemp("i32") : null;
2204
+
2205
+ if (isSpread) {
2206
+ this._emitSscanAssignSpread(ptrs[0], totTokensTmp, nTmp, sliceLenTmp);
2207
+ } else {
2208
+ for (let i = 0; i < ptrs.length; i++) {
2209
+ this._emitSscanAssignOne(ptrs[i], i, totTokensTmp, nTmp);
2210
+ }
2211
+ }
2212
+
2213
+ // return (n: i64, err: anyref)
2214
+ this.pushInstruction({ op: "local.get", index: nTmp });
2215
+
2216
+ this._callStdlib("fmt_sscan_has_err");
2217
+ this.pushInstruction({ op: "if", blockType: "anyref" });
2218
+ this._callStdlib("fmt_sscan_err_msg");
2219
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
2220
+ this.pushInstruction({
2221
+ op: "call",
2222
+ funcIndex: this.mod.resolveFuncIndex("__mk_error"),
2223
+ });
2224
+ this.pushInstruction("else");
2225
+ this.pushInstruction({ op: "local.get", index: nTmp });
2226
+ if (isSpread) {
2227
+ this.pushInstruction({ op: "local.get", index: sliceLenTmp });
2228
+ this.pushInstruction("i64.extend_i32_u");
2229
+ } else {
2230
+ this.pushInstruction({ op: "i64.const", value: BigInt(ptrs.length) });
2231
+ }
2232
+ this.pushInstruction("i64.lt_s");
2233
+ this.pushInstruction({ op: "if", blockType: "anyref" });
2234
+ const strIdx = this.mod.internString("unexpected EOF");
2235
+ this.pushInstruction({ op: "i32.const", value: strIdx });
2236
+ this.pushInstruction({
2237
+ op: "call",
2238
+ funcIndex: this.mod.getStringImportIndex(),
2239
+ });
2240
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
2241
+ this.pushInstruction({
2242
+ op: "call",
2243
+ funcIndex: this.mod.resolveFuncIndex("__mk_error"),
2244
+ });
2245
+ this.pushInstruction("else");
2246
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
2247
+ this.pushInstruction("end");
2248
+ this.pushInstruction("end");
2249
+
2250
+ if (sliceLenTmp !== null) this.releaseTemp(sliceLenTmp, "i32");
2251
+ this.releaseTemp(nTmp, "i64");
2252
+ this.releaseTemp(totTokensTmp, "i32");
2253
+ }
2254
+
2255
+ _emitSscanAssignSpread(sliceNode, totTokensTmp, nTmp, sliceLenTmp) {
2256
+ const sliceGoType = sliceNode._type ?? {
2257
+ kind: "slice",
2258
+ elem: { kind: "basic", name: "any" },
2259
+ };
2260
+ const sliceWType = this.toWasmType(sliceGoType);
2261
+ const sliceInfo = this.mod.getSliceType(sliceGoType.elem);
2262
+ const arrInfo = this.mod.getArrayType(sliceGoType.elem);
2263
+ const sliceTmp = this.acquireTemp(sliceWType);
2264
+ this.emitExpr(sliceNode, sliceWType);
2265
+ this.pushInstruction({ op: "local.set", index: sliceTmp });
2266
+
2267
+ // Read slice.len (field 2)
2268
+ this.pushInstruction({ op: "local.get", index: sliceTmp });
2269
+ this.pushInstruction({
2270
+ op: "struct.get",
2271
+ typeIndex: sliceInfo.typeIndex,
2272
+ fieldIndex: 2,
2273
+ });
2274
+ this.pushInstruction({ op: "local.set", index: sliceLenTmp });
2275
+
2276
+ // Loop index i = 0
2277
+ const idxTmp = this.acquireTemp("i32");
2278
+ this.pushInstruction({ op: "i32.const", value: 0 });
2279
+ this.pushInstruction({ op: "local.set", index: idxTmp });
2280
+
2281
+ // Loop: block $exit, loop $loop
2282
+ this.pushInstruction({ op: "block", blockType: "void" });
2283
+ this.pushInstruction({ op: "loop", blockType: "void" });
2284
+
2285
+ // if i >= sliceLen, break $exit
2286
+ this.pushInstruction({ op: "local.get", index: idxTmp });
2287
+ this.pushInstruction({ op: "local.get", index: sliceLenTmp });
2288
+ this.pushInstruction("i32.ge_s");
2289
+ this.pushInstruction({ op: "br_if", depth: 1 });
2290
+
2291
+ // if i >= totTokens, break $exit
2292
+ this.pushInstruction({ op: "local.get", index: idxTmp });
2293
+ this.pushInstruction({ op: "local.get", index: totTokensTmp });
2294
+ this.pushInstruction("i32.ge_s");
2295
+ this.pushInstruction({ op: "br_if", depth: 1 });
2296
+
2297
+ // check fmt_sscan_has_err
2298
+ this._callStdlib("fmt_sscan_has_err");
2299
+ this.pushInstruction({ op: "br_if", depth: 1 });
2300
+
2301
+ // Load ptr = slice.data[slice.offset + i]
2302
+ this.pushInstruction({ op: "local.get", index: sliceTmp });
2303
+ this.pushInstruction({
2304
+ op: "struct.get",
2305
+ typeIndex: sliceInfo.typeIndex,
2306
+ fieldIndex: 0,
2307
+ });
2308
+ this.pushInstruction({ op: "local.get", index: sliceTmp });
2309
+ this.pushInstruction({
2310
+ op: "struct.get",
2311
+ typeIndex: sliceInfo.typeIndex,
2312
+ fieldIndex: 1,
2313
+ });
2314
+ this.pushInstruction({ op: "local.get", index: idxTmp });
2315
+ this.pushInstruction("i32.add");
2316
+ this.pushInstruction({
2317
+ op: "array.get",
2318
+ typeIndex: arrInfo.typeIndex,
2319
+ });
2320
+
2321
+ const elemTmp = this.acquireTemp("anyref");
2322
+ this.pushInstruction({ op: "local.set", index: elemTmp });
2323
+
2324
+ // Test and write to the box
2325
+ this._emitSscanWriteAny(elemTmp, idxTmp, nTmp);
2326
+
2327
+ this.releaseTemp(elemTmp, "anyref");
2328
+
2329
+ // i++
2330
+ this.pushInstruction({ op: "local.get", index: idxTmp });
2331
+ this.pushInstruction({ op: "i32.const", value: 1 });
2332
+ this.pushInstruction("i32.add");
2333
+ this.pushInstruction({ op: "local.set", index: idxTmp });
2334
+
2335
+ // loop again
2336
+ this.pushInstruction({ op: "br", depth: 0 });
2337
+ this.pushInstruction("end"); // loop
2338
+ this.pushInstruction("end"); // block
2339
+
2340
+ this.releaseTemp(idxTmp, "i32");
2341
+ this.releaseTemp(sliceTmp, sliceWType);
2342
+ }
2343
+
2344
+ _emitSscanWriteAny(elemTmp, idxTmp, nTmp) {
2345
+ const types = [
2346
+ {
2347
+ goType: { kind: "basic", name: "int" },
2348
+ call: "fmt_sscan_token_i64",
2349
+ wrap: null,
2350
+ },
2351
+ {
2352
+ goType: { kind: "basic", name: "int64" },
2353
+ call: "fmt_sscan_token_i64",
2354
+ wrap: null,
2355
+ },
2356
+ {
2357
+ goType: { kind: "basic", name: "uint" },
2358
+ call: "fmt_sscan_token_i64",
2359
+ wrap: null,
2360
+ },
2361
+ {
2362
+ goType: { kind: "basic", name: "uint64" },
2363
+ call: "fmt_sscan_token_i64",
2364
+ wrap: null,
2365
+ },
2366
+ {
2367
+ goType: { kind: "basic", name: "uintptr" },
2368
+ call: "fmt_sscan_token_i64",
2369
+ wrap: null,
2370
+ },
2371
+ {
2372
+ goType: { kind: "basic", name: "int32" },
2373
+ call: "fmt_sscan_token_i64",
2374
+ wrap: "i32.wrap_i64",
2375
+ },
2376
+ {
2377
+ goType: { kind: "basic", name: "uint32" },
2378
+ call: "fmt_sscan_token_i64",
2379
+ wrap: "i32.wrap_i64",
2380
+ },
2381
+ {
2382
+ goType: { kind: "basic", name: "int16" },
2383
+ call: "fmt_sscan_token_i64",
2384
+ wrap: "i32.wrap_i64",
2385
+ },
2386
+ {
2387
+ goType: { kind: "basic", name: "uint16" },
2388
+ call: "fmt_sscan_token_i64",
2389
+ wrap: "i32.wrap_i64",
2390
+ },
2391
+ {
2392
+ goType: { kind: "basic", name: "int8" },
2393
+ call: "fmt_sscan_token_i64",
2394
+ wrap: "i32.wrap_i64",
2395
+ },
2396
+ {
2397
+ goType: { kind: "basic", name: "uint8" },
2398
+ call: "fmt_sscan_token_i64",
2399
+ wrap: "i32.wrap_i64",
2400
+ },
2401
+ {
2402
+ goType: { kind: "basic", name: "float64" },
2403
+ call: "fmt_sscan_token_f64",
2404
+ wrap: null,
2405
+ },
2406
+ {
2407
+ goType: { kind: "basic", name: "float32" },
2408
+ call: "fmt_sscan_token_f64",
2409
+ wrap: "f32.demote_f64",
2410
+ },
2411
+ {
2412
+ goType: { kind: "basic", name: "string" },
2413
+ call: "fmt_sscan_token_str",
2414
+ wrap: null,
2415
+ },
2416
+ {
2417
+ goType: { kind: "basic", name: "bool" },
2418
+ call: "fmt_sscan_token_bool",
2419
+ wrap: null,
2420
+ },
2421
+ ];
2422
+
2423
+ let ends = 0;
2424
+ for (const { goType, call, wrap } of types) {
2425
+ const ptrGoType = { kind: "pointer", base: goType };
2426
+ const ifaceBox = this.mod.getIfaceBoxType(ptrGoType);
2427
+ const scalarBox = this.mod.getBoxType(goType);
2428
+
2429
+ // Arm 1: wrapped in ifaceBox
2430
+ this.pushInstruction({ op: "local.get", index: elemTmp });
2431
+ this.pushInstruction({ op: "ref.test", typeIndex: ifaceBox.typeIndex });
2432
+ this.pushInstruction({ op: "if", blockType: "void" });
2433
+ this.pushInstruction({ op: "local.get", index: elemTmp });
2434
+ this.pushInstruction({ op: "ref.cast", typeIndex: ifaceBox.typeIndex });
2435
+ this.pushInstruction({
2436
+ op: "struct.get",
2437
+ typeIndex: ifaceBox.typeIndex,
2438
+ fieldIndex: 0,
2439
+ });
2440
+ this.pushInstruction({ op: "ref.cast", typeIndex: scalarBox.typeIndex });
2441
+ this.pushInstruction({ op: "local.get", index: idxTmp });
2442
+ this._callStdlib(call);
2443
+ if (wrap) this.pushInstruction(wrap);
2444
+ this.pushInstruction({
2445
+ op: "struct.set",
2446
+ typeIndex: scalarBox.typeIndex,
2447
+ fieldIndex: 0,
2448
+ });
2449
+ this._emitIncrementN(nTmp);
2450
+ this.pushInstruction("else");
2451
+ ends++;
2452
+
2453
+ // Arm 2: bare scalarBox
2454
+ this.pushInstruction({ op: "local.get", index: elemTmp });
2455
+ this.pushInstruction({ op: "ref.test", typeIndex: scalarBox.typeIndex });
2456
+ this.pushInstruction({ op: "if", blockType: "void" });
2457
+ this.pushInstruction({ op: "local.get", index: elemTmp });
2458
+ this.pushInstruction({ op: "ref.cast", typeIndex: scalarBox.typeIndex });
2459
+ this.pushInstruction({ op: "local.get", index: idxTmp });
2460
+ this._callStdlib(call);
2461
+ if (wrap) this.pushInstruction(wrap);
2462
+ this.pushInstruction({
2463
+ op: "struct.set",
2464
+ typeIndex: scalarBox.typeIndex,
2465
+ fieldIndex: 0,
2466
+ });
2467
+ this._emitIncrementN(nTmp);
2468
+ this.pushInstruction("else");
2469
+ ends++;
2470
+ }
2471
+
2472
+ for (let i = 0; i < ends; i++) {
2473
+ this.pushInstruction("end");
2474
+ }
2475
+ }
2476
+
2477
+ _emitIncrementN(nTmp) {
2478
+ this._callStdlib("fmt_sscan_has_err");
2479
+ this.pushInstruction({ op: "if", blockType: "void" });
2480
+ this.pushInstruction("else");
2481
+ this.pushInstruction({ op: "local.get", index: nTmp });
2482
+ this.pushInstruction({ op: "i64.const", value: 1n });
2483
+ this.pushInstruction("i64.add");
2484
+ this.pushInstruction({ op: "local.set", index: nTmp });
2485
+ this.pushInstruction("end");
2486
+ }
2487
+
2488
+ _emitSscanAssignOne(pExpr, tokenIdx, totTokensTmp, nTmp) {
2489
+ this.pushInstruction({ op: "i32.const", value: tokenIdx });
2490
+ this.pushInstruction({ op: "local.get", index: totTokensTmp });
2491
+ this.pushInstruction("i32.lt_s");
2492
+ this.pushInstruction({ op: "if", blockType: "void" });
2493
+
2494
+ this._callStdlib("fmt_sscan_has_err");
2495
+ this.pushInstruction({ op: "if", blockType: "void" });
2496
+ this.pushInstruction("else");
2497
+
2498
+ this._emitSscanWriteToken(pExpr, tokenIdx);
2499
+
2500
+ this._callStdlib("fmt_sscan_has_err");
2501
+ this.pushInstruction({ op: "if", blockType: "void" });
2502
+ this.pushInstruction("else");
2503
+ this.pushInstruction({ op: "local.get", index: nTmp });
2504
+ this.pushInstruction({ op: "i64.const", value: 1n });
2505
+ this.pushInstruction("i64.add");
2506
+ this.pushInstruction({ op: "local.set", index: nTmp });
2507
+ this.pushInstruction("end");
2508
+
2509
+ this.pushInstruction("end");
2510
+ this.pushInstruction("end");
2511
+ }
2512
+
2513
+ _emitSscanWriteToken(pExpr, tokenIdx) {
2514
+ const isAddressOf = pExpr.kind === "UnaryExpr" && pExpr.op === "&";
2515
+ const pType =
2516
+ pExpr._type ??
2517
+ (pExpr.kind === "Ident" ? this.resolveLocal(pExpr.name)?.goType : null) ??
1181
2518
  this._resolveExprGoType(pExpr);
1182
2519
  const pointeeType = pType?.base ?? pType;
1183
2520
  const targetNode = isAddressOf
@@ -1287,6 +2624,18 @@ export class IoEmitter {
1287
2624
  case "sha256_block_size":
1288
2625
  this._emitHelperSha256BlockSize(fn);
1289
2626
  return;
2627
+ case "os_file_write":
2628
+ this._emitHelperOsFileWrite(fn);
2629
+ return;
2630
+ case "os_file_write_string":
2631
+ this._emitHelperOsFileWriteString(fn);
2632
+ return;
2633
+ case "os_file_read":
2634
+ this._emitHelperOsFileRead(fn);
2635
+ return;
2636
+ case "os_file_close":
2637
+ this._emitHelperOsFileClose(fn);
2638
+ return;
1290
2639
  default:
1291
2640
  throw new Error(`Unknown io helper: ${kind}`);
1292
2641
  }
@@ -1585,6 +2934,15 @@ export class IoEmitter {
1585
2934
  typeIndex: structInfo.typeIndex,
1586
2935
  fieldIndex: 0,
1587
2936
  });
2937
+ if (structInfo.fields.length > 1) {
2938
+ this.pushInstruction({ op: "local.get", index: bTmp });
2939
+ this.pushInstruction({ op: "i64.const", value: 0n });
2940
+ this.pushInstruction({
2941
+ op: "struct.set",
2942
+ typeIndex: structInfo.typeIndex,
2943
+ fieldIndex: 1,
2944
+ });
2945
+ }
1588
2946
 
1589
2947
  this.pushInstruction({ op: "local.get", index: pLenTmp });
1590
2948
  this.pushInstruction("i64.extend_i32_u");
@@ -1694,6 +3052,15 @@ export class IoEmitter {
1694
3052
  this.emitIoConst("EOF", "anyref");
1695
3053
  this.pushInstruction("end");
1696
3054
  this.pushInstruction({ op: "local.set", index: resErrTmp });
3055
+ if (structInfo.fields.length > 1) {
3056
+ this.pushInstruction({ op: "local.get", index: bTmp });
3057
+ this.pushInstruction({ op: "i64.const", value: 0n });
3058
+ this.pushInstruction({
3059
+ op: "struct.set",
3060
+ typeIndex: structInfo.typeIndex,
3061
+ fieldIndex: 1,
3062
+ });
3063
+ }
1697
3064
  this.pushInstruction("else");
1698
3065
 
1699
3066
  // n = min(p.len, srcLen)
@@ -1737,6 +3104,15 @@ export class IoEmitter {
1737
3104
  typeIndex: structInfo.typeIndex,
1738
3105
  fieldIndex: 0,
1739
3106
  });
3107
+ if (structInfo.fields.length > 1) {
3108
+ this.pushInstruction({ op: "local.get", index: bTmp });
3109
+ this.pushInstruction({ op: "i64.const", value: 1n });
3110
+ this.pushInstruction({
3111
+ op: "struct.set",
3112
+ typeIndex: structInfo.typeIndex,
3113
+ fieldIndex: 1,
3114
+ });
3115
+ }
1740
3116
 
1741
3117
  this.pushInstruction({ op: "local.get", index: nTmp });
1742
3118
  this.pushInstruction("i64.extend_i32_u");
@@ -1817,6 +3193,47 @@ export class IoEmitter {
1817
3193
  this.pushInstruction("return");
1818
3194
  }
1819
3195
 
3196
+ _emitHelperOsFileWriteString(_fn) {
3197
+ this.pushInstruction({ op: "local.get", index: 1 });
3198
+ this._callStdlib("fmt_print_raw");
3199
+ this.pushInstruction({ op: "local.get", index: 1 });
3200
+ this.pushInstruction({
3201
+ op: "call",
3202
+ funcIndex: this.mod.getStringLenImportIndex(),
3203
+ });
3204
+ this.pushInstruction("i64.extend_i32_u");
3205
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
3206
+ this.pushInstruction("return");
3207
+ }
3208
+
3209
+ _emitHelperOsFileWrite(_fn) {
3210
+ this.pushInstruction({ op: "local.get", index: 1 });
3211
+ this._emitByteSliceToString({ elem: { kind: "basic", name: "byte" } });
3212
+ this._callStdlib("fmt_print_raw");
3213
+ const byteElemGo = { kind: "basic", name: "byte" };
3214
+ const sliceInfo = this.mod.getSliceType(byteElemGo);
3215
+ this.pushInstruction({ op: "local.get", index: 1 });
3216
+ this.pushInstruction({
3217
+ op: "struct.get",
3218
+ typeIndex: sliceInfo.typeIndex,
3219
+ fieldIndex: 2,
3220
+ });
3221
+ this.pushInstruction("i64.extend_i32_u");
3222
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
3223
+ this.pushInstruction("return");
3224
+ }
3225
+
3226
+ _emitHelperOsFileRead(_fn) {
3227
+ this.pushInstruction({ op: "i64.const", value: 0n });
3228
+ this._emitLazyErrorGlobal(this.mod.getIoErrGlobalIndex("EOF"), "EOF");
3229
+ this.pushInstruction("return");
3230
+ }
3231
+
3232
+ _emitHelperOsFileClose(_fn) {
3233
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
3234
+ this.pushInstruction("return");
3235
+ }
3236
+
1820
3237
  _emitHelperLimitedReaderRead(_fn) {
1821
3238
  this._emitLimitedReaderReadCore(0, 1);
1822
3239
  this.pushInstruction("return");