gofront 1.6.0 → 1.7.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 (80) hide show
  1. package/README.md +35 -39
  2. package/package.json +37 -4
  3. package/src/backend/js/expressions.js +559 -144
  4. package/src/backend/js/index.js +174 -49
  5. package/src/backend/js/runtime.js +1518 -54
  6. package/src/backend/js/statements.js +91 -73
  7. package/src/backend/js/stdlib/base64.js +12 -0
  8. package/src/backend/js/stdlib/binary.js +102 -0
  9. package/src/backend/js/stdlib/bits.js +15 -1
  10. package/src/backend/js/stdlib/builder.js +28 -9
  11. package/src/backend/js/stdlib/bytes.js +75 -18
  12. package/src/backend/js/stdlib/errors.js +25 -1
  13. package/src/backend/js/stdlib/fmt.js +70 -13
  14. package/src/backend/js/stdlib/hex.js +17 -0
  15. package/src/backend/js/stdlib/html.js +1 -1
  16. package/src/backend/js/stdlib/index.js +28 -0
  17. package/src/backend/js/stdlib/io.js +105 -3
  18. package/src/backend/js/stdlib/json.js +972 -0
  19. package/src/backend/js/stdlib/math.js +13 -1
  20. package/src/backend/js/stdlib/path.js +18 -4
  21. package/src/backend/js/stdlib/rand.js +10 -5
  22. package/src/backend/js/stdlib/sha256.js +12 -0
  23. package/src/backend/js/stdlib/simd.js +24 -0
  24. package/src/backend/js/stdlib/slices.js +52 -26
  25. package/src/backend/js/stdlib/strconv.js +21 -5
  26. package/src/backend/js/stdlib/strings.js +148 -15
  27. package/src/backend/js/stdlib/sync.js +13 -0
  28. package/src/backend/js/stdlib/time.js +90 -19
  29. package/src/backend/js/stdlib/unicode.js +2 -2
  30. package/src/backend/wasm/boundary.js +1225 -41
  31. package/src/backend/wasm/const-fold.js +205 -0
  32. package/src/backend/wasm/emit-builtins.js +220 -76
  33. package/src/backend/wasm/emit-exprs.js +475 -276
  34. package/src/backend/wasm/emit-maps.js +144 -8
  35. package/src/backend/wasm/emit-stdlib.js +12 -3005
  36. package/src/backend/wasm/emit-stmts.js +264 -270
  37. package/src/backend/wasm/emit.js +124 -87
  38. package/src/backend/wasm/encode.js +140 -29
  39. package/src/backend/wasm/index.js +1001 -32
  40. package/src/backend/wasm/optimize.js +17 -6
  41. package/src/backend/wasm/stdlib/bytes.js +5039 -0
  42. package/src/backend/wasm/stdlib/core.js +8903 -0
  43. package/src/backend/wasm/stdlib/index.js +43 -0
  44. package/src/backend/wasm/stdlib/io.js +2161 -0
  45. package/src/backend/wasm/stdlib/packages.js +2400 -0
  46. package/src/backend/wasm/stdlib/pure.js +720 -0
  47. package/src/backend/wasm/stdlib/simd.js +234 -0
  48. package/src/backend/wasm/stdlib/time.js +1200 -0
  49. package/src/backend/wasm/types.js +174 -1
  50. package/src/backend/wasm/wat.js +37 -0
  51. package/src/cli-core.js +1 -1
  52. package/src/compiler.js +18 -4
  53. package/src/dts-parser.js +150 -140
  54. package/src/index.js +2 -6
  55. package/src/lexer.js +80 -29
  56. package/src/lower/boxing.js +1 -7
  57. package/src/lower/captures.js +2 -6
  58. package/src/lower/embedding.js +2 -1
  59. package/src/lower/ownership.js +30 -9
  60. package/src/minifier.js +20 -68
  61. package/src/parser/declarations.js +3 -6
  62. package/src/parser/expressions.js +3 -8
  63. package/src/parser/index.js +18 -3
  64. package/src/parser/statements.js +25 -38
  65. package/src/parser/struct-tag.js +144 -0
  66. package/src/parser/types.js +64 -8
  67. package/src/resolver.js +2 -27
  68. package/src/templ-lexer.js +29 -63
  69. package/src/templ-parser.js +22 -45
  70. package/src/typechecker/assignability.js +126 -13
  71. package/src/typechecker/expressions.js +168 -16
  72. package/src/typechecker/index.js +35 -8
  73. package/src/typechecker/resolve.js +187 -8
  74. package/src/typechecker/statements.js +68 -9
  75. package/src/typechecker/stdlib/core.js +280 -89
  76. package/src/typechecker/stdlib/extended.js +490 -1
  77. package/src/typechecker/stdlib/simd.js +73 -0
  78. package/src/typechecker/stdlib.js +2 -0
  79. package/src/typechecker/types.js +362 -9
  80. package/src/vendor.js +86 -11
@@ -0,0 +1,205 @@
1
+ // Compile-time folding of package-level constant expressions for the wasm
2
+ // backend. Folds literals, other already-folded constants, unary/binary
3
+ // operators and `len("literal")` into a single BasicLit. Anything it cannot
4
+ // reduce returns null and the caller falls back to a runtime-initialised
5
+ // global (see `_collectPackageConsts`).
6
+
7
+ const INT = "INT";
8
+ const FLOAT = "FLOAT";
9
+ const STRING = "STRING";
10
+ const BOOL = "BOOL";
11
+
12
+ function fromLit(lit) {
13
+ switch (lit.litKind) {
14
+ case INT: {
15
+ const s = String(lit.value);
16
+ const clean = /^0[0-7]+$/.test(s) ? `0o${s.slice(1)}` : s;
17
+ return { k: INT, v: BigInt(clean) };
18
+ }
19
+ case FLOAT: {
20
+ const n = Number(lit.value);
21
+ return Number.isFinite(n) ? { k: FLOAT, v: n } : null;
22
+ }
23
+ case STRING:
24
+ return { k: STRING, v: String(lit.value ?? "") };
25
+ case BOOL:
26
+ return { k: BOOL, v: lit.value === "true" };
27
+ default:
28
+ return null;
29
+ }
30
+ }
31
+
32
+ function toLit(val) {
33
+ switch (val.k) {
34
+ case INT:
35
+ return { kind: "BasicLit", litKind: INT, value: val.v.toString() };
36
+ case FLOAT:
37
+ return {
38
+ kind: "BasicLit",
39
+ litKind: FLOAT,
40
+ value: Object.is(val.v, -0) ? "-0" : String(val.v),
41
+ };
42
+ case STRING:
43
+ return { kind: "BasicLit", litKind: STRING, value: val.v };
44
+ default:
45
+ return {
46
+ kind: "BasicLit",
47
+ litKind: BOOL,
48
+ value: val.v ? "true" : "false",
49
+ };
50
+ }
51
+ }
52
+
53
+ function asFloat(val) {
54
+ return val.k === INT ? Number(val.v) : val.v;
55
+ }
56
+
57
+ function foldUnary(op, x) {
58
+ if (op === "-" && x.k === INT) return { k: INT, v: -x.v };
59
+ if (op === "-" && x.k === FLOAT) return { k: FLOAT, v: -x.v };
60
+ if (op === "+" && (x.k === INT || x.k === FLOAT)) return x;
61
+ if (op === "!" && x.k === BOOL) return { k: BOOL, v: !x.v };
62
+ if (op === "^" && x.k === INT) return { k: INT, v: ~x.v };
63
+ return null;
64
+ }
65
+
66
+ function compare(op, a, b) {
67
+ switch (op) {
68
+ case "==":
69
+ return a === b;
70
+ case "!=":
71
+ return a !== b;
72
+ case "<":
73
+ return a < b;
74
+ case "<=":
75
+ return a <= b;
76
+ case ">":
77
+ return a > b;
78
+ case ">=":
79
+ return a >= b;
80
+ default:
81
+ return null;
82
+ }
83
+ }
84
+
85
+ function foldInts(op, a, b) {
86
+ switch (op) {
87
+ case "+":
88
+ return { k: INT, v: a + b };
89
+ case "-":
90
+ return { k: INT, v: a - b };
91
+ case "*":
92
+ return { k: INT, v: a * b };
93
+ case "/":
94
+ if (b === 0n) throw new Error("division by zero");
95
+ return { k: INT, v: a / b };
96
+ case "%":
97
+ if (b === 0n) throw new Error("division by zero");
98
+ return { k: INT, v: a % b };
99
+ case "&":
100
+ return { k: INT, v: a & b };
101
+ case "|":
102
+ return { k: INT, v: a | b };
103
+ case "^":
104
+ return { k: INT, v: a ^ b };
105
+ case "&^":
106
+ return { k: INT, v: a & ~b };
107
+ case "<<":
108
+ if (b < 0n) throw new Error("negative shift count");
109
+ return b > 1024n ? null : { k: INT, v: a << b };
110
+ case ">>":
111
+ if (b < 0n) throw new Error("negative shift count");
112
+ return b > 1024n ? null : { k: INT, v: a >> b };
113
+ default: {
114
+ const r = compare(op, a, b);
115
+ return r === null ? null : { k: BOOL, v: r };
116
+ }
117
+ }
118
+ }
119
+
120
+ function foldFloats(op, a, b) {
121
+ let v;
122
+ switch (op) {
123
+ case "+":
124
+ v = a + b;
125
+ break;
126
+ case "-":
127
+ v = a - b;
128
+ break;
129
+ case "*":
130
+ v = a * b;
131
+ break;
132
+ case "/":
133
+ if (b === 0) throw new Error("division by zero");
134
+ v = a / b;
135
+ break;
136
+ default: {
137
+ const r = compare(op, a, b);
138
+ return r === null ? null : { k: BOOL, v: r };
139
+ }
140
+ }
141
+ return Number.isFinite(v) ? { k: FLOAT, v } : null;
142
+ }
143
+
144
+ function foldBinary(op, a, b) {
145
+ if (a.k === BOOL && b.k === BOOL) {
146
+ if (op === "&&") return { k: BOOL, v: a.v && b.v };
147
+ if (op === "||") return { k: BOOL, v: a.v || b.v };
148
+ const r = op === "==" || op === "!=" ? compare(op, a.v, b.v) : null;
149
+ return r === null ? null : { k: BOOL, v: r };
150
+ }
151
+ if (a.k === STRING && b.k === STRING) {
152
+ if (op === "+") return { k: STRING, v: a.v + b.v };
153
+ const r = compare(op, a.v, b.v);
154
+ return r === null ? null : { k: BOOL, v: r };
155
+ }
156
+ if (a.k === INT && b.k === INT) return foldInts(op, a.v, b.v);
157
+ if (
158
+ (a.k === INT || a.k === FLOAT) &&
159
+ (b.k === INT || b.k === FLOAT) &&
160
+ op !== "<<" &&
161
+ op !== ">>"
162
+ ) {
163
+ return foldFloats(op, asFloat(a), asFloat(b));
164
+ }
165
+ return null;
166
+ }
167
+
168
+ function foldExpr(expr, resolve) {
169
+ switch (expr?.kind) {
170
+ case "BasicLit":
171
+ return fromLit(expr);
172
+ case "Ident": {
173
+ if (expr.name === "true" || expr.name === "false")
174
+ return { k: BOOL, v: expr.name === "true" };
175
+ const lit = resolve(expr.name);
176
+ return lit ? fromLit(lit) : null;
177
+ }
178
+ case "UnaryExpr": {
179
+ const x = foldExpr(expr.operand, resolve);
180
+ return x ? foldUnary(expr.op, x) : null;
181
+ }
182
+ case "BinaryExpr": {
183
+ const a = foldExpr(expr.left, resolve);
184
+ const b = a ? foldExpr(expr.right, resolve) : null;
185
+ return a && b ? foldBinary(expr.op, a, b) : null;
186
+ }
187
+ case "CallExpr": {
188
+ if (expr.func?.kind !== "Ident" || expr.func.name !== "len") return null;
189
+ if (expr.args?.length !== 1) return null;
190
+ const s = foldExpr(expr.args[0], resolve);
191
+ if (s?.k !== STRING) return null;
192
+ // Gofront strings across JS and WASM runtime use UTF-16 code units (s.length).
193
+ return { k: INT, v: BigInt(s.v.length) };
194
+ }
195
+ default:
196
+ return null;
197
+ }
198
+ }
199
+
200
+ // Folds `expr` into a BasicLit, or returns null when it needs the runtime.
201
+ // `resolve(name)` yields the BasicLit of an already-folded constant, if any.
202
+ export function foldConstExpr(expr, resolve) {
203
+ const val = foldExpr(expr, resolve);
204
+ return val ? toLit(val) : null;
205
+ }
@@ -65,18 +65,6 @@ export class BuiltinsEmitter {
65
65
  return null;
66
66
  }
67
67
 
68
- _getArrayElemType(t) {
69
- if (!t) return null;
70
- if (t.elem) return t.elem;
71
- if (t.underlying?.elem) return t.underlying.elem;
72
- if (t.kind === "ArrayType") return t.elem;
73
- if (t.name && this.mod.checker?.types?.has(t.name)) {
74
- const resolved = this.mod.checker.types.get(t.name);
75
- return this._getArrayElemType(resolved);
76
- }
77
- return null;
78
- }
79
-
80
68
  _emitBuiltinLen(call, targetWasmType) {
81
69
  const arg = call.args[0];
82
70
  const argType = arg._type ?? this._resolveExprGoType(arg);
@@ -92,12 +80,7 @@ export class BuiltinsEmitter {
92
80
  op: "call",
93
81
  funcIndex: this.mod.resolveFuncIndex(mapInfo.lenFuncName),
94
82
  });
95
- if ((targetWasmType ?? "i64") === "i64") {
96
- this.pushInstruction("i64.extend_i32_u");
97
- }
98
- return;
99
- }
100
- if (isSliceType(argType, this.mod.checker)) {
83
+ } else if (isSliceType(argType, this.mod.checker)) {
101
84
  const elemType = this._getSliceElemType(argType);
102
85
  const sliceInfo = this.mod.getSliceType(elemType);
103
86
  const sliceWType = {
@@ -111,12 +94,7 @@ export class BuiltinsEmitter {
111
94
  typeIndex: sliceInfo.typeIndex,
112
95
  fieldIndex: 2,
113
96
  });
114
- if ((targetWasmType ?? "i64") === "i64") {
115
- this.pushInstruction("i64.extend_i32_u");
116
- }
117
- return;
118
- }
119
- if (
97
+ } else if (
120
98
  isArrayType(argType, this.mod.checker) ||
121
99
  (argType?.kind === "pointer" &&
122
100
  isArrayType(argType.base, this.mod.checker))
@@ -130,19 +108,13 @@ export class BuiltinsEmitter {
130
108
  };
131
109
  this.emitExpr(arg, arrWType);
132
110
  this.pushInstruction("array.len");
133
- if ((targetWasmType ?? "i64") === "i64") {
134
- this.pushInstruction("i64.extend_i32_u");
135
- }
136
- return;
137
- }
138
- if (isStringType(argType, this.mod.checker)) {
111
+ } else if (isStringType(argType, this.mod.checker)) {
139
112
  this.emitExpr(arg, "externref");
140
113
  const lenIdx = this.mod.getStringLenImportIndex();
141
114
  this.pushInstruction({ op: "call", funcIndex: lenIdx });
142
- if ((targetWasmType ?? "i64") === "i64") {
143
- this.pushInstruction("i64.extend_i32_u");
144
- }
145
- return;
115
+ }
116
+ if ((targetWasmType ?? "i64") === "i64") {
117
+ this.pushInstruction("i64.extend_i32_u");
146
118
  }
147
119
  }
148
120
 
@@ -177,12 +149,7 @@ export class BuiltinsEmitter {
177
149
  typeIndex: sliceInfo.typeIndex,
178
150
  fieldIndex: 3,
179
151
  });
180
- if ((targetWasmType ?? "i64") === "i64") {
181
- this.pushInstruction("i64.extend_i32_u");
182
- }
183
- return;
184
- }
185
- if (
152
+ } else if (
186
153
  isArrayType(argType, this.mod.checker) ||
187
154
  (argType?.kind === "pointer" &&
188
155
  isArrayType(argType.base, this.mod.checker))
@@ -196,10 +163,9 @@ export class BuiltinsEmitter {
196
163
  };
197
164
  this.emitExpr(arg, arrWType);
198
165
  this.pushInstruction("array.len");
199
- if ((targetWasmType ?? "i64") === "i64") {
200
- this.pushInstruction("i64.extend_i32_u");
201
- }
202
- return;
166
+ }
167
+ if ((targetWasmType ?? "i64") === "i64") {
168
+ this.pushInstruction("i64.extend_i32_u");
203
169
  }
204
170
  }
205
171
 
@@ -894,12 +860,24 @@ export class BuiltinsEmitter {
894
860
  this.emitSlicesCall(func.field, args, targetWasmType);
895
861
  return true;
896
862
  case "strings":
863
+ if (func.field === "NewReader") {
864
+ this.emitStringsNewReader(call, targetWasmType);
865
+ return true;
866
+ }
897
867
  this.emitStringsCall(func.field, args, targetWasmType);
898
868
  return true;
899
869
  case "strconv":
900
870
  this.emitStrconvCall(func.field, args);
901
871
  return true;
902
872
  case "fmt":
873
+ if (func.field.startsWith("Fprint")) {
874
+ this.emitFprintCall(func.field, call, targetWasmType);
875
+ return true;
876
+ }
877
+ if (func.field.startsWith("Sscan")) {
878
+ this.emitSscanCall(func.field, call, targetWasmType);
879
+ return true;
880
+ }
903
881
  this.emitFmtCall(func.field, args);
904
882
  return true;
905
883
  case "errors":
@@ -914,12 +892,53 @@ export class BuiltinsEmitter {
914
892
  case "shared":
915
893
  this.emitSharedNew(func.field, args);
916
894
  return true;
895
+ case "unicode":
896
+ this.emitUnicodeCall(func.field, args, targetWasmType);
897
+ return true;
898
+ case "rand":
899
+ this.emitRandCall(func.field, args, targetWasmType);
900
+ return true;
901
+ case "bytes":
902
+ if (func.field === "NewReader") {
903
+ this.emitBytesNewReader(call, targetWasmType);
904
+ return true;
905
+ }
906
+ this.emitBytesCall(func.field, args, targetWasmType);
907
+ return true;
908
+ case "path":
909
+ case "filepath":
910
+ this.emitPathCall(func.field, args);
911
+ return true;
912
+ case "html":
913
+ this.emitHtmlCall(func.field, args);
914
+ return true;
915
+ case "io":
916
+ this.emitIoCall(func.field, call, targetWasmType);
917
+ return true;
918
+ case "time":
919
+ this.emitTimeCall(func.field, call, targetWasmType);
920
+ return true;
921
+ case "binary":
922
+ this.emitBinaryCall(func.field, call, targetWasmType);
923
+ return true;
924
+ case "sha256":
925
+ this.emitSha256Call(func.field, call, targetWasmType);
926
+ return true;
927
+ case "hex":
928
+ this.emitHexCall(func.field, call, targetWasmType);
929
+ return true;
930
+ case "base64":
931
+ this.emitBase64Call(func.field, call, targetWasmType);
932
+ return true;
933
+ case "simd":
934
+ this.emitSimdPackageCall(func.field, args, targetWasmType);
935
+ return true;
917
936
  default:
918
937
  return false;
919
938
  }
920
939
  }
921
940
 
922
- _emitMethodCall(call) {
941
+ _emitMethodCall(call, targetWasmType = null) {
923
942
  const { func, args } = call;
924
943
  if (func.kind !== "SelectorExpr") return false;
925
944
 
@@ -930,6 +949,39 @@ export class BuiltinsEmitter {
930
949
  return true;
931
950
  }
932
951
  const recvTypeName = this._getReceiverTypeName(recvType, func.expr);
952
+ if (
953
+ recvTypeName === "simd.F32x4" ||
954
+ recvTypeName === "gofront/simd.F32x4" ||
955
+ recvType?.kind === "simd" ||
956
+ recvType?.underlying?.kind === "simd" ||
957
+ recvType?.name === "simd.F32x4"
958
+ ) {
959
+ return this.emitSimdMethodCall(
960
+ func.field,
961
+ func.expr,
962
+ args,
963
+ targetWasmType,
964
+ );
965
+ }
966
+ if (
967
+ this._emitStdlibReceiverMethod(
968
+ recvTypeName,
969
+ func.field,
970
+ func.expr,
971
+ args,
972
+ targetWasmType,
973
+ )
974
+ ) {
975
+ return true;
976
+ }
977
+ if (recvTypeName === "strings.Builder") {
978
+ this.emitBuilderMethodCall(func.field, func.expr, args);
979
+ return true;
980
+ }
981
+ if (recvTypeName === "strings.Replacer") {
982
+ this.emitReplacerMethodCall(func.field, func.expr, args);
983
+ return true;
984
+ }
933
985
  if (isNonEmptyInterface(recvType, this.mod.checker)) {
934
986
  const ifaceName = recvTypeName ?? "anon";
935
987
  const dispatchName = `__dispatch_${ifaceName}_${func.field}`;
@@ -950,38 +1002,15 @@ export class BuiltinsEmitter {
950
1002
  }
951
1003
  if (recvTypeName) {
952
1004
  const methodName = `${recvTypeName}.${func.field}`;
953
- let targetFuncIdx = this.mod.resolveFuncIndex(methodName);
954
- let targetParamTypes = this.mod.getFuncParamTypes(methodName);
1005
+ const targetFuncIdx = this.mod.resolveFuncIndex(methodName);
1006
+ const targetParamTypes = this.mod.getFuncParamTypes(methodName);
955
1007
 
956
1008
  // If not found directly, check embedded structs
957
- if (targetFuncIdx === null) {
958
- const structInfo = this.mod.getStructType(recvTypeName);
959
- if (structInfo) {
960
- for (const embed of structInfo.embeds) {
961
- const embedMethodName = `${embed.name}.${func.field}`;
962
- const subIdx = this.mod.resolveFuncIndex(embedMethodName);
963
- if (subIdx !== null) {
964
- targetFuncIdx = subIdx;
965
- targetParamTypes = this.mod.getFuncParamTypes(embedMethodName);
966
- const baseWType = this.toWasmType(recvType);
967
- this.emitExpr(func.expr, baseWType);
968
- this.pushInstruction({
969
- op: "struct.get",
970
- typeIndex: structInfo.typeIndex,
971
- fieldIndex: embed.fieldIndex,
972
- });
973
- for (let i = 0; i < args.length; i++) {
974
- const pType = targetParamTypes[i + 1] ?? null;
975
- this.emitExpr(args[i], pType);
976
- }
977
- this.pushInstruction({
978
- op: "call",
979
- funcIndex: targetFuncIdx,
980
- });
981
- return true;
982
- }
983
- }
984
- }
1009
+ if (
1010
+ targetFuncIdx === null &&
1011
+ this._emitEmbeddedMethodCall(recvTypeName, func, args, recvType)
1012
+ ) {
1013
+ return true;
985
1014
  }
986
1015
 
987
1016
  if (targetFuncIdx !== null) {
@@ -1003,6 +1032,113 @@ export class BuiltinsEmitter {
1003
1032
  return false;
1004
1033
  }
1005
1034
 
1035
+ _emitStdlibReceiverMethod(
1036
+ recvTypeName,
1037
+ field,
1038
+ expr,
1039
+ args,
1040
+ targetWasmType = null,
1041
+ ) {
1042
+ if (recvTypeName === "strings.Builder") {
1043
+ this.emitBuilderMethodCall(field, expr, args, targetWasmType);
1044
+ return true;
1045
+ }
1046
+ if (recvTypeName === "strings.Replacer") {
1047
+ this.emitReplacerMethodCall(field, expr, args);
1048
+ return true;
1049
+ }
1050
+ if (recvTypeName === "bytes.Buffer") {
1051
+ this.emitBytesBufferMethodCall(field, expr, args, targetWasmType);
1052
+ return true;
1053
+ }
1054
+ if (recvTypeName === "strings.Reader") {
1055
+ this.emitStringsReaderMethodCall(field, expr, args, targetWasmType);
1056
+ return true;
1057
+ }
1058
+ if (recvTypeName === "bytes.Reader") {
1059
+ this.emitBytesReaderMethodCall(field, expr, args, targetWasmType);
1060
+ return true;
1061
+ }
1062
+ if (recvTypeName === "time.Time") {
1063
+ this.emitTimeMethodCall(field, expr, args, targetWasmType);
1064
+ return true;
1065
+ }
1066
+ if (recvTypeName === "time.Duration") {
1067
+ this.emitDurationMethodCall(field, expr, args, targetWasmType);
1068
+ return true;
1069
+ }
1070
+ if (recvTypeName === "io.LimitedReader") {
1071
+ this.emitIoLimitedReaderMethodCall(field, expr, args, targetWasmType);
1072
+ return true;
1073
+ }
1074
+ if (recvTypeName === "sync.Mutex" || recvTypeName === "sync.RWMutex") {
1075
+ this.emitSyncMutexMethodCall(field, expr, args, targetWasmType);
1076
+ return true;
1077
+ }
1078
+ if (recvTypeName === "sync.Once") {
1079
+ this.emitSyncOnceMethodCall(field, expr, args, targetWasmType);
1080
+ return true;
1081
+ }
1082
+ if (recvTypeName === "sync.WaitGroup") {
1083
+ this.emitSyncWaitGroupMethodCall(field, expr, args, targetWasmType);
1084
+ return true;
1085
+ }
1086
+ if (
1087
+ recvTypeName === "binary.LittleEndian" ||
1088
+ recvTypeName === "binary.BigEndian" ||
1089
+ recvTypeName === "encoding/binary.LittleEndian" ||
1090
+ recvTypeName === "encoding/binary.BigEndian" ||
1091
+ recvTypeName === "binary.ByteOrder" ||
1092
+ recvTypeName === "encoding/binary.ByteOrder"
1093
+ ) {
1094
+ this.emitBinaryOrderMethodCall(
1095
+ recvTypeName,
1096
+ field,
1097
+ expr,
1098
+ args,
1099
+ targetWasmType,
1100
+ );
1101
+ return true;
1102
+ }
1103
+ if (
1104
+ recvTypeName === "base64.Encoding" ||
1105
+ recvTypeName === "encoding/base64.Encoding"
1106
+ ) {
1107
+ this.emitBase64EncodingMethodCall(field, expr, args, targetWasmType);
1108
+ return true;
1109
+ }
1110
+ return false;
1111
+ }
1112
+
1113
+ _emitEmbeddedMethodCall(recvTypeName, func, args, recvType) {
1114
+ const structInfo = this.mod.getStructType(recvTypeName);
1115
+ if (!structInfo) return false;
1116
+ for (const embed of structInfo.embeds) {
1117
+ const embedMethodName = `${embed.name}.${func.field}`;
1118
+ const subIdx = this.mod.resolveFuncIndex(embedMethodName);
1119
+ if (subIdx !== null) {
1120
+ const targetParamTypes = this.mod.getFuncParamTypes(embedMethodName);
1121
+ const baseWType = this.toWasmType(recvType);
1122
+ this.emitExpr(func.expr, baseWType);
1123
+ this.pushInstruction({
1124
+ op: "struct.get",
1125
+ typeIndex: structInfo.typeIndex,
1126
+ fieldIndex: embed.fieldIndex,
1127
+ });
1128
+ for (let i = 0; i < args.length; i++) {
1129
+ const pType = targetParamTypes[i + 1] ?? null;
1130
+ this.emitExpr(args[i], pType);
1131
+ }
1132
+ this.pushInstruction({
1133
+ op: "call",
1134
+ funcIndex: subIdx,
1135
+ });
1136
+ return true;
1137
+ }
1138
+ }
1139
+ return false;
1140
+ }
1141
+
1006
1142
  _emitStaticCall(call) {
1007
1143
  const { func, args } = call;
1008
1144
  if (func.kind !== "Ident") return false;
@@ -1076,6 +1212,14 @@ export class BuiltinsEmitter {
1076
1212
  }
1077
1213
 
1078
1214
  emitCallExpr(call, targetWasmType = null) {
1215
+ if (call._isTypeConversion) {
1216
+ this.emitTypeConversion({
1217
+ targetType: call._conversionTargetType,
1218
+ expr: call.args[0],
1219
+ });
1220
+ return;
1221
+ }
1222
+
1079
1223
  const deqFunc = this._dequalify(call.func);
1080
1224
  if (deqFunc) {
1081
1225
  this.emitCallExpr({ ...call, func: deqFunc }, targetWasmType);
@@ -1090,7 +1234,7 @@ export class BuiltinsEmitter {
1090
1234
  return;
1091
1235
  }
1092
1236
 
1093
- if (this._emitMethodCall(call)) {
1237
+ if (this._emitMethodCall(call, targetWasmType)) {
1094
1238
  return;
1095
1239
  }
1096
1240