gofront 1.6.1 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -49
- package/package.json +12 -8
- package/src/backend/js/expressions.js +1627 -148
- package/src/backend/js/fmt-runtime.js +573 -0
- package/src/backend/js/index.js +508 -102
- package/src/backend/js/runtime.js +1997 -106
- package/src/backend/js/statements.js +931 -87
- package/src/backend/js/stdlib/bits.js +87 -14
- package/src/backend/js/stdlib/builder.js +41 -6
- package/src/backend/js/stdlib/bytes.js +253 -7
- package/src/backend/js/stdlib/errors.js +7 -1
- package/src/backend/js/stdlib/fmt.js +349 -10
- package/src/backend/js/stdlib/index.js +19 -2
- package/src/backend/js/stdlib/json.js +1167 -0
- package/src/backend/js/stdlib/maps.js +0 -8
- package/src/backend/js/stdlib/math.js +17 -1
- package/src/backend/js/stdlib/simd.js +34 -0
- package/src/backend/js/stdlib/slices.js +36 -6
- package/src/backend/js/stdlib/strconv.js +10 -5
- package/src/backend/js/stdlib/strings.js +83 -4
- package/src/backend/js/stdlib/testing.js +7 -0
- package/src/backend/js/stdlib/time.js +79 -55
- package/src/backend/js/stdlib/unicode.js +1 -1
- package/src/backend/js/stdlib/utf8.js +1 -1
- package/src/backend/js/templ.js +38 -76
- package/src/backend/js/type-info.js +272 -0
- package/src/backend/shared/fmt-types.js +188 -0
- package/src/backend/wasm/boundary.js +446 -72
- package/src/backend/wasm/emit-builtins.js +320 -13
- package/src/backend/wasm/emit-exprs.js +1404 -199
- package/src/backend/wasm/emit-maps.js +61 -13
- package/src/backend/wasm/emit-stmts.js +1359 -164
- package/src/backend/wasm/emit.js +518 -74
- package/src/backend/wasm/encode.js +128 -13
- package/src/backend/wasm/globals.js +452 -0
- package/src/backend/wasm/index.js +194 -2489
- package/src/backend/wasm/method-expr.js +381 -0
- package/src/backend/wasm/module-emitter.js +2240 -0
- package/src/backend/wasm/monomorph.js +62 -4
- package/src/backend/wasm/optimize.js +4 -2
- package/src/backend/wasm/prescan.js +397 -0
- package/src/backend/wasm/stdlib/bytes.js +1804 -127
- package/src/backend/wasm/stdlib/core.js +1574 -199
- package/src/backend/wasm/stdlib/index.js +3 -5
- package/src/backend/wasm/stdlib/io.js +1567 -150
- package/src/backend/wasm/stdlib/packages.js +2 -0
- package/src/backend/wasm/stdlib/simd.js +499 -0
- package/src/backend/wasm/stdlib/time.js +1041 -12
- package/src/backend/wasm/types.js +221 -15
- package/src/backend/wasm/variadic.js +93 -0
- package/src/backend/wasm/wat.js +84 -20
- package/src/{cli-core.js → cli/cli-core.js} +236 -10
- package/src/{test-runner.js → cli/test-runner.js} +332 -39
- package/src/{vendor.js → cli/vendor.js} +89 -15
- package/src/compiler.js +107 -269
- package/src/dts-parser.js +71 -14
- package/src/index.js +15 -169
- package/src/{lexer.js → lexer/lexer.js} +102 -55
- package/src/{tokens.js → lexer/tokens.js} +1 -0
- package/src/link/sourcemap.js +97 -0
- package/src/link/stdlib.js +515 -0
- package/src/link/wasm.js +294 -0
- package/src/lower/bounds.js +394 -0
- package/src/lower/boxing.js +1 -6
- package/src/lower/captures.js +176 -32
- package/src/lower/embedding.js +2 -1
- package/src/lower/index.js +26 -18
- package/src/lower/json-codecs.js +1398 -0
- package/src/lower/ownership.js +22 -1
- package/src/lower/range.js +86 -1
- package/src/lower/reachability.js +132 -0
- package/src/parser/declarations.js +58 -13
- package/src/parser/expressions.js +29 -7
- package/src/parser/index.js +2 -1
- package/src/parser/statements.js +37 -22
- package/src/parser/struct-tag.js +144 -0
- package/src/{templ-parser.js → parser/templ.js} +138 -15
- package/src/parser/types.js +130 -13
- package/src/resolver.js +22 -1
- package/src/typechecker/assignability.js +215 -11
- package/src/typechecker/const-fold.js +356 -0
- package/src/typechecker/constants.js +256 -0
- package/src/typechecker/expressions.js +960 -99
- package/src/typechecker/index.js +491 -72
- package/src/typechecker/init-order.js +330 -0
- package/src/typechecker/resolve.js +596 -52
- package/src/typechecker/statements.js +157 -17
- package/src/typechecker/stdlib/core.js +333 -55
- package/src/typechecker/stdlib/excluded.js +898 -0
- package/src/typechecker/stdlib/extended.js +359 -26
- package/src/typechecker/{stdlib.js → stdlib/index.js} +6 -4
- package/src/typechecker/stdlib/simd.js +123 -0
- package/src/typechecker/termination.js +1 -1
- package/src/typechecker/types.js +165 -26
- package/stdlib/bytes/iter.go +192 -0
- package/stdlib/bytes/search.go +240 -0
- package/stdlib/bytes/split.go +218 -0
- package/stdlib/cmp/cmp.go +65 -0
- package/stdlib/encoding/json/errors.go +31 -0
- package/stdlib/encoding/json/indent.go +71 -0
- package/stdlib/encoding/json/number.go +12 -0
- package/stdlib/encoding/json/stream.go +173 -0
- package/stdlib/errors/overlay.go +12 -0
- package/stdlib/hash/hash.go +53 -0
- package/stdlib/internal/jsonrt/dec.go +738 -0
- package/stdlib/internal/jsonrt/enc.go +366 -0
- package/stdlib/internal/jsonrt/indent.go +135 -0
- package/stdlib/internal/jsonrt/number.go +27 -0
- package/stdlib/internal/jsonrt/reader.go +73 -0
- package/stdlib/internal/jsonrt/scanner.go +649 -0
- package/stdlib/io/io.go +346 -0
- package/stdlib/iter/iter.go +18 -0
- package/stdlib/maps/iter.go +65 -0
- package/stdlib/math/extra.go +270 -0
- package/stdlib/slices/extra.go +73 -0
- package/stdlib/slices/iter.go +113 -0
- package/stdlib/sort/sort.go +561 -0
- package/stdlib/strconv/quote.go +341 -0
- package/stdlib/strings/extra.go +35 -0
- package/stdlib/strings/iter.go +122 -0
- package/stdlib/sync/extra.go +105 -0
- package/stdlib/unicode/unicode.go +112 -0
- package/stdlib/unicode/utf8/bytes.go +239 -0
- package/src/backend/wasm/const-fold.js +0 -205
- package/src/backend/wasm/emit-stdlib.js +0 -13
- /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
- /package/src/{colors.js → cli/colors.js} +0 -0
- /package/src/{dev-server.js → cli/dev-server.js} +0 -0
- /package/src/{minifier.js → cli/minifier.js} +0 -0
- /package/src/{project-config.js → cli/project-config.js} +0 -0
- /package/src/{pwa.js → cli/pwa.js} +0 -0
- /package/src/{templ-lexer.js → lexer/templ-lexer.js} +0 -0
|
@@ -3,10 +3,16 @@
|
|
|
3
3
|
// call expression dispatch (static, method, closure, package).
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
|
+
anonIfaceName,
|
|
6
7
|
getMapKeyValTypes,
|
|
7
8
|
isArrayType,
|
|
9
|
+
isBoolGoType,
|
|
10
|
+
isComplex,
|
|
11
|
+
isComplex64,
|
|
8
12
|
isMapType,
|
|
9
13
|
isNonEmptyInterface,
|
|
14
|
+
isScalarType,
|
|
15
|
+
isSigned,
|
|
10
16
|
isSliceType,
|
|
11
17
|
isStringType,
|
|
12
18
|
isStructType,
|
|
@@ -228,7 +234,12 @@ export class BuiltinsEmitter {
|
|
|
228
234
|
this.emitPanic("runtime error: makeslice: len out of range");
|
|
229
235
|
this.pushInstruction("end");
|
|
230
236
|
|
|
231
|
-
if (
|
|
237
|
+
if (
|
|
238
|
+
isStructType(elemGoType, this.mod.checker, this.mod) ||
|
|
239
|
+
isComplex(elemGoType) ||
|
|
240
|
+
(elemGoType?.kind !== "pointer" &&
|
|
241
|
+
isArrayType(elemGoType, this.mod.checker))
|
|
242
|
+
) {
|
|
232
243
|
const arrTmp = this.acquireTemp({
|
|
233
244
|
kind: "ref",
|
|
234
245
|
nullable: true,
|
|
@@ -302,6 +313,49 @@ export class BuiltinsEmitter {
|
|
|
302
313
|
}
|
|
303
314
|
}
|
|
304
315
|
|
|
316
|
+
_emitBuiltinNew(call) {
|
|
317
|
+
const targetType =
|
|
318
|
+
call._type?.base ??
|
|
319
|
+
(call.args[0]?.kind === "TypeExpr"
|
|
320
|
+
? call.args[0].type
|
|
321
|
+
: call.args[0]?._type) ??
|
|
322
|
+
call.args[0];
|
|
323
|
+
if (isStructType(targetType, this.mod.checker, this.mod)) {
|
|
324
|
+
let structInfo = this._resolveStructInfo({ _type: targetType });
|
|
325
|
+
if (!structInfo) {
|
|
326
|
+
const typeName =
|
|
327
|
+
targetType.kind === "named" ? targetType.name : targetType.name;
|
|
328
|
+
if (typeName) structInfo = this.mod.getStructType(typeName);
|
|
329
|
+
}
|
|
330
|
+
if (!structInfo) {
|
|
331
|
+
throw new Error(
|
|
332
|
+
`Unknown struct in new: ${targetType.name ?? targetType}`,
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
for (const f of structInfo.fields) {
|
|
336
|
+
this.emitZeroValue(f.goType, f.wType);
|
|
337
|
+
}
|
|
338
|
+
this.pushInstruction({
|
|
339
|
+
op: "struct.new",
|
|
340
|
+
typeIndex: structInfo.typeIndex,
|
|
341
|
+
});
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
if (isArrayType(targetType, this.mod.checker)) {
|
|
345
|
+
const wType = this.toWasmType(targetType);
|
|
346
|
+
this.emitZeroValue(targetType, wType);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const box = this.mod.getBoxType(targetType);
|
|
350
|
+
const valWType = this.toWasmType(targetType);
|
|
351
|
+
this.emitZeroValue(targetType, valWType);
|
|
352
|
+
this.pushInstruction({
|
|
353
|
+
op: "struct.new",
|
|
354
|
+
typeIndex: box.typeIndex,
|
|
355
|
+
typeName: box.name,
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
305
359
|
// With `newLen` already computed: when it exceeds the old capacity, allocate
|
|
306
360
|
// a doubled (min 2, at least newLen) backing array and copy the old elements
|
|
307
361
|
// into it at offset 0; otherwise reuse the old array, offset and capacity.
|
|
@@ -374,6 +428,17 @@ export class BuiltinsEmitter {
|
|
|
374
428
|
this.pushInstruction("end");
|
|
375
429
|
}
|
|
376
430
|
|
|
431
|
+
// The source operand of `append(b, x...)` and `copy(b, x)`: a string
|
|
432
|
+
// (the only non-slice form Go allows) is converted to a fresh byte slice.
|
|
433
|
+
_emitSliceOperand(node, elemGoType, sliceWType) {
|
|
434
|
+
if (isStringType(node._type, this.mod.checker)) {
|
|
435
|
+
this.emitExpr(node, "externref");
|
|
436
|
+
this._emitStringToByteSlice({ kind: "slice", elem: elemGoType });
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
this.emitExpr(node, sliceWType);
|
|
440
|
+
}
|
|
441
|
+
|
|
377
442
|
_emitBuiltinAppend(call) {
|
|
378
443
|
const { args } = call;
|
|
379
444
|
const sNode = args[0];
|
|
@@ -428,7 +493,7 @@ export class BuiltinsEmitter {
|
|
|
428
493
|
|
|
429
494
|
if (args.length === 2 && args[1]._spread) {
|
|
430
495
|
const s2Tmp = this.acquireTemp(sliceWType);
|
|
431
|
-
this.
|
|
496
|
+
this._emitSliceOperand(args[1], elemGoType, sliceWType);
|
|
432
497
|
this.pushInstruction({ op: "local.set", index: s2Tmp });
|
|
433
498
|
|
|
434
499
|
const s2ArrTmp = this.acquireTemp(arrWType);
|
|
@@ -487,7 +552,7 @@ export class BuiltinsEmitter {
|
|
|
487
552
|
this.pushInstruction("i32.add");
|
|
488
553
|
}
|
|
489
554
|
this.emitExpr(elemNode, arrInfo.elemWType);
|
|
490
|
-
this.
|
|
555
|
+
this._emitCopyIfValue(elemNode, elemGoType, arrInfo.elemWType);
|
|
491
556
|
this.pushInstruction({
|
|
492
557
|
op: "array.set",
|
|
493
558
|
typeIndex: arrInfo.typeIndex,
|
|
@@ -538,7 +603,7 @@ export class BuiltinsEmitter {
|
|
|
538
603
|
this.pushInstruction({ op: "local.set", index: dstTmp });
|
|
539
604
|
|
|
540
605
|
const srcTmp = this.acquireTemp(sliceWType);
|
|
541
|
-
this.
|
|
606
|
+
this._emitSliceOperand(srcNode, elemGoType, sliceWType);
|
|
542
607
|
this.pushInstruction({ op: "local.set", index: srcTmp });
|
|
543
608
|
|
|
544
609
|
const nTmp = this.acquireTemp("i32");
|
|
@@ -667,7 +732,7 @@ export class BuiltinsEmitter {
|
|
|
667
732
|
const arg = args[i];
|
|
668
733
|
const isLast = i === args.length - 1 && isPrintln;
|
|
669
734
|
const isBool =
|
|
670
|
-
arg._type
|
|
735
|
+
isBoolGoType(arg._type) ||
|
|
671
736
|
(arg.kind === "BasicLit" && arg.litKind === "BOOL");
|
|
672
737
|
const wType = toWasmType(arg._type, this.mod.checker);
|
|
673
738
|
this.emitExpr(arg, wType);
|
|
@@ -795,6 +860,136 @@ export class BuiltinsEmitter {
|
|
|
795
860
|
}
|
|
796
861
|
}
|
|
797
862
|
|
|
863
|
+
_emitBuiltinComplex(call, targetWasmType) {
|
|
864
|
+
const arg0 = call.args[0];
|
|
865
|
+
const arg1 = call.args[1];
|
|
866
|
+
const callType = call._type;
|
|
867
|
+
const is64 =
|
|
868
|
+
callType?.name === "complex64" ||
|
|
869
|
+
arg0._type?.name === "float32" ||
|
|
870
|
+
arg1._type?.name === "float32" ||
|
|
871
|
+
targetWasmType?.typeName === "$complex64";
|
|
872
|
+
const complexName = is64 ? "complex64" : "complex128";
|
|
873
|
+
const info = this.mod.getComplexType(complexName);
|
|
874
|
+
this.emitExpr(arg0, info.elemWType);
|
|
875
|
+
this.emitExpr(arg1, info.elemWType);
|
|
876
|
+
this.pushInstruction({
|
|
877
|
+
op: "struct.new",
|
|
878
|
+
typeIndex: info.typeIndex,
|
|
879
|
+
typeName: info.name,
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
_emitBuiltinReal(call, targetWasmType) {
|
|
884
|
+
const arg = call.args[0];
|
|
885
|
+
const argType = arg._type ?? this._resolveExprGoType(arg);
|
|
886
|
+
const is64 = isComplex64(argType);
|
|
887
|
+
const complexName = is64 ? "complex64" : "complex128";
|
|
888
|
+
const info = this.mod.getComplexType(complexName);
|
|
889
|
+
const complexWType = {
|
|
890
|
+
kind: "ref",
|
|
891
|
+
nullable: true,
|
|
892
|
+
typeIndex: info.typeIndex,
|
|
893
|
+
typeName: info.name,
|
|
894
|
+
};
|
|
895
|
+
this.emitExpr(arg, complexWType);
|
|
896
|
+
this.pushInstruction({
|
|
897
|
+
op: "struct.get",
|
|
898
|
+
typeIndex: info.typeIndex,
|
|
899
|
+
typeName: info.name,
|
|
900
|
+
fieldIndex: 0,
|
|
901
|
+
});
|
|
902
|
+
if (targetWasmType && targetWasmType !== info.elemWType) {
|
|
903
|
+
if (info.elemWType === "f32" && targetWasmType === "f64") {
|
|
904
|
+
this.pushInstruction("f64.promote_f32");
|
|
905
|
+
} else if (info.elemWType === "f64" && targetWasmType === "f32") {
|
|
906
|
+
this.pushInstruction("f32.demote_f64");
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
_emitBuiltinImag(call, targetWasmType) {
|
|
912
|
+
const arg = call.args[0];
|
|
913
|
+
const argType = arg._type ?? this._resolveExprGoType(arg);
|
|
914
|
+
const is64 = isComplex64(argType);
|
|
915
|
+
const complexName = is64 ? "complex64" : "complex128";
|
|
916
|
+
const info = this.mod.getComplexType(complexName);
|
|
917
|
+
const complexWType = {
|
|
918
|
+
kind: "ref",
|
|
919
|
+
nullable: true,
|
|
920
|
+
typeIndex: info.typeIndex,
|
|
921
|
+
typeName: info.name,
|
|
922
|
+
};
|
|
923
|
+
this.emitExpr(arg, complexWType);
|
|
924
|
+
this.pushInstruction({
|
|
925
|
+
op: "struct.get",
|
|
926
|
+
typeIndex: info.typeIndex,
|
|
927
|
+
typeName: info.name,
|
|
928
|
+
fieldIndex: 1,
|
|
929
|
+
});
|
|
930
|
+
if (targetWasmType && targetWasmType !== info.elemWType) {
|
|
931
|
+
if (info.elemWType === "f32" && targetWasmType === "f64") {
|
|
932
|
+
this.pushInstruction("f64.promote_f32");
|
|
933
|
+
} else if (info.elemWType === "f64" && targetWasmType === "f32") {
|
|
934
|
+
this.pushInstruction("f32.demote_f64");
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
// min/max fold left over the operands: floats use f32/f64.min/max (NaN
|
|
940
|
+
// propagates, -0 < +0), integers `select` on lt/gt, strings compare via the
|
|
941
|
+
// string import. A single operand is the result itself.
|
|
942
|
+
_emitBuiltinMinMax(call, targetWasmType) {
|
|
943
|
+
const isMin = call.func.name === "min";
|
|
944
|
+
const goType = call._type ?? this._resolveExprGoType(call.args[0]);
|
|
945
|
+
const wType =
|
|
946
|
+
goType?.kind === "untyped" && typeof targetWasmType === "string"
|
|
947
|
+
? targetWasmType
|
|
948
|
+
: toWasmType(goType, this.mod.checker);
|
|
949
|
+
const [first, ...rest] = call.args;
|
|
950
|
+
this.emitExpr(first, wType);
|
|
951
|
+
if (rest.length === 0) return;
|
|
952
|
+
const acc = this.acquireTemp(wType);
|
|
953
|
+
const next = this.acquireTemp(wType);
|
|
954
|
+
const isStr = isStringType(goType, this.mod.checker);
|
|
955
|
+
const isFloatType = wType === "f32" || wType === "f64";
|
|
956
|
+
const cmp = isMin ? "lt" : "gt";
|
|
957
|
+
for (const arg of rest) {
|
|
958
|
+
this.pushInstruction({ op: "local.set", index: acc });
|
|
959
|
+
this.emitExpr(arg, wType);
|
|
960
|
+
this.pushInstruction({ op: "local.set", index: next });
|
|
961
|
+
if (isFloatType) {
|
|
962
|
+
this.pushInstruction({ op: "local.get", index: acc });
|
|
963
|
+
this.pushInstruction({ op: "local.get", index: next });
|
|
964
|
+
this.pushInstruction(`${wType}.${isMin ? "min" : "max"}`);
|
|
965
|
+
continue;
|
|
966
|
+
}
|
|
967
|
+
if (isStr) {
|
|
968
|
+
// next < acc (min) / next > acc (max) ? next : acc
|
|
969
|
+
this.pushInstruction({ op: "local.get", index: next });
|
|
970
|
+
this.pushInstruction({ op: "local.get", index: acc });
|
|
971
|
+
this.pushInstruction({
|
|
972
|
+
op: "call",
|
|
973
|
+
funcIndex: this.mod.getStringCmpImportIndex(isMin ? "<" : ">"),
|
|
974
|
+
});
|
|
975
|
+
this.pushInstruction({ op: "if", blockType: wType });
|
|
976
|
+
this.pushInstruction({ op: "local.get", index: next });
|
|
977
|
+
this.pushInstruction("else");
|
|
978
|
+
this.pushInstruction({ op: "local.get", index: acc });
|
|
979
|
+
this.pushInstruction("end");
|
|
980
|
+
continue;
|
|
981
|
+
}
|
|
982
|
+
this.pushInstruction({ op: "local.get", index: next });
|
|
983
|
+
this.pushInstruction({ op: "local.get", index: acc });
|
|
984
|
+
this.pushInstruction({ op: "local.get", index: next });
|
|
985
|
+
this.pushInstruction({ op: "local.get", index: acc });
|
|
986
|
+
this.pushInstruction(`${wType}.${cmp}_${isSigned(goType) ? "s" : "u"}`);
|
|
987
|
+
this.pushInstruction("select");
|
|
988
|
+
}
|
|
989
|
+
this.releaseTemp(next, wType);
|
|
990
|
+
this.releaseTemp(acc, wType);
|
|
991
|
+
}
|
|
992
|
+
|
|
798
993
|
_emitBuiltinCall(call, targetWasmType) {
|
|
799
994
|
const { func } = call;
|
|
800
995
|
if (func.kind !== "Ident") return false;
|
|
@@ -808,6 +1003,9 @@ export class BuiltinsEmitter {
|
|
|
808
1003
|
case "cap":
|
|
809
1004
|
this._emitBuiltinCap(call, targetWasmType);
|
|
810
1005
|
return true;
|
|
1006
|
+
case "new":
|
|
1007
|
+
this._emitBuiltinNew(call);
|
|
1008
|
+
return true;
|
|
811
1009
|
case "make":
|
|
812
1010
|
this._emitBuiltinMake(call);
|
|
813
1011
|
return true;
|
|
@@ -833,6 +1031,19 @@ export class BuiltinsEmitter {
|
|
|
833
1031
|
case "recover":
|
|
834
1032
|
this._emitBuiltinRecover(call, targetWasmType);
|
|
835
1033
|
return true;
|
|
1034
|
+
case "complex":
|
|
1035
|
+
this._emitBuiltinComplex(call, targetWasmType);
|
|
1036
|
+
return true;
|
|
1037
|
+
case "real":
|
|
1038
|
+
this._emitBuiltinReal(call, targetWasmType);
|
|
1039
|
+
return true;
|
|
1040
|
+
case "imag":
|
|
1041
|
+
this._emitBuiltinImag(call, targetWasmType);
|
|
1042
|
+
return true;
|
|
1043
|
+
case "min":
|
|
1044
|
+
case "max":
|
|
1045
|
+
this._emitBuiltinMinMax(call, targetWasmType);
|
|
1046
|
+
return true;
|
|
836
1047
|
default:
|
|
837
1048
|
return false;
|
|
838
1049
|
}
|
|
@@ -845,6 +1056,12 @@ export class BuiltinsEmitter {
|
|
|
845
1056
|
this.emitTestingCall(func, args);
|
|
846
1057
|
return true;
|
|
847
1058
|
}
|
|
1059
|
+
if (
|
|
1060
|
+
func.expr?.name &&
|
|
1061
|
+
(this.resolveLocal(func.expr.name) ||
|
|
1062
|
+
this.mod.resolveGlobal(func.expr.name))
|
|
1063
|
+
)
|
|
1064
|
+
return false;
|
|
848
1065
|
const pkgName = func.expr?.name;
|
|
849
1066
|
switch (pkgName) {
|
|
850
1067
|
case "math":
|
|
@@ -903,6 +1120,14 @@ export class BuiltinsEmitter {
|
|
|
903
1120
|
this.emitBytesNewReader(call, targetWasmType);
|
|
904
1121
|
return true;
|
|
905
1122
|
}
|
|
1123
|
+
if (func.field === "NewBuffer") {
|
|
1124
|
+
this.emitBytesNewBuffer(call, targetWasmType);
|
|
1125
|
+
return true;
|
|
1126
|
+
}
|
|
1127
|
+
if (func.field === "NewBufferString") {
|
|
1128
|
+
this.emitBytesNewBufferString(call, targetWasmType);
|
|
1129
|
+
return true;
|
|
1130
|
+
}
|
|
906
1131
|
this.emitBytesCall(func.field, args, targetWasmType);
|
|
907
1132
|
return true;
|
|
908
1133
|
case "path":
|
|
@@ -930,6 +1155,9 @@ export class BuiltinsEmitter {
|
|
|
930
1155
|
case "base64":
|
|
931
1156
|
this.emitBase64Call(func.field, call, targetWasmType);
|
|
932
1157
|
return true;
|
|
1158
|
+
case "simd":
|
|
1159
|
+
this.emitSimdPackageCall(func.field, args, targetWasmType);
|
|
1160
|
+
return true;
|
|
933
1161
|
default:
|
|
934
1162
|
return false;
|
|
935
1163
|
}
|
|
@@ -946,6 +1174,23 @@ export class BuiltinsEmitter {
|
|
|
946
1174
|
return true;
|
|
947
1175
|
}
|
|
948
1176
|
const recvTypeName = this._getReceiverTypeName(recvType, func.expr);
|
|
1177
|
+
if (
|
|
1178
|
+
recvTypeName === "simd.F32x4" ||
|
|
1179
|
+
recvTypeName === "gofront/simd.F32x4" ||
|
|
1180
|
+
recvType?.kind === "simd" ||
|
|
1181
|
+
recvType?.underlying?.kind === "simd" ||
|
|
1182
|
+
recvType?.name === "simd.F32x4"
|
|
1183
|
+
) {
|
|
1184
|
+
return this.emitSimdMethodCall(
|
|
1185
|
+
func.field,
|
|
1186
|
+
func.expr,
|
|
1187
|
+
args,
|
|
1188
|
+
targetWasmType,
|
|
1189
|
+
recvTypeName === "simd.Mask32x4" ||
|
|
1190
|
+
recvType?.underlying?.simd === "Mask32x4" ||
|
|
1191
|
+
recvType?.simd === "Mask32x4",
|
|
1192
|
+
);
|
|
1193
|
+
}
|
|
949
1194
|
if (
|
|
950
1195
|
this._emitStdlibReceiverMethod(
|
|
951
1196
|
recvTypeName,
|
|
@@ -966,7 +1211,7 @@ export class BuiltinsEmitter {
|
|
|
966
1211
|
return true;
|
|
967
1212
|
}
|
|
968
1213
|
if (isNonEmptyInterface(recvType, this.mod.checker)) {
|
|
969
|
-
const ifaceName = recvTypeName ??
|
|
1214
|
+
const ifaceName = recvTypeName ?? anonIfaceName(recvType);
|
|
970
1215
|
const dispatchName = `__dispatch_${ifaceName}_${func.field}`;
|
|
971
1216
|
const targetFuncIdx = this.mod.resolveFuncIndex(dispatchName);
|
|
972
1217
|
if (targetFuncIdx !== null) {
|
|
@@ -977,7 +1222,7 @@ export class BuiltinsEmitter {
|
|
|
977
1222
|
const pType = targetParamTypes[i + 1] ?? null;
|
|
978
1223
|
const pGoType = paramGoTypes[i + 1] ?? null;
|
|
979
1224
|
this.emitExpr(args[i], pType);
|
|
980
|
-
this.
|
|
1225
|
+
this._emitCopyIfValue(args[i], pGoType, pType);
|
|
981
1226
|
}
|
|
982
1227
|
this.pushInstruction({ op: "call", funcIndex: targetFuncIdx });
|
|
983
1228
|
return true;
|
|
@@ -999,14 +1244,20 @@ export class BuiltinsEmitter {
|
|
|
999
1244
|
if (targetFuncIdx !== null) {
|
|
1000
1245
|
const recvWType = targetParamTypes[0] ?? null;
|
|
1001
1246
|
const recvGoType = this.mod.getFuncParamGoTypes(methodName)[0] ?? null;
|
|
1002
|
-
this.emitExpr(func
|
|
1003
|
-
|
|
1247
|
+
this.emitExpr(this._recvOperand(func, recvGoType), recvWType);
|
|
1248
|
+
// `p.M()` with a value receiver reads `*p`: a nil `p` panics here.
|
|
1249
|
+
if (
|
|
1250
|
+
recvGoType?.kind !== "pointer" &&
|
|
1251
|
+
isStructType(recvGoType, this.mod.checker, this.mod)
|
|
1252
|
+
)
|
|
1253
|
+
this._emitNilCheck(func.expr._type);
|
|
1254
|
+
this._emitCopyIfValue(func.expr, recvGoType, recvWType);
|
|
1004
1255
|
const paramGoTypes = this.mod.getFuncParamGoTypes(methodName);
|
|
1005
1256
|
for (let i = 0; i < args.length; i++) {
|
|
1006
1257
|
const pType = targetParamTypes[i + 1] ?? null;
|
|
1007
1258
|
const pGoType = paramGoTypes[i + 1] ?? null;
|
|
1008
1259
|
this.emitExpr(args[i], pType);
|
|
1009
|
-
this.
|
|
1260
|
+
this._emitCopyIfValue(args[i], pGoType, pType);
|
|
1010
1261
|
}
|
|
1011
1262
|
this.pushInstruction({ op: "call", funcIndex: targetFuncIdx });
|
|
1012
1263
|
return true;
|
|
@@ -1015,6 +1266,43 @@ export class BuiltinsEmitter {
|
|
|
1015
1266
|
return false;
|
|
1016
1267
|
}
|
|
1017
1268
|
|
|
1269
|
+
// The receiver operand of a method call: `p.Get()` with a value receiver
|
|
1270
|
+
// and `p *N` (a named scalar or slice) passes `*p`.
|
|
1271
|
+
_recvOperand(func, recvGoType) {
|
|
1272
|
+
const t = func.expr._type;
|
|
1273
|
+
// A pointer receiver on `*p` gets `p` itself, so the method mutates *p.
|
|
1274
|
+
if (recvGoType?.kind === "pointer") {
|
|
1275
|
+
const pointer = this._structDerefPointer(func.expr);
|
|
1276
|
+
if (pointer) return pointer;
|
|
1277
|
+
}
|
|
1278
|
+
if (
|
|
1279
|
+
t?.kind === "pointer" &&
|
|
1280
|
+
recvGoType?.kind !== "pointer" &&
|
|
1281
|
+
(isScalarType(t.base, this.mod.checker, this.mod) ||
|
|
1282
|
+
isSliceType(t.base, this.mod.checker))
|
|
1283
|
+
)
|
|
1284
|
+
return { kind: "UnaryExpr", op: "*", operand: func.expr, _type: t.base };
|
|
1285
|
+
return this._ptrRecvOperand(func);
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
// `x.M()` with a pointer receiver on a named scalar value passes `&x`
|
|
1289
|
+
// (the typechecker boxed `x`).
|
|
1290
|
+
_ptrRecvOperand(func) {
|
|
1291
|
+
const t = func.expr._type;
|
|
1292
|
+
if (!func._type?._ptrRecv || t?.kind !== "named") return func.expr;
|
|
1293
|
+
if (
|
|
1294
|
+
!isScalarType(t, this.mod.checker, this.mod) &&
|
|
1295
|
+
!isSliceType(t, this.mod.checker)
|
|
1296
|
+
)
|
|
1297
|
+
return func.expr;
|
|
1298
|
+
return {
|
|
1299
|
+
kind: "UnaryExpr",
|
|
1300
|
+
op: "&",
|
|
1301
|
+
operand: func.expr,
|
|
1302
|
+
_type: { kind: "pointer", base: t },
|
|
1303
|
+
};
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1018
1306
|
_emitStdlibReceiverMethod(
|
|
1019
1307
|
recvTypeName,
|
|
1020
1308
|
field,
|
|
@@ -1050,11 +1338,28 @@ export class BuiltinsEmitter {
|
|
|
1050
1338
|
this.emitDurationMethodCall(field, expr, args, targetWasmType);
|
|
1051
1339
|
return true;
|
|
1052
1340
|
}
|
|
1341
|
+
if (
|
|
1342
|
+
recvTypeName === "time.Month" ||
|
|
1343
|
+
recvTypeName === "time.Weekday" ||
|
|
1344
|
+
recvTypeName === "time.Location"
|
|
1345
|
+
) {
|
|
1346
|
+
this.emitTimeAuxMethodCall(
|
|
1347
|
+
recvTypeName,
|
|
1348
|
+
field,
|
|
1349
|
+
expr,
|
|
1350
|
+
args,
|
|
1351
|
+
targetWasmType,
|
|
1352
|
+
);
|
|
1353
|
+
return true;
|
|
1354
|
+
}
|
|
1053
1355
|
if (recvTypeName === "io.LimitedReader") {
|
|
1054
1356
|
this.emitIoLimitedReaderMethodCall(field, expr, args, targetWasmType);
|
|
1055
1357
|
return true;
|
|
1056
1358
|
}
|
|
1057
|
-
if (
|
|
1359
|
+
if (
|
|
1360
|
+
(recvTypeName === "sync.Mutex" || recvTypeName === "sync.RWMutex") &&
|
|
1361
|
+
field !== "RLocker"
|
|
1362
|
+
) {
|
|
1058
1363
|
this.emitSyncMutexMethodCall(field, expr, args, targetWasmType);
|
|
1059
1364
|
return true;
|
|
1060
1365
|
}
|
|
@@ -1137,7 +1442,7 @@ export class BuiltinsEmitter {
|
|
|
1137
1442
|
const pType = paramTypes[i] ?? null;
|
|
1138
1443
|
const pGoType = paramGoTypes[i] ?? null;
|
|
1139
1444
|
this.emitExpr(arg, pType);
|
|
1140
|
-
this.
|
|
1445
|
+
this._emitCopyIfValue(arg, pGoType, pType);
|
|
1141
1446
|
}
|
|
1142
1447
|
this.pushInstruction({ op: "call", funcIndex: targetFuncIdx });
|
|
1143
1448
|
return true;
|
|
@@ -1158,6 +1463,8 @@ export class BuiltinsEmitter {
|
|
|
1158
1463
|
|
|
1159
1464
|
const closureTmp = this.acquireTemp(closureWType);
|
|
1160
1465
|
this.emitExpr(func, closureWType);
|
|
1466
|
+
// Calling a nil func value panics like a nil pointer dereference.
|
|
1467
|
+
this._emitNilBranch();
|
|
1161
1468
|
this.pushInstruction({ op: "local.set", index: closureTmp });
|
|
1162
1469
|
|
|
1163
1470
|
// Push param 0: env (anyref)
|
|
@@ -1174,7 +1481,7 @@ export class BuiltinsEmitter {
|
|
|
1174
1481
|
const pWType = closureInfo.paramWTypes[i] ?? null;
|
|
1175
1482
|
const pGoType = closureInfo.sig.params[i] ?? null;
|
|
1176
1483
|
this.emitExpr(arg, pWType);
|
|
1177
|
-
this.
|
|
1484
|
+
this._emitCopyIfValue(arg, pGoType, pWType);
|
|
1178
1485
|
}
|
|
1179
1486
|
|
|
1180
1487
|
// Push funcref
|