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
@@ -205,6 +205,31 @@ export class StmtsEmitter {
205
205
  }
206
206
  }
207
207
 
208
+ _emitAssignToTarget(target, wasmType, goType, emitValue) {
209
+ const tempName = `__assign_tmp_${this.tempCounter++}`;
210
+ const effectiveGoType = goType ??
211
+ target._type ?? {
212
+ kind: "basic",
213
+ name: wasmType === "i64" ? "int64" : "int",
214
+ };
215
+ const effectiveWasmType = wasmType ?? this.toWasmType(effectiveGoType);
216
+ const tempIdx = this.allocLocal(
217
+ tempName,
218
+ effectiveWasmType,
219
+ effectiveGoType,
220
+ true,
221
+ );
222
+ emitValue();
223
+ this.pushInstruction({ op: "local.set", index: tempIdx });
224
+ const rNode = {
225
+ kind: "Ident",
226
+ name: tempName,
227
+ _type: effectiveGoType,
228
+ };
229
+ this._emitAssignSingle(target, rNode, "=");
230
+ this.locals.delete(tempName);
231
+ }
232
+
208
233
  _emitAssignSingle(l, r, op) {
209
234
  if (!r) return;
210
235
  if (l.kind === "Ident") {
@@ -261,7 +286,11 @@ export class StmtsEmitter {
261
286
  );
262
287
  }
263
288
  const lastStep = path[path.length - 1];
264
- const baseWType = this.toWasmType(l.expr._type);
289
+ const exprGoType =
290
+ l.expr._type ??
291
+ this.resolveLocal(l.expr.name)?.goType ??
292
+ this._resolveExprGoType(l.expr);
293
+ const baseWType = this.toWasmType(exprGoType);
265
294
 
266
295
  this.emitExpr(l.expr, baseWType);
267
296
  for (let i = 0; i < path.length - 1; i++) {
@@ -314,7 +343,13 @@ export class StmtsEmitter {
314
343
  this.releaseTemp(tmpL, baseWType);
315
344
  return;
316
345
  }
317
- const box = this.mod.getBoxType(l.operand._type?.base ?? l.operand._type);
346
+ const operandGoType =
347
+ l.operand._type ??
348
+ (l.operand.kind === "Ident"
349
+ ? this.resolveLocal(l.operand.name)?.goType
350
+ : null) ??
351
+ this._resolveExprGoType(l.operand);
352
+ const box = this.mod.getBoxType(operandGoType?.base ?? operandGoType);
318
353
  const baseWType = {
319
354
  kind: "ref",
320
355
  nullable: true,
@@ -455,43 +490,59 @@ export class StmtsEmitter {
455
490
 
456
491
  this.releaseTemp(anyTmp, "anyref");
457
492
 
458
- // Assign val to valLhs
459
- if (isDefine && valLhs.kind === "Ident" && valLhs.name !== "_") {
460
- const idx = this.allocLocal(valLhs.name, targetWType, targetGoType);
461
- this.pushInstruction({ op: "local.get", index: valTmp });
462
- this.pushInstruction({ op: "local.set", index: idx });
463
- } else if (valLhs.kind === "Ident" && valLhs.name !== "_") {
464
- const local = this.resolveLocal(valLhs.name);
465
- this.pushInstruction({ op: "local.get", index: valTmp });
466
- if (local) {
467
- this.pushInstruction({ op: "local.set", index: local.index });
468
- } else {
469
- const global = this.mod.resolveGlobal(valLhs.name);
470
- this.pushInstruction({ op: "global.set", index: global.index });
471
- }
472
- }
493
+ this._emitStoreLhsFromTemp(
494
+ valLhs,
495
+ valTmp,
496
+ targetWType,
497
+ targetGoType,
498
+ isDefine,
499
+ );
500
+ this._emitStoreLhsFromTemp(
501
+ okLhs,
502
+ okTmp,
503
+ "i32",
504
+ { kind: "basic", name: "bool" },
505
+ isDefine,
506
+ );
473
507
 
474
- // Assign ok to okLhs
475
- if (isDefine && okLhs.kind === "Ident" && okLhs.name !== "_") {
476
- const idx = this.allocLocal(okLhs.name, "i32", {
477
- kind: "basic",
478
- name: "bool",
479
- });
480
- this.pushInstruction({ op: "local.get", index: okTmp });
508
+ this.releaseTemp(valTmp, targetWType);
509
+ this.releaseTemp(okTmp, "i32");
510
+ }
511
+
512
+ _emitStoreLhsFromTemp(lhsNode, tempIdx, wType, goType, isDefine) {
513
+ if (lhsNode.kind !== "Ident" || lhsNode.name === "_") return;
514
+ if (isDefine) {
515
+ const idx = this.allocLocal(lhsNode.name, wType, goType);
516
+ const local = this.locals.get(lhsNode.name);
517
+ this.pushInstruction({ op: "local.get", index: tempIdx });
518
+ if (local?.isBoxed) {
519
+ this.pushInstruction({
520
+ op: "struct.new",
521
+ typeIndex: local.boxInfo.typeIndex,
522
+ });
523
+ }
481
524
  this.pushInstruction({ op: "local.set", index: idx });
482
- } else if (okLhs.kind === "Ident" && okLhs.name !== "_") {
483
- const local = this.resolveLocal(okLhs.name);
484
- this.pushInstruction({ op: "local.get", index: okTmp });
485
- if (local) {
486
- this.pushInstruction({ op: "local.set", index: local.index });
525
+ return;
526
+ }
527
+ const local = this.resolveLocal(lhsNode.name);
528
+ if (local) {
529
+ if (local.isBoxed) {
530
+ this.pushInstruction({ op: "local.get", index: local.index });
531
+ this.pushInstruction({ op: "local.get", index: tempIdx });
532
+ this.pushInstruction({
533
+ op: "struct.set",
534
+ typeIndex: local.boxInfo.typeIndex,
535
+ fieldIndex: 0,
536
+ });
487
537
  } else {
488
- const global = this.mod.resolveGlobal(okLhs.name);
489
- this.pushInstruction({ op: "global.set", index: global.index });
538
+ this.pushInstruction({ op: "local.get", index: tempIdx });
539
+ this.pushInstruction({ op: "local.set", index: local.index });
490
540
  }
541
+ } else {
542
+ const global = this.mod.resolveGlobal(lhsNode.name);
543
+ this.pushInstruction({ op: "local.get", index: tempIdx });
544
+ this.pushInstruction({ op: "global.set", index: global.index });
491
545
  }
492
-
493
- this.releaseTemp(valTmp, targetWType);
494
- this.releaseTemp(okTmp, "i32");
495
546
  }
496
547
 
497
548
  _emitCommaOkMapIndex(valLhs, okLhs, indexExpr, isDefine) {
@@ -512,82 +563,20 @@ export class StmtsEmitter {
512
563
  this.pushInstruction({ op: "local.set", index: okTmp });
513
564
  this.pushInstruction({ op: "local.set", index: valTmp });
514
565
 
515
- // Assign val to valLhs
516
- if (isDefine && valLhs.kind === "Ident" && valLhs.name !== "_") {
517
- const idx = this.allocLocal(valLhs.name, mapInfo.valWType, valType);
518
- const local = this.locals.get(valLhs.name);
519
- if (local?.isBoxed) {
520
- this.pushInstruction({ op: "local.get", index: valTmp });
521
- this.pushInstruction({
522
- op: "struct.new",
523
- typeIndex: local.boxInfo.typeIndex,
524
- });
525
- this.pushInstruction({ op: "local.set", index: idx });
526
- } else {
527
- this.pushInstruction({ op: "local.get", index: valTmp });
528
- this.pushInstruction({ op: "local.set", index: idx });
529
- }
530
- } else if (valLhs.kind === "Ident" && valLhs.name !== "_") {
531
- const local = this.resolveLocal(valLhs.name);
532
- if (local) {
533
- if (local.isBoxed) {
534
- this.pushInstruction({ op: "local.get", index: local.index });
535
- this.pushInstruction({ op: "local.get", index: valTmp });
536
- this.pushInstruction({
537
- op: "struct.set",
538
- typeIndex: local.boxInfo.typeIndex,
539
- fieldIndex: 0,
540
- });
541
- } else {
542
- this.pushInstruction({ op: "local.get", index: valTmp });
543
- this.pushInstruction({ op: "local.set", index: local.index });
544
- }
545
- } else {
546
- const global = this.mod.resolveGlobal(valLhs.name);
547
- this.pushInstruction({ op: "local.get", index: valTmp });
548
- this.pushInstruction({ op: "global.set", index: global.index });
549
- }
550
- }
551
-
552
- // Assign ok to okLhs
553
- if (isDefine && okLhs.kind === "Ident" && okLhs.name !== "_") {
554
- const idx = this.allocLocal(okLhs.name, "i32", {
555
- kind: "basic",
556
- name: "bool",
557
- });
558
- const local = this.locals.get(okLhs.name);
559
- if (local?.isBoxed) {
560
- this.pushInstruction({ op: "local.get", index: okTmp });
561
- this.pushInstruction({
562
- op: "struct.new",
563
- typeIndex: local.boxInfo.typeIndex,
564
- });
565
- this.pushInstruction({ op: "local.set", index: idx });
566
- } else {
567
- this.pushInstruction({ op: "local.get", index: okTmp });
568
- this.pushInstruction({ op: "local.set", index: idx });
569
- }
570
- } else if (okLhs.kind === "Ident" && okLhs.name !== "_") {
571
- const local = this.resolveLocal(okLhs.name);
572
- if (local) {
573
- if (local.isBoxed) {
574
- this.pushInstruction({ op: "local.get", index: local.index });
575
- this.pushInstruction({ op: "local.get", index: okTmp });
576
- this.pushInstruction({
577
- op: "struct.set",
578
- typeIndex: local.boxInfo.typeIndex,
579
- fieldIndex: 0,
580
- });
581
- } else {
582
- this.pushInstruction({ op: "local.get", index: okTmp });
583
- this.pushInstruction({ op: "local.set", index: local.index });
584
- }
585
- } else {
586
- const global = this.mod.resolveGlobal(okLhs.name);
587
- this.pushInstruction({ op: "local.get", index: okTmp });
588
- this.pushInstruction({ op: "global.set", index: global.index });
589
- }
590
- }
566
+ this._emitStoreLhsFromTemp(
567
+ valLhs,
568
+ valTmp,
569
+ mapInfo.valWType,
570
+ valType,
571
+ isDefine,
572
+ );
573
+ this._emitStoreLhsFromTemp(
574
+ okLhs,
575
+ okTmp,
576
+ "i32",
577
+ { kind: "basic", name: "bool" },
578
+ isDefine,
579
+ );
591
580
 
592
581
  this.releaseTemp(valTmp, mapInfo.valWType);
593
582
  this.releaseTemp(okTmp, "i32");
@@ -693,7 +682,7 @@ export class StmtsEmitter {
693
682
  }
694
683
 
695
684
  // Scalar types
696
- const box = this.mod.getBoxType(targetGoType);
685
+ const box = this.mod.getIfaceBoxType(targetGoType);
697
686
  if (box) {
698
687
  this.pushInstruction({ op: "ref.test", typeIndex: box.typeIndex });
699
688
  return;
@@ -734,17 +723,9 @@ export class StmtsEmitter {
734
723
  }
735
724
  if (isStructType(targetGoType, this.mod.checker, this.mod)) {
736
725
  const sInfo = this.mod.getStructType(this._structNameOf(targetGoType));
737
- const box = this.mod.getBoxType(targetGoType);
726
+ const box = this.mod.getIfaceBoxType(targetGoType);
738
727
  if (sInfo && box) {
739
- this.pushInstruction({
740
- op: "ref.cast_null",
741
- typeIndex: box.typeIndex,
742
- });
743
- this.pushInstruction({
744
- op: "struct.get",
745
- typeIndex: box.typeIndex,
746
- fieldIndex: 0,
747
- });
728
+ this._emitUnbox(box);
748
729
  this.emitCloneStruct(sInfo, targetWType);
749
730
  return;
750
731
  }
@@ -775,21 +756,25 @@ export class StmtsEmitter {
775
756
  }
776
757
 
777
758
  // Scalar types
778
- const box = this.mod.getBoxType(targetGoType);
759
+ const box = this.mod.getIfaceBoxType(targetGoType);
779
760
  if (box) {
780
- this.pushInstruction({
781
- op: "ref.cast_null",
782
- typeIndex: box.typeIndex,
783
- });
784
- this.pushInstruction({
785
- op: "struct.get",
786
- typeIndex: box.typeIndex,
787
- fieldIndex: 0,
788
- });
761
+ this._emitUnbox(box);
789
762
  return;
790
763
  }
791
764
  }
792
765
 
766
+ _emitUnbox(box) {
767
+ this.pushInstruction({
768
+ op: "ref.cast_null",
769
+ typeIndex: box.typeIndex,
770
+ });
771
+ this.pushInstruction({
772
+ op: "struct.get",
773
+ typeIndex: box.typeIndex,
774
+ fieldIndex: 0,
775
+ });
776
+ }
777
+
793
778
  _emitCompoundAssign(lhs, rhs, op) {
794
779
  const baseOp = op.slice(0, -1);
795
780
  const l = Array.isArray(lhs) ? lhs[0] : lhs;
@@ -938,6 +923,38 @@ export class StmtsEmitter {
938
923
  return;
939
924
  }
940
925
 
926
+ if ((l.kind === "UnaryExpr" && l.op === "*") || l.kind === "StarExpr") {
927
+ const operand = l.operand ?? l.expr;
928
+ const box = this.mod.getBoxType(operand._type?.base ?? operand._type);
929
+ if (box) {
930
+ const baseWType = {
931
+ kind: "ref",
932
+ nullable: true,
933
+ typeIndex: box.typeIndex,
934
+ };
935
+ const boxTmp = this.acquireTemp(baseWType);
936
+ this.emitExpr(operand, baseWType);
937
+ this.pushInstruction({ op: "local.set", index: boxTmp });
938
+ this.pushInstruction({ op: "local.get", index: boxTmp });
939
+ this.pushInstruction({ op: "local.get", index: boxTmp });
940
+ this.pushInstruction({
941
+ op: "struct.get",
942
+ typeIndex: box.typeIndex,
943
+ fieldIndex: 0,
944
+ });
945
+ const targetType = box.wType;
946
+ this.emitExpr(r, targetType);
947
+ this.emitBinaryOp(baseOp, targetType, l._type ?? operand._type?.base);
948
+ this.pushInstruction({
949
+ op: "struct.set",
950
+ typeIndex: box.typeIndex,
951
+ fieldIndex: 0,
952
+ });
953
+ this.releaseTemp(boxTmp, baseWType);
954
+ return;
955
+ }
956
+ }
957
+
941
958
  if (l.kind !== "Ident") return;
942
959
 
943
960
  const localInfo = this.resolveLocal(l.name);
@@ -1016,6 +1033,46 @@ export class StmtsEmitter {
1016
1033
  emitIncDecStmt(stmt) {
1017
1034
  const { expr, op } = stmt;
1018
1035
 
1036
+ if (
1037
+ (expr.kind === "UnaryExpr" && expr.op === "*") ||
1038
+ expr.kind === "StarExpr"
1039
+ ) {
1040
+ const operand = expr.operand ?? expr.expr;
1041
+ const structInfo = this._resolveStructInfo(operand);
1042
+ if (!structInfo) {
1043
+ const box = this.mod.getBoxType(operand._type?.base ?? operand._type);
1044
+ if (box) {
1045
+ const baseWType = {
1046
+ kind: "ref",
1047
+ nullable: true,
1048
+ typeIndex: box.typeIndex,
1049
+ };
1050
+ const boxTmp = this.acquireTemp(baseWType);
1051
+ this.emitExpr(operand, baseWType);
1052
+ this.pushInstruction({ op: "local.set", index: boxTmp });
1053
+ this.pushInstruction({ op: "local.get", index: boxTmp });
1054
+ this.pushInstruction({ op: "local.get", index: boxTmp });
1055
+ this.pushInstruction({
1056
+ op: "struct.get",
1057
+ typeIndex: box.typeIndex,
1058
+ fieldIndex: 0,
1059
+ });
1060
+ this._emitIncDecStep(
1061
+ op,
1062
+ box.wType,
1063
+ operand._type?.base ?? operand._type,
1064
+ );
1065
+ this.pushInstruction({
1066
+ op: "struct.set",
1067
+ typeIndex: box.typeIndex,
1068
+ fieldIndex: 0,
1069
+ });
1070
+ this.releaseTemp(boxTmp, baseWType);
1071
+ return;
1072
+ }
1073
+ }
1074
+ }
1075
+
1019
1076
  if (expr.kind === "SelectorExpr") {
1020
1077
  const structInfo = this._resolveStructInfo(expr.expr);
1021
1078
  if (!structInfo) return;
@@ -1046,20 +1103,7 @@ export class StmtsEmitter {
1046
1103
  fieldIndex: lastStep.fieldIndex,
1047
1104
  });
1048
1105
 
1049
- if (targetType === "i64") {
1050
- this.pushInstruction({ op: "i64.const", value: 1n });
1051
- this.pushInstruction(op === "++" ? "i64.add" : "i64.sub");
1052
- } else if (targetType === "f32") {
1053
- this.pushInstruction({ op: "f32.const", value: 1.0 });
1054
- this.pushInstruction(op === "++" ? "f32.add" : "f32.sub");
1055
- } else if (targetType === "f64") {
1056
- this.pushInstruction({ op: "f64.const", value: 1.0 });
1057
- this.pushInstruction(op === "++" ? "f64.add" : "f64.sub");
1058
- } else {
1059
- this.pushInstruction({ op: "i32.const", value: 1 });
1060
- this.pushInstruction(op === "++" ? "i32.add" : "i32.sub");
1061
- this.emitNarrowIntWrap(expr._type);
1062
- }
1106
+ this._emitIncDecStep(op, targetType, expr._type);
1063
1107
 
1064
1108
  this.pushInstruction({
1065
1109
  op: "struct.set",
@@ -1096,20 +1140,7 @@ export class StmtsEmitter {
1096
1140
  funcIndex: this.mod.resolveFuncIndex(mapInfo.getFuncName),
1097
1141
  });
1098
1142
 
1099
- if (mapInfo.valWType === "i64") {
1100
- this.pushInstruction({ op: "i64.const", value: 1n });
1101
- this.pushInstruction(op === "++" ? "i64.add" : "i64.sub");
1102
- } else if (mapInfo.valWType === "f32") {
1103
- this.pushInstruction({ op: "f32.const", value: 1.0 });
1104
- this.pushInstruction(op === "++" ? "f32.add" : "f32.sub");
1105
- } else if (mapInfo.valWType === "f64") {
1106
- this.pushInstruction({ op: "f64.const", value: 1.0 });
1107
- this.pushInstruction(op === "++" ? "f64.add" : "f64.sub");
1108
- } else {
1109
- this.pushInstruction({ op: "i32.const", value: 1 });
1110
- this.pushInstruction(op === "++" ? "i32.add" : "i32.sub");
1111
- this.emitNarrowIntWrap(valType);
1112
- }
1143
+ this._emitIncDecStep(op, mapInfo.valWType, valType);
1113
1144
 
1114
1145
  this.pushInstruction({
1115
1146
  op: "call",
@@ -1167,20 +1198,7 @@ export class StmtsEmitter {
1167
1198
  typeIndex: arrInfo.typeIndex,
1168
1199
  });
1169
1200
 
1170
- if (targetType === "i64") {
1171
- this.pushInstruction({ op: "i64.const", value: 1n });
1172
- this.pushInstruction(op === "++" ? "i64.add" : "i64.sub");
1173
- } else if (targetType === "f32") {
1174
- this.pushInstruction({ op: "f32.const", value: 1.0 });
1175
- this.pushInstruction(op === "++" ? "f32.add" : "f32.sub");
1176
- } else if (targetType === "f64") {
1177
- this.pushInstruction({ op: "f64.const", value: 1.0 });
1178
- this.pushInstruction(op === "++" ? "f64.add" : "f64.sub");
1179
- } else {
1180
- this.pushInstruction({ op: "i32.const", value: 1 });
1181
- this.pushInstruction(op === "++" ? "i32.add" : "i32.sub");
1182
- this.emitNarrowIntWrap(elemGoType);
1183
- }
1201
+ this._emitIncDecStep(op, targetType, elemGoType);
1184
1202
 
1185
1203
  this.pushInstruction({
1186
1204
  op: "array.set",
@@ -1199,7 +1217,6 @@ export class StmtsEmitter {
1199
1217
 
1200
1218
  if (localInfo?.isBoxed) {
1201
1219
  const boxInfo = localInfo.boxInfo;
1202
- const innerWType = boxInfo.wType;
1203
1220
  this.pushInstruction({ op: "local.get", index: localInfo.index });
1204
1221
  this.pushInstruction({ op: "local.get", index: localInfo.index });
1205
1222
  this.pushInstruction({
@@ -1207,20 +1224,7 @@ export class StmtsEmitter {
1207
1224
  typeIndex: boxInfo.typeIndex,
1208
1225
  fieldIndex: 0,
1209
1226
  });
1210
- if (innerWType === "i64") {
1211
- this.pushInstruction({ op: "i64.const", value: 1n });
1212
- this.pushInstruction(op === "++" ? "i64.add" : "i64.sub");
1213
- } else if (innerWType === "f32") {
1214
- this.pushInstruction({ op: "f32.const", value: 1.0 });
1215
- this.pushInstruction(op === "++" ? "f32.add" : "f32.sub");
1216
- } else if (innerWType === "f64") {
1217
- this.pushInstruction({ op: "f64.const", value: 1.0 });
1218
- this.pushInstruction(op === "++" ? "f64.add" : "f64.sub");
1219
- } else {
1220
- this.pushInstruction({ op: "i32.const", value: 1 });
1221
- this.pushInstruction(op === "++" ? "i32.add" : "i32.sub");
1222
- this.emitNarrowIntWrap(localInfo.goType);
1223
- }
1227
+ this._emitIncDecStep(op, boxInfo.wType, localInfo.goType);
1224
1228
  this.pushInstruction({
1225
1229
  op: "struct.set",
1226
1230
  typeIndex: boxInfo.typeIndex,
@@ -1237,20 +1241,7 @@ export class StmtsEmitter {
1237
1241
  this.pushInstruction({ op: "global.get", index: globalInfo.index });
1238
1242
  }
1239
1243
 
1240
- if (targetType === "i64") {
1241
- this.pushInstruction({ op: "i64.const", value: 1n });
1242
- this.pushInstruction(op === "++" ? "i64.add" : "i64.sub");
1243
- } else if (targetType === "f32") {
1244
- this.pushInstruction({ op: "f32.const", value: 1.0 });
1245
- this.pushInstruction(op === "++" ? "f32.add" : "f32.sub");
1246
- } else if (targetType === "f64") {
1247
- this.pushInstruction({ op: "f64.const", value: 1.0 });
1248
- this.pushInstruction(op === "++" ? "f64.add" : "f64.sub");
1249
- } else {
1250
- this.pushInstruction({ op: "i32.const", value: 1 });
1251
- this.pushInstruction(op === "++" ? "i32.add" : "i32.sub");
1252
- this.emitNarrowIntWrap(expr._type);
1253
- }
1244
+ this._emitIncDecStep(op, targetType, expr._type);
1254
1245
 
1255
1246
  if (localInfo) {
1256
1247
  this.pushInstruction({ op: "local.set", index: localInfo.index });
@@ -1260,6 +1251,21 @@ export class StmtsEmitter {
1260
1251
  }
1261
1252
  }
1262
1253
 
1254
+ _emitIncDecStep(op, targetType, goType) {
1255
+ const isAdd = op === "++";
1256
+ if (targetType === "i64") {
1257
+ this.pushInstruction({ op: "i64.const", value: 1n });
1258
+ this.pushInstruction(isAdd ? "i64.add" : "i64.sub");
1259
+ } else if (targetType === "f32" || targetType === "f64") {
1260
+ this.pushInstruction({ op: `${targetType}.const`, value: 1.0 });
1261
+ this.pushInstruction(`${targetType}.${isAdd ? "add" : "sub"}`);
1262
+ } else {
1263
+ this.pushInstruction({ op: "i32.const", value: 1 });
1264
+ this.pushInstruction(isAdd ? "i32.add" : "i32.sub");
1265
+ this.emitNarrowIntWrap(goType);
1266
+ }
1267
+ }
1268
+
1263
1269
  emitIfStmt(stmt) {
1264
1270
  if (stmt.init) this.emitStmt(stmt.init);
1265
1271
 
@@ -1775,8 +1781,9 @@ export class StmtsEmitter {
1775
1781
  nullable: true,
1776
1782
  typeIndex: arrInfo.typeIndex,
1777
1783
  };
1778
- const arrTmp = this.acquireTemp(arrWType);
1779
- const offTmp = this.acquireTemp("i32");
1784
+ const hasVal = Boolean(lhs[1] && lhs[1].name !== "_");
1785
+ const arrTmp = hasVal ? this.acquireTemp(arrWType) : null;
1786
+ const offTmp = hasVal ? this.acquireTemp("i32") : null;
1780
1787
  const lenTmp = this.acquireTemp("i32");
1781
1788
 
1782
1789
  if (isSlice) {
@@ -1789,18 +1796,26 @@ export class StmtsEmitter {
1789
1796
  this.emitExpr(iterExpr, sliceWType);
1790
1797
  this.pushInstruction({ op: "local.set", index: sliceTmp });
1791
1798
 
1792
- this._emitSliceUnpack(sliceTmp, sliceInfo, {
1793
- arr: arrTmp,
1794
- off: offTmp,
1795
- len: lenTmp,
1796
- });
1799
+ if (hasVal) {
1800
+ this._emitSliceUnpack(sliceTmp, sliceInfo, {
1801
+ arr: arrTmp,
1802
+ off: offTmp,
1803
+ len: lenTmp,
1804
+ });
1805
+ } else {
1806
+ this._emitSliceUnpack(sliceTmp, sliceInfo, {
1807
+ len: lenTmp,
1808
+ });
1809
+ }
1797
1810
  this.releaseTemp(sliceTmp, sliceWType);
1798
1811
  } else {
1799
1812
  this.emitExpr(iterExpr, arrWType);
1800
- this.pushInstruction({ op: "local.set", index: arrTmp });
1801
- this.pushInstruction({ op: "i32.const", value: 0 });
1802
- this.pushInstruction({ op: "local.set", index: offTmp });
1803
- this.pushInstruction({ op: "local.get", index: arrTmp });
1813
+ if (hasVal) {
1814
+ this.pushInstruction({ op: "local.set", index: arrTmp });
1815
+ this.pushInstruction({ op: "i32.const", value: 0 });
1816
+ this.pushInstruction({ op: "local.set", index: offTmp });
1817
+ this.pushInstruction({ op: "local.get", index: arrTmp });
1818
+ }
1804
1819
  this.pushInstruction("array.len");
1805
1820
  this.pushInstruction({ op: "local.set", index: lenTmp });
1806
1821
  }
@@ -1934,8 +1949,8 @@ export class StmtsEmitter {
1934
1949
 
1935
1950
  this.releaseTemp(idxTmp, "i32");
1936
1951
  this.releaseTemp(lenTmp, "i32");
1937
- this.releaseTemp(offTmp, "i32");
1938
- this.releaseTemp(arrTmp, arrWType);
1952
+ if (offTmp !== null) this.releaseTemp(offTmp, "i32");
1953
+ if (arrTmp !== null) this.releaseTemp(arrTmp, arrWType);
1939
1954
 
1940
1955
  restoreShadowed();
1941
1956
  }
@@ -2185,74 +2200,53 @@ export class StmtsEmitter {
2185
2200
  if (stmt.init) this.emitStmt(stmt.init);
2186
2201
 
2187
2202
  const getCaseVals = (c) => c.list ?? c.values ?? [];
2203
+ const nonDefaultCases = (stmt.cases ?? []).filter(
2204
+ (c) => getCaseVals(c).length > 0,
2205
+ );
2206
+ const defaultCase = (stmt.cases ?? []).find(
2207
+ (c) => getCaseVals(c).length === 0,
2208
+ );
2188
2209
 
2210
+ let tagGoType = null;
2211
+ let tagWType = null;
2212
+ let tagTmp = -1;
2189
2213
  if (stmt.tag) {
2190
- const tagGoType = stmt.tag._type ?? this._resolveExprGoType(stmt.tag);
2191
- const tagWType = this.toWasmType(tagGoType);
2192
- const tagTmp = this.acquireTemp(tagWType);
2214
+ tagGoType = stmt.tag._type ?? this._resolveExprGoType(stmt.tag);
2215
+ tagWType = this.toWasmType(tagGoType);
2216
+ tagTmp = this.acquireTemp(tagWType);
2193
2217
  this.emitExpr(stmt.tag, tagWType);
2194
2218
  this.pushInstruction({ op: "local.set", index: tagTmp });
2219
+ }
2195
2220
 
2196
- const nonDefaultCases = (stmt.cases ?? []).filter(
2197
- (c) => getCaseVals(c).length > 0,
2198
- );
2199
- const defaultCase = (stmt.cases ?? []).find(
2200
- (c) => getCaseVals(c).length === 0,
2201
- );
2202
-
2203
- let ifCount = 0;
2204
- for (const c of nonDefaultCases) {
2205
- const vals = getCaseVals(c);
2206
- for (let i = 0; i < vals.length; i++) {
2221
+ let ifCount = 0;
2222
+ for (const c of nonDefaultCases) {
2223
+ const vals = getCaseVals(c);
2224
+ for (let i = 0; i < vals.length; i++) {
2225
+ if (stmt.tag) {
2207
2226
  this.pushInstruction({ op: "local.get", index: tagTmp });
2208
2227
  this.emitExpr(vals[i], tagWType);
2209
2228
  this.emitBinaryOp("==", tagWType, tagGoType);
2210
- if (i > 0) this.pushInstruction("i32.or");
2211
- }
2212
- this.pushInstruction({ op: "if", blockType: "void" });
2213
- ifCount++;
2214
-
2215
- for (const s of c.stmts ?? []) this.emitStmt(s);
2216
- this.pushInstruction("else");
2217
- }
2218
-
2219
- if (defaultCase) {
2220
- for (const s of defaultCase.stmts ?? []) this.emitStmt(s);
2221
- }
2222
-
2223
- for (let i = 0; i < ifCount; i++) {
2224
- this.pushInstruction("end");
2225
- }
2226
- this.releaseTemp(tagTmp, tagWType);
2227
- } else {
2228
- const nonDefaultCases = (stmt.cases ?? []).filter(
2229
- (c) => getCaseVals(c).length > 0,
2230
- );
2231
- const defaultCase = (stmt.cases ?? []).find(
2232
- (c) => getCaseVals(c).length === 0,
2233
- );
2234
-
2235
- let ifCount = 0;
2236
- for (const c of nonDefaultCases) {
2237
- const vals = getCaseVals(c);
2238
- for (let i = 0; i < vals.length; i++) {
2229
+ } else {
2239
2230
  this.emitExpr(vals[i], "i32");
2240
- if (i > 0) this.pushInstruction("i32.or");
2241
2231
  }
2242
- this.pushInstruction({ op: "if", blockType: "void" });
2243
- ifCount++;
2244
-
2245
- for (const s of c.stmts ?? []) this.emitStmt(s);
2246
- this.pushInstruction("else");
2232
+ if (i > 0) this.pushInstruction("i32.or");
2247
2233
  }
2234
+ this.pushInstruction({ op: "if", blockType: "void" });
2235
+ ifCount++;
2248
2236
 
2249
- if (defaultCase) {
2250
- for (const s of defaultCase.stmts ?? []) this.emitStmt(s);
2251
- }
2237
+ for (const s of c.stmts ?? []) this.emitStmt(s);
2238
+ this.pushInstruction("else");
2239
+ }
2252
2240
 
2253
- for (let i = 0; i < ifCount; i++) {
2254
- this.pushInstruction("end");
2255
- }
2241
+ if (defaultCase) {
2242
+ for (const s of defaultCase.stmts ?? []) this.emitStmt(s);
2243
+ }
2244
+
2245
+ for (let i = 0; i < ifCount; i++) {
2246
+ this.pushInstruction("end");
2247
+ }
2248
+ if (stmt.tag) {
2249
+ this.releaseTemp(tagTmp, tagWType);
2256
2250
  }
2257
2251
 
2258
2252
  this.pushInstruction("end");