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.
- package/README.md +35 -39
- package/package.json +37 -4
- package/src/backend/js/expressions.js +559 -144
- package/src/backend/js/index.js +174 -49
- package/src/backend/js/runtime.js +1518 -54
- package/src/backend/js/statements.js +91 -73
- package/src/backend/js/stdlib/base64.js +12 -0
- package/src/backend/js/stdlib/binary.js +102 -0
- package/src/backend/js/stdlib/bits.js +15 -1
- package/src/backend/js/stdlib/builder.js +28 -9
- package/src/backend/js/stdlib/bytes.js +75 -18
- package/src/backend/js/stdlib/errors.js +25 -1
- package/src/backend/js/stdlib/fmt.js +70 -13
- package/src/backend/js/stdlib/hex.js +17 -0
- package/src/backend/js/stdlib/html.js +1 -1
- package/src/backend/js/stdlib/index.js +28 -0
- package/src/backend/js/stdlib/io.js +105 -3
- package/src/backend/js/stdlib/json.js +972 -0
- package/src/backend/js/stdlib/math.js +13 -1
- package/src/backend/js/stdlib/path.js +18 -4
- package/src/backend/js/stdlib/rand.js +10 -5
- package/src/backend/js/stdlib/sha256.js +12 -0
- package/src/backend/js/stdlib/simd.js +24 -0
- package/src/backend/js/stdlib/slices.js +52 -26
- package/src/backend/js/stdlib/strconv.js +21 -5
- package/src/backend/js/stdlib/strings.js +148 -15
- package/src/backend/js/stdlib/sync.js +13 -0
- package/src/backend/js/stdlib/time.js +90 -19
- package/src/backend/js/stdlib/unicode.js +2 -2
- package/src/backend/wasm/boundary.js +1225 -41
- package/src/backend/wasm/const-fold.js +205 -0
- package/src/backend/wasm/emit-builtins.js +220 -76
- package/src/backend/wasm/emit-exprs.js +475 -276
- package/src/backend/wasm/emit-maps.js +144 -8
- package/src/backend/wasm/emit-stdlib.js +12 -3005
- package/src/backend/wasm/emit-stmts.js +264 -270
- package/src/backend/wasm/emit.js +124 -87
- package/src/backend/wasm/encode.js +140 -29
- package/src/backend/wasm/index.js +1001 -32
- package/src/backend/wasm/optimize.js +17 -6
- package/src/backend/wasm/stdlib/bytes.js +5039 -0
- package/src/backend/wasm/stdlib/core.js +8903 -0
- package/src/backend/wasm/stdlib/index.js +43 -0
- package/src/backend/wasm/stdlib/io.js +2161 -0
- package/src/backend/wasm/stdlib/packages.js +2400 -0
- package/src/backend/wasm/stdlib/pure.js +720 -0
- package/src/backend/wasm/stdlib/simd.js +234 -0
- package/src/backend/wasm/stdlib/time.js +1200 -0
- package/src/backend/wasm/types.js +174 -1
- package/src/backend/wasm/wat.js +37 -0
- package/src/cli-core.js +1 -1
- package/src/compiler.js +18 -4
- package/src/dts-parser.js +150 -140
- package/src/index.js +2 -6
- package/src/lexer.js +80 -29
- package/src/lower/boxing.js +1 -7
- package/src/lower/captures.js +2 -6
- package/src/lower/embedding.js +2 -1
- package/src/lower/ownership.js +30 -9
- package/src/minifier.js +20 -68
- package/src/parser/declarations.js +3 -6
- package/src/parser/expressions.js +3 -8
- package/src/parser/index.js +18 -3
- package/src/parser/statements.js +25 -38
- package/src/parser/struct-tag.js +144 -0
- package/src/parser/types.js +64 -8
- package/src/resolver.js +2 -27
- package/src/templ-lexer.js +29 -63
- package/src/templ-parser.js +22 -45
- package/src/typechecker/assignability.js +126 -13
- package/src/typechecker/expressions.js +168 -16
- package/src/typechecker/index.js +35 -8
- package/src/typechecker/resolve.js +187 -8
- package/src/typechecker/statements.js +68 -9
- package/src/typechecker/stdlib/core.js +280 -89
- package/src/typechecker/stdlib/extended.js +490 -1
- package/src/typechecker/stdlib/simd.js +73 -0
- package/src/typechecker/stdlib.js +2 -0
- package/src/typechecker/types.js +362 -9
- package/src/vendor.js +86 -11
package/src/backend/js/index.js
CHANGED
|
@@ -28,22 +28,37 @@ import { isComplex, isNumeric } from "../../typechecker/types.js";
|
|
|
28
28
|
import { expressionGenMethods } from "./expressions.js";
|
|
29
29
|
import {
|
|
30
30
|
HELPER_APPEND,
|
|
31
|
+
HELPER_BASE64,
|
|
32
|
+
HELPER_BINARY,
|
|
31
33
|
HELPER_CDIV,
|
|
32
34
|
HELPER_CMUL,
|
|
35
|
+
HELPER_CRYPTO_RAND,
|
|
36
|
+
HELPER_DURATION,
|
|
33
37
|
HELPER_EQUAL,
|
|
34
38
|
HELPER_ERROR,
|
|
39
|
+
HELPER_ERROR_AS,
|
|
35
40
|
HELPER_ERROR_IS,
|
|
41
|
+
HELPER_ERROR_JOIN,
|
|
42
|
+
HELPER_HEX,
|
|
36
43
|
HELPER_IFACE_BOX,
|
|
44
|
+
HELPER_IFEQ,
|
|
37
45
|
HELPER_INJECT_STYLES,
|
|
46
|
+
HELPER_IO_EOF,
|
|
47
|
+
HELPER_JSON,
|
|
38
48
|
HELPER_LEN,
|
|
39
49
|
HELPER_NIL_CALL,
|
|
40
50
|
HELPER_PANIC,
|
|
41
51
|
HELPER_PATH_CLEAN,
|
|
52
|
+
HELPER_PATH_ERROR,
|
|
42
53
|
HELPER_S,
|
|
43
54
|
HELPER_SCLONE,
|
|
55
|
+
HELPER_SHA256,
|
|
56
|
+
HELPER_SIMD,
|
|
44
57
|
HELPER_SORT_SLICE,
|
|
45
58
|
HELPER_SPRINTF,
|
|
46
59
|
HELPER_STRCONV,
|
|
60
|
+
HELPER_STRCONV_ERROR,
|
|
61
|
+
HELPER_SYNC,
|
|
47
62
|
HELPER_TESTING,
|
|
48
63
|
HELPER_TIME_FMT,
|
|
49
64
|
HELPER_TIME_PARSE,
|
|
@@ -104,6 +119,7 @@ const HELPER_MAP = [
|
|
|
104
119
|
["sclone", HELPER_SCLONE],
|
|
105
120
|
["ifaceBox", HELPER_IFACE_BOX],
|
|
106
121
|
["equal", HELPER_EQUAL],
|
|
122
|
+
["ifeq", HELPER_IFEQ],
|
|
107
123
|
["cmul", HELPER_CMUL],
|
|
108
124
|
["cdiv", HELPER_CDIV],
|
|
109
125
|
["panicRt", HELPER_PANIC],
|
|
@@ -111,12 +127,26 @@ const HELPER_MAP = [
|
|
|
111
127
|
["sprintf", HELPER_SPRINTF],
|
|
112
128
|
["error", HELPER_ERROR],
|
|
113
129
|
["errorIs", HELPER_ERROR_IS],
|
|
130
|
+
["errorAs", HELPER_ERROR_AS],
|
|
131
|
+
["errorJoin", HELPER_ERROR_JOIN],
|
|
132
|
+
["strconvError", HELPER_STRCONV_ERROR],
|
|
133
|
+
["pathError", HELPER_PATH_ERROR],
|
|
134
|
+
["ioEOF", HELPER_IO_EOF],
|
|
114
135
|
["strconv", HELPER_STRCONV],
|
|
115
136
|
["pathClean", HELPER_PATH_CLEAN],
|
|
116
137
|
["sortSlice", HELPER_SORT_SLICE],
|
|
117
138
|
["timeFmt", HELPER_TIME_FMT],
|
|
118
139
|
["timeParse", HELPER_TIME_PARSE],
|
|
140
|
+
["duration", HELPER_DURATION],
|
|
119
141
|
["testing", HELPER_TESTING],
|
|
142
|
+
["sync", HELPER_SYNC],
|
|
143
|
+
["cryptoRand", HELPER_CRYPTO_RAND],
|
|
144
|
+
["sha256", HELPER_SHA256],
|
|
145
|
+
["binary", HELPER_BINARY],
|
|
146
|
+
["hex", HELPER_HEX],
|
|
147
|
+
["base64", HELPER_BASE64],
|
|
148
|
+
["json", HELPER_JSON],
|
|
149
|
+
["simd", HELPER_SIMD],
|
|
120
150
|
];
|
|
121
151
|
|
|
122
152
|
export class CodeGen {
|
|
@@ -144,6 +174,7 @@ export class CodeGen {
|
|
|
144
174
|
this._srcMappings = []; // { genLine, srcLine, srcFileIdx } for source map
|
|
145
175
|
this._currentSrcFileIdx = 0; // updated as each top-level decl is generated
|
|
146
176
|
this._boxedVars = new Set(); // address-taken scalar variables that need boxing
|
|
177
|
+
this._jsonCodecs = new Map(); // memoized JSON encoders and decoders
|
|
147
178
|
// Runtime helper usage tracking — only emit helpers that are actually used
|
|
148
179
|
this._helpers = new Set();
|
|
149
180
|
// Per-function context for Go value semantics (see _withFnCtx)
|
|
@@ -249,6 +280,7 @@ export class CodeGen {
|
|
|
249
280
|
this._emitTypeDecls(program, methods);
|
|
250
281
|
this._emitVarConstDecls(program);
|
|
251
282
|
const initNames = this._emitFuncDecls(program);
|
|
283
|
+
this._emitJsonCodecs();
|
|
252
284
|
this._callInitAndMain(initNames, program, isTest);
|
|
253
285
|
const prependedLines = this._prependHelpers(isTest);
|
|
254
286
|
return this._finalizeOutput(prependedLines);
|
|
@@ -428,6 +460,23 @@ export class CodeGen {
|
|
|
428
460
|
/** Marks a runtime helper (key of HELPER_MAP) as needed by the output. */
|
|
429
461
|
useHelper(name) {
|
|
430
462
|
this._helpers.add(name);
|
|
463
|
+
if (
|
|
464
|
+
name === "strconvError" ||
|
|
465
|
+
name === "pathError" ||
|
|
466
|
+
name === "ioEOF" ||
|
|
467
|
+
name === "base64" ||
|
|
468
|
+
name === "hex" ||
|
|
469
|
+
name === "json"
|
|
470
|
+
) {
|
|
471
|
+
this._helpers.add("error");
|
|
472
|
+
}
|
|
473
|
+
if (name === "json") {
|
|
474
|
+
this.useHelper("base64");
|
|
475
|
+
}
|
|
476
|
+
if (name === "binary") {
|
|
477
|
+
this.useHelper("ioEOF");
|
|
478
|
+
this._helpers.add("error");
|
|
479
|
+
}
|
|
431
480
|
}
|
|
432
481
|
|
|
433
482
|
_prependHelpers(isTest = false) {
|
|
@@ -496,29 +545,61 @@ export class CodeGen {
|
|
|
496
545
|
|
|
497
546
|
genNamedTypeClass(name, methodDecls) {
|
|
498
547
|
const namedType = this.checker?.types.get(name);
|
|
499
|
-
const
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
ctorDefault = "null";
|
|
504
|
-
} else if (underlying?.kind === "map") {
|
|
505
|
-
field = "_map";
|
|
506
|
-
ctorDefault = "{}";
|
|
507
|
-
} else {
|
|
508
|
-
field = "_items";
|
|
509
|
-
ctorDefault = "[]";
|
|
510
|
-
}
|
|
548
|
+
const field = this._namedBoxField(namedType?.underlying);
|
|
549
|
+
// Values of the type stay raw (number, string, array, map, function); the
|
|
550
|
+
// class is only the box used when a value is stored in an interface.
|
|
551
|
+
// Methods are static (`T.$M(recv, ...)`) so raw values can call them.
|
|
511
552
|
this.line(`class ${name} {`);
|
|
512
553
|
this.indented(() => {
|
|
513
|
-
this.line(
|
|
514
|
-
|
|
515
|
-
);
|
|
554
|
+
this.line(`constructor(${field}) { this.${field} = ${field}; }`);
|
|
555
|
+
this.line(`__gfUnbox() { return this.${field}; }`);
|
|
516
556
|
for (const m of methodDecls) {
|
|
517
557
|
this.blank();
|
|
518
|
-
this.genMethod(m,
|
|
558
|
+
this.genMethod(m, { staticNamed: true });
|
|
559
|
+
if (!m.recvPointer) {
|
|
560
|
+
this.line(
|
|
561
|
+
`${m.name}(...__a) { return ${name}.$${m.name}(this.${field}, ...__a); }`,
|
|
562
|
+
);
|
|
563
|
+
}
|
|
519
564
|
}
|
|
520
565
|
});
|
|
521
566
|
this.line("}");
|
|
567
|
+
// Box for *T in an interface. It also proxies `.value` to the pointer, so
|
|
568
|
+
// helpers that write through a pointer argument (errors.As, json.Unmarshal)
|
|
569
|
+
// keep working. Pointer methods get the { value } box, value methods its value.
|
|
570
|
+
this.line(`class ${name}$Ptr {`);
|
|
571
|
+
this.indented(() => {
|
|
572
|
+
this.line("constructor(_p) { this._p = _p; }");
|
|
573
|
+
this.line("__gfUnbox() { return this._p; }");
|
|
574
|
+
this.line("get value() { return this._p.value; }");
|
|
575
|
+
this.line("set value(v) { this._p.value = v; }");
|
|
576
|
+
for (const m of methodDecls) {
|
|
577
|
+
const recv = m.recvPointer ? "this._p" : "this._p.value";
|
|
578
|
+
this.line(
|
|
579
|
+
`${m.name}(...__a) { return ${name}.$${m.name}(${recv}, ...__a); }`,
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
this.line("}");
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
_namedBoxField(underlying) {
|
|
587
|
+
if (underlying?.kind === "func") return "_fn";
|
|
588
|
+
if (underlying?.kind === "map") return "_map";
|
|
589
|
+
return "_items";
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// Box/dispatch info for a named non-struct type with methods, or null.
|
|
593
|
+
_namedBoxInfo(type) {
|
|
594
|
+
if (type?.kind !== "named") return null;
|
|
595
|
+
const u = type.underlying;
|
|
596
|
+
if (!u || u.kind === "struct" || u.kind === "interface") return null;
|
|
597
|
+
const methods = type.methods ?? type._generic?.methods;
|
|
598
|
+
if (!methods || methods.size === 0) return null;
|
|
599
|
+
if (![...methods.values()].some((m) => Object.hasOwn(m ?? {}, "_ptrRecv")))
|
|
600
|
+
return null;
|
|
601
|
+
const cls = this._dequalify(type.name).replace(/\[.*$/, "");
|
|
602
|
+
return { cls, field: this._namedBoxField(u), methods };
|
|
522
603
|
}
|
|
523
604
|
|
|
524
605
|
_collectStructFields(name, structTypeAst) {
|
|
@@ -570,7 +651,7 @@ export class CodeGen {
|
|
|
570
651
|
.map((f) => `${f.name}: ${binding(f)} = ${f.zero}`)
|
|
571
652
|
.join(", ");
|
|
572
653
|
this.line(
|
|
573
|
-
`if (typeof ${first} === "object" && ${first} !== null && ${first}.constructor === Object) ({ ${pattern} } = ${first});`,
|
|
654
|
+
`if (arguments.length === 1 && typeof ${first} === "object" && ${first} !== null && ${first}.constructor === Object) ({ ${pattern} } = ${first});`,
|
|
574
655
|
);
|
|
575
656
|
}
|
|
576
657
|
for (const f of fields) {
|
|
@@ -626,6 +707,14 @@ export class CodeGen {
|
|
|
626
707
|
}
|
|
627
708
|
}
|
|
628
709
|
|
|
710
|
+
_emitJsonCodecs() {
|
|
711
|
+
if (!this._jsonCodecs || this._jsonCodecs.size === 0) return;
|
|
712
|
+
for (const [, code] of this._jsonCodecs) {
|
|
713
|
+
this.line(code);
|
|
714
|
+
this.blank();
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
629
718
|
_genSingleEmbedStubs(embed, declared) {
|
|
630
719
|
const embedName = embed.kind === "named" ? embed.name : null;
|
|
631
720
|
if (!embedName) return;
|
|
@@ -651,36 +740,45 @@ export class CodeGen {
|
|
|
651
740
|
}
|
|
652
741
|
}
|
|
653
742
|
|
|
654
|
-
genMethod(decl,
|
|
743
|
+
genMethod(decl, opts = null) {
|
|
655
744
|
const prevFileIdx = this._currentSrcFileIdx;
|
|
656
745
|
if (decl._srcFileIdx != null) this._currentSrcFileIdx = decl._srcFileIdx;
|
|
657
|
-
const
|
|
658
|
-
const
|
|
659
|
-
|
|
746
|
+
const staticNamed = Boolean(opts?.staticNamed);
|
|
747
|
+
const recvParam =
|
|
748
|
+
decl.recvName && decl.recvName !== "_" ? decl.recvName : "__recv";
|
|
749
|
+
this.line(
|
|
750
|
+
this._methodSignature(decl, staticNamed, recvParam),
|
|
751
|
+
decl._line ?? null,
|
|
752
|
+
);
|
|
660
753
|
const prevBoxed = this._boxedVars;
|
|
661
754
|
this._boxedVars = new Set();
|
|
662
755
|
this._scanAddressTaken(decl.body);
|
|
663
|
-
const prevUnwrapped = this._unwrappedRecv;
|
|
664
756
|
this._withFnCtx(decl.body, () =>
|
|
665
757
|
this.indented(() => {
|
|
666
|
-
if (decl.recvName && decl.recvName !== "_") {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
}
|
|
671
|
-
this.line(`const ${decl.recvName} = ${this._receiverValue(decl)};`);
|
|
672
|
-
}
|
|
758
|
+
if (!staticNamed && decl.recvName && decl.recvName !== "_") {
|
|
759
|
+
this.line(`const ${decl.recvName} = ${this._receiverValue(decl)};`);
|
|
760
|
+
}
|
|
761
|
+
if (staticNamed && this._boxedVars.has(recvParam)) {
|
|
762
|
+
this.line(`${recvParam} = { value: ${recvParam} };`);
|
|
673
763
|
}
|
|
674
764
|
this._emitParamCopies(decl.params);
|
|
675
765
|
this._withNamedReturns(decl, () => this._genBody(decl.body, decl));
|
|
676
766
|
}),
|
|
677
767
|
);
|
|
678
|
-
this._unwrappedRecv = prevUnwrapped;
|
|
679
768
|
this._boxedVars = prevBoxed;
|
|
680
769
|
this.line("}");
|
|
681
770
|
this._currentSrcFileIdx = prevFileIdx;
|
|
682
771
|
}
|
|
683
772
|
|
|
773
|
+
// Static methods of named non-struct types take the receiver as first parameter.
|
|
774
|
+
_methodSignature(decl, staticNamed, recvParam) {
|
|
775
|
+
const params = decl.params.map((p) => p.name);
|
|
776
|
+
const asyncPrefix = decl.async ? "async " : "";
|
|
777
|
+
if (!staticNamed)
|
|
778
|
+
return `${asyncPrefix}${decl.name}(${params.join(", ")}) {`;
|
|
779
|
+
return `static ${asyncPrefix}$${decl.name}(${[recvParam, ...params].join(", ")}) {`;
|
|
780
|
+
}
|
|
781
|
+
|
|
684
782
|
// Value receivers are copies in Go; only materialize the copy when the body mutates it.
|
|
685
783
|
_receiverValue(decl) {
|
|
686
784
|
const name = decl.recvName;
|
|
@@ -696,19 +794,10 @@ export class CodeGen {
|
|
|
696
794
|
return "this";
|
|
697
795
|
}
|
|
698
796
|
|
|
699
|
-
//
|
|
700
|
-
//
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
_namedWrapperField(type, expr = null) {
|
|
704
|
-
if (type?.kind !== "named") return null;
|
|
705
|
-
if (!this.namedWrapperNames.has(type.name)) return null;
|
|
706
|
-
if (expr?.kind === "Ident" && expr.name === this._unwrappedRecv)
|
|
707
|
-
return null;
|
|
708
|
-
const u = type.underlying;
|
|
709
|
-
if (u?.kind === "func") return "_fn";
|
|
710
|
-
if (u?.kind === "map") return "_map";
|
|
711
|
-
return "_items";
|
|
797
|
+
// Named non-struct values are kept raw in the JS backend, so there is no
|
|
798
|
+
// wrapper field to unwrap any more; kept for call-site compatibility.
|
|
799
|
+
_namedWrapperField(_type, _expr = null) {
|
|
800
|
+
return null;
|
|
712
801
|
}
|
|
713
802
|
|
|
714
803
|
// ── Function declarations ────────────────────────────────────
|
|
@@ -822,8 +911,35 @@ export class CodeGen {
|
|
|
822
911
|
}
|
|
823
912
|
|
|
824
913
|
// Scan AST node for _addressTaken idents on scalars and populate _boxedVars.
|
|
914
|
+
// A pointer-receiver method call on a named non-struct local (`l.Set(5)`)
|
|
915
|
+
// takes the variable's address too, so the variable must be boxed.
|
|
825
916
|
_scanAddressTaken(node) {
|
|
826
917
|
scanAddressTaken(node, this._boxedVars);
|
|
918
|
+
const visit = (n) => {
|
|
919
|
+
if (!n || typeof n !== "object") return;
|
|
920
|
+
if (Array.isArray(n)) {
|
|
921
|
+
for (const item of n) visit(item);
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
924
|
+
if (n.kind === "CallExpr" && n.func?.kind === "SelectorExpr") {
|
|
925
|
+
const recv = n.func.expr;
|
|
926
|
+
if (
|
|
927
|
+
recv?.kind === "Ident" &&
|
|
928
|
+
this._namedPtrMethodOn(recv._type, n.func.field)
|
|
929
|
+
)
|
|
930
|
+
this._boxedVars.add(recv.name);
|
|
931
|
+
}
|
|
932
|
+
for (const key of Object.keys(n)) {
|
|
933
|
+
if (key.startsWith("_") || key === "kind") continue;
|
|
934
|
+
visit(n[key]);
|
|
935
|
+
}
|
|
936
|
+
};
|
|
937
|
+
visit(node);
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
_namedPtrMethodOn(type, method) {
|
|
941
|
+
const info = this._namedBoxInfo(type);
|
|
942
|
+
return Boolean(info?.methods.get(method)?._ptrRecv);
|
|
827
943
|
}
|
|
828
944
|
|
|
829
945
|
_isReferenceType(t) {
|
|
@@ -854,12 +970,7 @@ export class CodeGen {
|
|
|
854
970
|
}
|
|
855
971
|
return js;
|
|
856
972
|
});
|
|
857
|
-
|
|
858
|
-
this.line(`let ${spec.names[0]} = ${vals[0]};`);
|
|
859
|
-
} else {
|
|
860
|
-
// let [a, b] = [v1, v2]
|
|
861
|
-
this.line(`let [${spec.names.join(", ")}] = [${vals.join(", ")}];`);
|
|
862
|
-
}
|
|
973
|
+
this._emitVarBindings(spec.names, vals, paired);
|
|
863
974
|
} else {
|
|
864
975
|
const zero = spec.type ? this.zeroValueForTypeNode(spec.type) : "null";
|
|
865
976
|
for (const name of spec.names) {
|
|
@@ -871,6 +982,20 @@ export class CodeGen {
|
|
|
871
982
|
}
|
|
872
983
|
}
|
|
873
984
|
|
|
985
|
+
// `var a = v` / `var a, b = v1, v2` / `var a, b = f()`, boxing address-taken names.
|
|
986
|
+
_emitVarBindings(names, vals, paired) {
|
|
987
|
+
if (names.length === 1) {
|
|
988
|
+
const val = this._boxedVars.has(names[0])
|
|
989
|
+
? `{ value: ${vals[0]} }`
|
|
990
|
+
: vals[0];
|
|
991
|
+
this.line(`let ${names[0]} = ${val};`);
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
const rhs = paired ? `[${vals.join(", ")}]` : vals[0];
|
|
995
|
+
this.line(`let [${names.join(", ")}] = ${rhs};`);
|
|
996
|
+
this._boxDeclaredNames(names);
|
|
997
|
+
}
|
|
998
|
+
|
|
874
999
|
genConstDecl(decl) {
|
|
875
1000
|
for (const spec of decl.decls) {
|
|
876
1001
|
const vals = spec.value.map((v) => this.genExpr(v));
|