gofront 1.5.1 → 1.6.1
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 +174 -466
- package/package.json +16 -20
- package/src/backend/js/expressions.js +288 -128
- package/src/backend/js/index.js +138 -56
- package/src/backend/js/runtime.js +1055 -53
- package/src/backend/js/source-map.js +32 -0
- package/src/backend/js/statements.js +151 -83
- 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 +22 -3
- package/src/backend/js/stdlib/fmt.js +95 -20
- 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 +19 -0
- package/src/backend/js/stdlib/io.js +105 -3
- package/src/backend/js/stdlib/maps.js +1 -1
- package/src/backend/js/stdlib/math.js +13 -1
- package/src/backend/js/stdlib/path.js +20 -6
- package/src/backend/js/stdlib/rand.js +10 -5
- package/src/backend/js/stdlib/sha256.js +12 -0
- package/src/backend/js/stdlib/shared.js +17 -0
- package/src/backend/js/stdlib/slices.js +53 -27
- package/src/backend/js/stdlib/sort.js +1 -1
- package/src/backend/js/stdlib/strconv.js +52 -11
- package/src/backend/js/stdlib/strings.js +152 -16
- package/src/backend/js/stdlib/sync.js +13 -0
- package/src/backend/js/stdlib/testing.js +2 -2
- package/src/backend/js/stdlib/time.js +93 -22
- package/src/backend/js/stdlib/unicode.js +2 -2
- package/src/backend/js/templ.js +1 -1
- package/src/backend/wasm/boundary.js +1677 -58
- package/src/backend/wasm/const-fold.js +205 -0
- package/src/backend/wasm/emit-builtins.js +1230 -0
- package/src/backend/wasm/emit-exprs.js +2096 -0
- package/src/backend/wasm/emit-maps.js +1999 -0
- package/src/backend/wasm/emit-shared.js +519 -0
- package/src/backend/wasm/emit-stdlib.js +13 -0
- package/src/backend/wasm/emit-stmts.js +2466 -0
- package/src/backend/wasm/emit.js +656 -5031
- package/src/backend/wasm/encode.js +259 -85
- package/src/backend/wasm/glue.js +19 -5
- package/src/backend/wasm/index.js +2432 -86
- package/src/backend/wasm/monomorph.js +711 -0
- package/src/backend/wasm/optimize.js +236 -0
- 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 +40 -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/time.js +1200 -0
- package/src/backend/wasm/types.js +312 -36
- package/src/backend/wasm/wat.js +49 -2
- package/src/cli-core.js +276 -73
- package/src/compiler.js +162 -25
- package/src/dts-parser.js +79 -126
- package/src/index.js +88 -121
- package/src/lexer.js +80 -29
- package/src/lower/boxing.js +4 -6
- package/src/lower/captures.js +12 -23
- package/src/lower/escape.js +4 -9
- package/src/lower/functions.js +277 -5
- package/src/lower/globals.js +7 -15
- package/src/lower/index.js +5 -2
- package/src/lower/ownership.js +35 -19
- package/src/lower/range.js +2 -5
- package/src/lower/walk.js +25 -0
- 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/types.js +1 -2
- package/src/resolver.js +3 -27
- package/src/templ-lexer.js +29 -63
- package/src/templ-parser.js +22 -45
- package/src/test-runner.js +20 -0
- package/src/typechecker/assignability.js +123 -14
- package/src/typechecker/expressions.js +244 -4
- package/src/typechecker/index.js +27 -1
- package/src/typechecker/resolve.js +71 -12
- package/src/typechecker/statements.js +0 -7
- package/src/typechecker/stdlib/core.js +292 -103
- package/src/typechecker/stdlib/extended.js +471 -4
- package/src/typechecker/stdlib/shared.js +53 -0
- package/src/typechecker/stdlib.js +2 -0
- package/src/typechecker/types.js +545 -8
- package/src/vendor.js +2 -2
|
@@ -57,3 +57,35 @@ export function buildSourceMap(sources, mappings, sourcesContent) {
|
|
|
57
57
|
if (sourcesContent) map.sourcesContent = sourcesContent;
|
|
58
58
|
return JSON.stringify(map);
|
|
59
59
|
}
|
|
60
|
+
|
|
61
|
+
// WASM source maps use the convention "generated line 0, generated column =
|
|
62
|
+
// byte offset into the module". `mappings` is Array<{ offset, srcFileIdx,
|
|
63
|
+
// srcLine }> (0-based line), one segment per function body (function-level
|
|
64
|
+
// granularity); DevTools shows the Go file/line for each wasm function.
|
|
65
|
+
export function buildWasmSourceMap(sources, mappings, sourcesContent) {
|
|
66
|
+
const sorted = [...mappings].sort((a, b) => a.offset - b.offset);
|
|
67
|
+
const segments = [];
|
|
68
|
+
let prevOffset = 0;
|
|
69
|
+
let prevSrcFile = 0;
|
|
70
|
+
let prevSrcLine = 0;
|
|
71
|
+
for (const m of sorted) {
|
|
72
|
+
const fileIdx = m.srcFileIdx ?? 0;
|
|
73
|
+
segments.push(
|
|
74
|
+
vlqEncode(m.offset - prevOffset) +
|
|
75
|
+
vlqEncode(fileIdx - prevSrcFile) +
|
|
76
|
+
vlqEncode(m.srcLine - prevSrcLine) +
|
|
77
|
+
vlqEncode(0),
|
|
78
|
+
);
|
|
79
|
+
prevOffset = m.offset;
|
|
80
|
+
prevSrcFile = fileIdx;
|
|
81
|
+
prevSrcLine = m.srcLine;
|
|
82
|
+
}
|
|
83
|
+
const map = {
|
|
84
|
+
version: 3,
|
|
85
|
+
sources: sources.map((s) => s.replace(/\\/g, "/")),
|
|
86
|
+
names: [],
|
|
87
|
+
mappings: segments.join(","),
|
|
88
|
+
};
|
|
89
|
+
if (sourcesContent) map.sourcesContent = sourcesContent;
|
|
90
|
+
return JSON.stringify(map);
|
|
91
|
+
}
|
|
@@ -31,27 +31,35 @@ export const statementGenMethods = {
|
|
|
31
31
|
},
|
|
32
32
|
|
|
33
33
|
// Shared helper for comma-ok map index in both DefineStmt and AssignStmt.
|
|
34
|
-
// isDefine=true → emit `let v = m[k]; let ok = k in m;`
|
|
35
|
-
// isDefine=false → emit `v = k in m ? m[k] : zero; ok = k in m;`
|
|
36
34
|
_genCommaOkMapIndex(stmt, rhsNode, isDefine) {
|
|
37
35
|
const mapExpr = this.genExpr(rhsNode.expr);
|
|
38
36
|
const keyExpr = this.genExpr(rhsNode.index);
|
|
39
37
|
const [vName, okName] = stmt.lhs.map((e) => e.name ?? this.genExpr(e));
|
|
40
38
|
const decl = isDefine ? "let " : "";
|
|
41
|
-
if (
|
|
42
|
-
if (
|
|
39
|
+
if (isDefine && !this.strict) {
|
|
40
|
+
if (vName !== "_") {
|
|
43
41
|
this.line(`let ${vName} = ${mapExpr}[${keyExpr}];`);
|
|
44
|
-
} else {
|
|
45
|
-
const zero = rhsNode._mapValueType
|
|
46
|
-
? this.zeroValueForType(rhsNode._mapValueType)
|
|
47
|
-
: "undefined";
|
|
48
|
-
this.line(
|
|
49
|
-
`${vName} = (${keyExpr}) in ${mapExpr} ? ${mapExpr}[${keyExpr}] : ${zero};`,
|
|
50
|
-
);
|
|
51
42
|
}
|
|
43
|
+
if (okName !== "_") {
|
|
44
|
+
this.line(`let ${okName} = (${keyExpr}) in ${mapExpr};`);
|
|
45
|
+
}
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const zero = rhsNode._mapValueType
|
|
49
|
+
? this.zeroValueForType(rhsNode._mapValueType)
|
|
50
|
+
: "undefined";
|
|
51
|
+
this._tmpCounter = (this._tmpCounter ?? 0) + 1;
|
|
52
|
+
const mTmp = `__m${this._tmpCounter}`;
|
|
53
|
+
const kTmp = `__k${this._tmpCounter}`;
|
|
54
|
+
this.line(`const ${mTmp} = ${mapExpr}, ${kTmp} = ${keyExpr};`);
|
|
55
|
+
if (vName !== "_") {
|
|
56
|
+
this.line(
|
|
57
|
+
`${decl}${vName} = (${mTmp} && (${kTmp} in ${mTmp})) ? ${mTmp}[${kTmp}] : ${zero};`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
if (okName !== "_") {
|
|
61
|
+
this.line(`${decl}${okName} = Boolean(${mTmp} && (${kTmp} in ${mTmp}));`);
|
|
52
62
|
}
|
|
53
|
-
if (okName !== "_")
|
|
54
|
-
this.line(`${decl}${okName} = (${keyExpr}) in ${mapExpr};`);
|
|
55
63
|
},
|
|
56
64
|
|
|
57
65
|
genStmt(stmt) {
|
|
@@ -63,6 +71,33 @@ export const statementGenMethods = {
|
|
|
63
71
|
this.genTypeDeclWithMethods(stmt, []);
|
|
64
72
|
break;
|
|
65
73
|
case "IncDecStmt": {
|
|
74
|
+
if (stmt.expr.kind === "IndexExpr" && stmt.expr._mapValueType) {
|
|
75
|
+
const zero = this.zeroValueForType(stmt.expr._mapValueType);
|
|
76
|
+
const wrapField = this._namedWrapperField(
|
|
77
|
+
stmt.expr.expr._type,
|
|
78
|
+
stmt.expr.expr,
|
|
79
|
+
);
|
|
80
|
+
const base = wrapField
|
|
81
|
+
? `${this.genExpr(stmt.expr.expr)}.${wrapField}`
|
|
82
|
+
: this.genExpr(stmt.expr.expr);
|
|
83
|
+
const idx = this.genExpr(stmt.expr.index);
|
|
84
|
+
const op = stmt.op === "++" ? "+" : "-";
|
|
85
|
+
if (
|
|
86
|
+
this._hasCallExpr(stmt.expr.expr) ||
|
|
87
|
+
this._hasCallExpr(stmt.expr.index)
|
|
88
|
+
) {
|
|
89
|
+
this.line(
|
|
90
|
+
`((__m, __k) => { __m[__k] = (__m[__k] ?? ${zero}) ${op} 1; })(${base}, ${idx});`,
|
|
91
|
+
srcLine,
|
|
92
|
+
);
|
|
93
|
+
} else {
|
|
94
|
+
this.line(
|
|
95
|
+
`${base}[${idx}] = (${base}[${idx}] ?? ${zero}) ${op} 1;`,
|
|
96
|
+
srcLine,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
66
101
|
if (
|
|
67
102
|
this.strict &&
|
|
68
103
|
this._genStrictCompound(
|
|
@@ -266,6 +301,35 @@ export const statementGenMethods = {
|
|
|
266
301
|
if (active.length === 0) {
|
|
267
302
|
if (rhs.length > 0) this.line(`${rhs[0]};`);
|
|
268
303
|
} else if (lhs.length === 1) {
|
|
304
|
+
if (
|
|
305
|
+
stmt.op !== "=" &&
|
|
306
|
+
stmt.lhs[0].kind === "IndexExpr" &&
|
|
307
|
+
stmt.lhs[0]._mapValueType
|
|
308
|
+
) {
|
|
309
|
+
const zero = this.zeroValueForType(stmt.lhs[0]._mapValueType);
|
|
310
|
+
const wrapField = this._namedWrapperField(
|
|
311
|
+
stmt.lhs[0].expr._type,
|
|
312
|
+
stmt.lhs[0].expr,
|
|
313
|
+
);
|
|
314
|
+
const base = wrapField
|
|
315
|
+
? `${this.genExpr(stmt.lhs[0].expr)}.${wrapField}`
|
|
316
|
+
: this.genExpr(stmt.lhs[0].expr);
|
|
317
|
+
const idx = this.genExpr(stmt.lhs[0].index);
|
|
318
|
+
const binOp = stmt.op.slice(0, -1);
|
|
319
|
+
if (
|
|
320
|
+
this._hasCallExpr(stmt.lhs[0].expr) ||
|
|
321
|
+
this._hasCallExpr(stmt.lhs[0].index)
|
|
322
|
+
) {
|
|
323
|
+
this.line(
|
|
324
|
+
`((__m, __k) => { __m[__k] = (__m[__k] ?? ${zero}) ${binOp} (${active[0].r}); })(${base}, ${idx});`,
|
|
325
|
+
);
|
|
326
|
+
} else {
|
|
327
|
+
this.line(
|
|
328
|
+
`${base}[${idx}] = (${base}[${idx}] ?? ${zero}) ${binOp} (${active[0].r});`,
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
269
333
|
if (
|
|
270
334
|
this.strict &&
|
|
271
335
|
stmt.op !== "=" &&
|
|
@@ -333,11 +397,11 @@ export const statementGenMethods = {
|
|
|
333
397
|
result = `{ re: ${lhsStr}.re - ${rhsExpr}.re, im: ${lhsStr}.im - ${rhsExpr}.im }`;
|
|
334
398
|
break;
|
|
335
399
|
case "*":
|
|
336
|
-
this.
|
|
400
|
+
this.useHelper("cmul");
|
|
337
401
|
result = `__cmul(${lhsStr}, ${rhsExpr})`;
|
|
338
402
|
break;
|
|
339
403
|
case "/":
|
|
340
|
-
this.
|
|
404
|
+
this.useHelper("cdiv");
|
|
341
405
|
result = `__cdiv(${lhsStr}, ${rhsExpr})`;
|
|
342
406
|
break;
|
|
343
407
|
default:
|
|
@@ -379,6 +443,22 @@ export const statementGenMethods = {
|
|
|
379
443
|
} else {
|
|
380
444
|
this.line("return;");
|
|
381
445
|
}
|
|
446
|
+
} else if (this.namedReturnVars?.length > 0) {
|
|
447
|
+
const vars = this.namedReturnVars;
|
|
448
|
+
if (stmt.values.length === 1 && vars.length === 1) {
|
|
449
|
+
this.line(`${vars[0]} = ${this._genReturnValue(stmt.values[0])};`);
|
|
450
|
+
} else if (stmt.values.length === 1 && vars.length > 1) {
|
|
451
|
+
const val = this._genReturnValue(stmt.values[0]);
|
|
452
|
+
this.line(`[${vars.join(", ")}] = ${val};`);
|
|
453
|
+
} else if (stmt.values.length > 1 && stmt.values.length === vars.length) {
|
|
454
|
+
const temps = stmt.values.map((v) => this._genReturnValue(v));
|
|
455
|
+
this.line(`[${vars.join(", ")}] = [${temps.join(", ")}];`);
|
|
456
|
+
}
|
|
457
|
+
this.line(
|
|
458
|
+
vars.length === 1
|
|
459
|
+
? `return ${vars[0]};`
|
|
460
|
+
: `return [${vars.join(", ")}];`,
|
|
461
|
+
);
|
|
382
462
|
} else if (stmt.values.length === 1) {
|
|
383
463
|
this.line(`return ${this._genReturnValue(stmt.values[0])};`);
|
|
384
464
|
} else {
|
|
@@ -616,6 +696,39 @@ export const statementGenMethods = {
|
|
|
616
696
|
return nodeAssigns(node, name);
|
|
617
697
|
},
|
|
618
698
|
|
|
699
|
+
_genStringRangeFor(stmt, iteree, isAssign) {
|
|
700
|
+
this._loopDepth = this._loopDepth ?? 0;
|
|
701
|
+
const d = this._loopDepth++;
|
|
702
|
+
const [idxNode, valNode] = stmt.init.lhs;
|
|
703
|
+
const s = `__s${d}`;
|
|
704
|
+
const i = `__i${d}`;
|
|
705
|
+
const cp = `__cp${d}`;
|
|
706
|
+
this.line(
|
|
707
|
+
`for (let ${i} = 0, ${s} = Array.from(${iteree} ?? ""); ${i} < ${s}.length; ${i}++) {`,
|
|
708
|
+
);
|
|
709
|
+
this.indented(() => {
|
|
710
|
+
this._emitRangeVar(idxNode, i, isAssign);
|
|
711
|
+
if (valNode && valNode.name !== "_") {
|
|
712
|
+
this.line(`const ${cp} = ${s}[${i}].codePointAt(0);`);
|
|
713
|
+
this._emitRangeVar(valNode, cp, isAssign);
|
|
714
|
+
}
|
|
715
|
+
const declared = isAssign
|
|
716
|
+
? []
|
|
717
|
+
: [idxNode, valNode]
|
|
718
|
+
.filter((e) => e?.kind === "Ident" && e.name !== "_")
|
|
719
|
+
.map((e) => e.name);
|
|
720
|
+
if (this._bodyRedeclares(stmt.body, declared)) {
|
|
721
|
+
this.line("{");
|
|
722
|
+
this.indented(() => this.genBlock(stmt.body));
|
|
723
|
+
this.line("}");
|
|
724
|
+
} else {
|
|
725
|
+
this.genBlock(stmt.body);
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
this.line("}");
|
|
729
|
+
this._loopDepth--;
|
|
730
|
+
},
|
|
731
|
+
|
|
619
732
|
_genIterFor(init, iterType, iteree, lhs, body) {
|
|
620
733
|
const iterExpr = this._genRangeIterExpr(iterType, iteree, lhs);
|
|
621
734
|
const binding =
|
|
@@ -645,12 +758,17 @@ export const statementGenMethods = {
|
|
|
645
758
|
return;
|
|
646
759
|
}
|
|
647
760
|
|
|
648
|
-
if (
|
|
649
|
-
this.
|
|
761
|
+
if (this._isStringRangeType(iterType)) {
|
|
762
|
+
this._genStringRangeFor(stmt, iteree, init.kind === "AssignStmt");
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
if (this._isMapRangeType(iterType)) {
|
|
767
|
+
this._genIterFor(init, iterType, iteree, lhs, stmt.body);
|
|
650
768
|
return;
|
|
651
769
|
}
|
|
652
770
|
|
|
653
|
-
this.
|
|
771
|
+
this._genSliceRangeFor(stmt, iteree, init.kind === "AssignStmt");
|
|
654
772
|
},
|
|
655
773
|
|
|
656
774
|
_genRangeIterExpr(iterType, iteree, lhs) {
|
|
@@ -658,23 +776,14 @@ export const statementGenMethods = {
|
|
|
658
776
|
if (lhs.length === 1) return `Object.keys(${iteree})`;
|
|
659
777
|
return `Object.entries(${iteree})`;
|
|
660
778
|
}
|
|
661
|
-
|
|
662
|
-
if (lhs.length === 1) return `Array.from(${iteree}).keys()`;
|
|
663
|
-
return `Array.from(${iteree}, (__c, __i) => [__i, __c.codePointAt(0)])`;
|
|
664
|
-
}
|
|
665
|
-
this._usesSliceGuard = true;
|
|
779
|
+
this.useHelper("sliceGuard");
|
|
666
780
|
if (lhs.length === 1) return `__s(${iteree}).keys()`;
|
|
667
781
|
return `__s(${iteree}).entries()`;
|
|
668
782
|
},
|
|
669
783
|
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
let iteree = this.genExpr(range.expr);
|
|
674
|
-
const yieldParams = range._yieldParams;
|
|
675
|
-
|
|
676
|
-
// Wrap bare function expressions to avoid "Function statements require a name"
|
|
677
|
-
if (range.expr.kind === "FuncLit") {
|
|
784
|
+
_genIteratorLoop(itereeExpr, paramsStr, body) {
|
|
785
|
+
let iteree = this.genExpr(itereeExpr);
|
|
786
|
+
if (itereeExpr.kind === "FuncLit") {
|
|
678
787
|
iteree = `(${iteree})`;
|
|
679
788
|
}
|
|
680
789
|
|
|
@@ -683,17 +792,13 @@ export const statementGenMethods = {
|
|
|
683
792
|
const retFlag = `__returned${d}`;
|
|
684
793
|
const retVar = `__retVal${d}`;
|
|
685
794
|
|
|
686
|
-
// Yield callback param names (blank vars get _$N to avoid JS syntax error)
|
|
687
|
-
const cbParams = lhs.map((n, i) => (n === "_" ? `_$${i}` : n));
|
|
688
|
-
|
|
689
795
|
this.line("{");
|
|
690
796
|
this.indented(() => {
|
|
691
797
|
this.line(`let ${breakFlag} = false;`);
|
|
692
798
|
this.line(`let ${retFlag} = false;`);
|
|
693
799
|
this.line(`let ${retVar};`);
|
|
694
800
|
|
|
695
|
-
|
|
696
|
-
this.line(`${iteree}(function(${params}) {`);
|
|
801
|
+
this.line(`${iteree}(function(${paramsStr}) {`);
|
|
697
802
|
this.indented(() => {
|
|
698
803
|
this.line(`if (${breakFlag}) return false;`);
|
|
699
804
|
const prev = {
|
|
@@ -707,7 +812,7 @@ export const statementGenMethods = {
|
|
|
707
812
|
this._iterReturnFlag = retFlag;
|
|
708
813
|
this._iterReturnVar = retVar;
|
|
709
814
|
|
|
710
|
-
this.genBlock(
|
|
815
|
+
this.genBlock(body);
|
|
711
816
|
|
|
712
817
|
this._inIteratorBody = prev.in;
|
|
713
818
|
this._iterBreakFlag = prev.break;
|
|
@@ -723,54 +828,17 @@ export const statementGenMethods = {
|
|
|
723
828
|
this._iterDepth--;
|
|
724
829
|
},
|
|
725
830
|
|
|
831
|
+
genIteratorFor(stmt) {
|
|
832
|
+
const range = stmt.init.rhs[0];
|
|
833
|
+
const lhs = stmt.init.lhs.map((e) => e.name ?? this.genExpr(e));
|
|
834
|
+
const cbParams = lhs.map((n, i) => (n === "_" ? `_$${i}` : n));
|
|
835
|
+
const params = range._yieldParams.length === 0 ? "" : cbParams.join(", ");
|
|
836
|
+
this._genIteratorLoop(range.expr, params, stmt.body);
|
|
837
|
+
},
|
|
838
|
+
|
|
726
839
|
// 0-param iterator: for range iter { body }
|
|
727
840
|
genIteratorForCond(stmt) {
|
|
728
|
-
|
|
729
|
-
let iteree = this.genExpr(range.expr);
|
|
730
|
-
|
|
731
|
-
if (range.expr.kind === "FuncLit") {
|
|
732
|
-
iteree = `(${iteree})`;
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
const d = this._iterDepth++;
|
|
736
|
-
const breakFlag = `__broke${d}`;
|
|
737
|
-
const retFlag = `__returned${d}`;
|
|
738
|
-
const retVar = `__retVal${d}`;
|
|
739
|
-
|
|
740
|
-
this.line("{");
|
|
741
|
-
this.indented(() => {
|
|
742
|
-
this.line(`let ${breakFlag} = false;`);
|
|
743
|
-
this.line(`let ${retFlag} = false;`);
|
|
744
|
-
this.line(`let ${retVar};`);
|
|
745
|
-
|
|
746
|
-
this.line(`${iteree}(function() {`);
|
|
747
|
-
this.indented(() => {
|
|
748
|
-
this.line(`if (${breakFlag}) return false;`);
|
|
749
|
-
const prev = {
|
|
750
|
-
in: this._inIteratorBody,
|
|
751
|
-
break: this._iterBreakFlag,
|
|
752
|
-
ret: this._iterReturnFlag,
|
|
753
|
-
retVar: this._iterReturnVar,
|
|
754
|
-
};
|
|
755
|
-
this._inIteratorBody = true;
|
|
756
|
-
this._iterBreakFlag = breakFlag;
|
|
757
|
-
this._iterReturnFlag = retFlag;
|
|
758
|
-
this._iterReturnVar = retVar;
|
|
759
|
-
|
|
760
|
-
this.genBlock(stmt.body);
|
|
761
|
-
|
|
762
|
-
this._inIteratorBody = prev.in;
|
|
763
|
-
this._iterBreakFlag = prev.break;
|
|
764
|
-
this._iterReturnFlag = prev.ret;
|
|
765
|
-
this._iterReturnVar = prev.retVar;
|
|
766
|
-
|
|
767
|
-
this.line("return true;");
|
|
768
|
-
});
|
|
769
|
-
this.line("});");
|
|
770
|
-
this.line(`if (${retFlag}) return ${retVar};`);
|
|
771
|
-
});
|
|
772
|
-
this.line("}");
|
|
773
|
-
this._iterDepth--;
|
|
841
|
+
this._genIteratorLoop(stmt.cond.expr, "", stmt.body);
|
|
774
842
|
},
|
|
775
843
|
|
|
776
844
|
// Inline a statement as a for-init/post string (no semicolon)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// src/backend/js/stdlib/base64.js
|
|
2
|
+
// CodeGen for Go encoding/base64 package.
|
|
3
|
+
|
|
4
|
+
export const base64Methods = {
|
|
5
|
+
_genBase64(fn, a) {
|
|
6
|
+
this.useHelper("base64");
|
|
7
|
+
this.useHelper("error");
|
|
8
|
+
const args = a();
|
|
9
|
+
if (fn === "NewEncoding") return `__base64_make(${args[0]}, "=")`;
|
|
10
|
+
return undefined;
|
|
11
|
+
},
|
|
12
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// src/backend/js/stdlib/binary.js
|
|
2
|
+
// CodeGen for Go encoding/binary package.
|
|
3
|
+
|
|
4
|
+
function sizeOfGoType(gt) {
|
|
5
|
+
if (!gt) return -1;
|
|
6
|
+
if (gt.kind === "basic") {
|
|
7
|
+
switch (gt.name) {
|
|
8
|
+
case "bool":
|
|
9
|
+
case "int8":
|
|
10
|
+
case "uint8":
|
|
11
|
+
case "byte":
|
|
12
|
+
return 1;
|
|
13
|
+
case "int16":
|
|
14
|
+
case "uint16":
|
|
15
|
+
return 2;
|
|
16
|
+
case "int32":
|
|
17
|
+
case "uint32":
|
|
18
|
+
case "float32":
|
|
19
|
+
case "rune":
|
|
20
|
+
return 4;
|
|
21
|
+
case "int64":
|
|
22
|
+
case "uint64":
|
|
23
|
+
case "float64":
|
|
24
|
+
case "int":
|
|
25
|
+
case "uint":
|
|
26
|
+
case "uintptr":
|
|
27
|
+
return 8;
|
|
28
|
+
default:
|
|
29
|
+
return -1;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (gt.kind === "array" || gt.kind === "ArrayType") {
|
|
33
|
+
const es = sizeOfGoType(gt.elem);
|
|
34
|
+
const len = gt.len ?? gt.size ?? 0;
|
|
35
|
+
return es > 0 ? es * len : -1;
|
|
36
|
+
}
|
|
37
|
+
if (
|
|
38
|
+
gt.kind === "pointer" ||
|
|
39
|
+
gt.kind === "PointerType" ||
|
|
40
|
+
gt.kind === "StarExpr"
|
|
41
|
+
) {
|
|
42
|
+
return sizeOfGoType(gt.base ?? gt.expr ?? gt.operand);
|
|
43
|
+
}
|
|
44
|
+
if (gt.kind === "struct" || gt.kind === "StructType") {
|
|
45
|
+
let total = 0;
|
|
46
|
+
if (gt.fields instanceof Map) {
|
|
47
|
+
for (const fType of gt.fields.values()) {
|
|
48
|
+
const s = sizeOfGoType(fType);
|
|
49
|
+
if (s < 0) return -1;
|
|
50
|
+
total += s;
|
|
51
|
+
}
|
|
52
|
+
return total;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return -1;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const binaryMethods = {
|
|
59
|
+
_genBinary(fn, a, expr) {
|
|
60
|
+
this.useHelper("binary");
|
|
61
|
+
this.useHelper("error");
|
|
62
|
+
const args = a();
|
|
63
|
+
if (fn === "Read") {
|
|
64
|
+
const targetType = expr?.args?.[2]?._type;
|
|
65
|
+
const baseType = targetType?.base ?? targetType;
|
|
66
|
+
const resolved =
|
|
67
|
+
baseType?.kind === "named"
|
|
68
|
+
? (baseType.underlying ?? baseType)
|
|
69
|
+
: baseType;
|
|
70
|
+
const sz = sizeOfGoType(resolved);
|
|
71
|
+
const typeTag =
|
|
72
|
+
resolved?.name ??
|
|
73
|
+
(resolved?.kind === "basic" ? resolved.name : (baseType?.name ?? ""));
|
|
74
|
+
return `__binary_read(${args[0]}, ${args[1]}, ${args[2]}${sz > 0 ? `, ${sz}` : ", 0"}, "${typeTag}")`;
|
|
75
|
+
}
|
|
76
|
+
if (fn === "Write") {
|
|
77
|
+
const targetType = expr?.args?.[2]?._type;
|
|
78
|
+
const baseType = targetType?.base ?? targetType;
|
|
79
|
+
const resolved =
|
|
80
|
+
baseType?.kind === "named"
|
|
81
|
+
? (baseType.underlying ?? baseType)
|
|
82
|
+
: baseType;
|
|
83
|
+
const sz = sizeOfGoType(resolved);
|
|
84
|
+
const typeTag =
|
|
85
|
+
resolved?.name ??
|
|
86
|
+
(resolved?.kind === "basic" ? resolved.name : (baseType?.name ?? ""));
|
|
87
|
+
return `__binary_write(${args[0]}, ${args[1]}, ${args[2]}${sz > 0 ? `, ${sz}` : ", 0"}, "${typeTag}")`;
|
|
88
|
+
}
|
|
89
|
+
if (fn === "Size") {
|
|
90
|
+
const sz = sizeOfGoType(expr?.args?.[0]?._type);
|
|
91
|
+
if (sz >= 0) return `${sz}`;
|
|
92
|
+
return `__binary_size(${args[0]})`;
|
|
93
|
+
}
|
|
94
|
+
if (fn === "AppendUint16")
|
|
95
|
+
return `__binary_le.AppendUint16(${args[0]}, ${args[1]})`;
|
|
96
|
+
if (fn === "AppendUint32")
|
|
97
|
+
return `__binary_le.AppendUint32(${args[0]}, ${args[1]})`;
|
|
98
|
+
if (fn === "AppendUint64")
|
|
99
|
+
return `__binary_le.AppendUint64(${args[0]}, ${args[1]})`;
|
|
100
|
+
return undefined;
|
|
101
|
+
},
|
|
102
|
+
};
|
|
@@ -19,7 +19,21 @@ const BITS_MAP = {
|
|
|
19
19
|
OnesCount64: ([x]) =>
|
|
20
20
|
`((() => { let v = BigInt.asUintN(64, BigInt(${x})); let c = 0; while (v > 0n) { if (v & 1n) c++; v >>= 1n; } return c; })())`,
|
|
21
21
|
RotateLeft64: ([x, k]) =>
|
|
22
|
-
`((() => { const s = BigInt(${k}) & 63n; const v = BigInt.asUintN(64, BigInt(${x})); return BigInt.asUintN(64, (v << s) | (v >> ((64n - s) & 63n))); })())`,
|
|
22
|
+
`((() => { const s = BigInt(${k}) & 63n; const v = BigInt.asUintN(64, BigInt(${x})); return Number(BigInt.asUintN(64, (v << s) | (v >> ((64n - s) & 63n)))); })())`,
|
|
23
|
+
|
|
24
|
+
Len32: ([x]) => `((v => 32 - Math.clz32(v >>> 0))(${x}))`,
|
|
25
|
+
Len64: ([x]) =>
|
|
26
|
+
`((() => { const v = BigInt.asUintN(64, BigInt(${x})); if (v === 0n) return 0; const hi = Number(v >> 32n); return hi !== 0 ? 64 - Math.clz32(hi) : 32 - Math.clz32(Number(v & 0xffffffffn)); })())`,
|
|
27
|
+
ReverseBytes16: ([x]) =>
|
|
28
|
+
`((v => ((v & 0xff) << 8) | ((v >>> 8) & 0xff))((${x}) & 0xffff))`,
|
|
29
|
+
ReverseBytes32: ([x]) =>
|
|
30
|
+
`((v => (((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v >>> 8) & 0xff00) | ((v >>> 24) & 0xff)) >>> 0)((${x}) >>> 0))`,
|
|
31
|
+
ReverseBytes64: ([x]) =>
|
|
32
|
+
`((() => { const v = BigInt.asUintN(64, BigInt(${x})); let r = 0n; for (let i = 0n; i < 8n; i++) r = (r << 8n) | ((v >> (i * 8n)) & 0xffn); return Number(r); })())`,
|
|
33
|
+
Reverse32: ([x]) =>
|
|
34
|
+
`((() => { let v = (${x}) >>> 0; v = ((v >>> 1) & 0x55555555) | ((v & 0x55555555) << 1); v = ((v >>> 2) & 0x33333333) | ((v & 0x33333333) << 2); v = ((v >>> 4) & 0x0f0f0f0f) | ((v & 0x0f0f0f0f) << 4); v = ((v >>> 8) & 0x00ff00ff) | ((v & 0x00ff00ff) << 8); return ((v >>> 16) | (v << 16)) >>> 0; })())`,
|
|
35
|
+
Reverse64: ([x]) =>
|
|
36
|
+
`((() => { const rev32 = (v) => { v = ((v >>> 1) & 0x55555555) | ((v & 0x55555555) << 1); v = ((v >>> 2) & 0x33333333) | ((v & 0x33333333) << 2); v = ((v >>> 4) & 0x0f0f0f0f) | ((v & 0x0f0f0f0f) << 4); v = ((v >>> 8) & 0x00ff00ff) | ((v & 0x00ff00ff) << 8); return ((v >>> 16) | (v << 16)) >>> 0; }; const v = BigInt.asUintN(64, BigInt(${x})); const lo = Number(v & 0xffffffffn); const hi = Number((v >> 32n) & 0xffffffffn); return Number((BigInt(rev32(lo)) << 32n) | BigInt(rev32(hi))); })())`,
|
|
23
37
|
};
|
|
24
38
|
|
|
25
39
|
/** @type {ThisType<CodeGen>} */
|
|
@@ -3,25 +3,40 @@
|
|
|
3
3
|
/** @typedef {import('../index.js').CodeGen} CodeGen */
|
|
4
4
|
|
|
5
5
|
const BUILDER_STR = {
|
|
6
|
-
WriteString: (b, a) =>
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
WriteString: (b, a) =>
|
|
7
|
+
`((__s) => { ${b}._buf += __s; return [new TextEncoder().encode(__s).length, null]; })(${a[0]})`,
|
|
8
|
+
WriteByte: (b, a) => `(${b}._buf += String.fromCodePoint(${a[0]}), null)`,
|
|
9
|
+
WriteRune: (b, a) =>
|
|
10
|
+
`((cp) => { const r = (cp < 0 || cp > 0x10ffff || (cp >= 0xd800 && cp <= 0xdfff)) ? 0xfffd : cp; const s = String.fromCodePoint(r); ${b}._buf += s; return [new TextEncoder().encode(s).length, null]; })(${a[0]})`,
|
|
11
|
+
Write: (b, a) =>
|
|
12
|
+
`(${b}._buf += new TextDecoder().decode(new Uint8Array(${a[0]})), [${a[0]}.length, null])`,
|
|
9
13
|
String: (b) => `${b}._buf`,
|
|
10
14
|
Reset: (b) => `(${b}._buf = "")`,
|
|
15
|
+
Len: (b) => `new TextEncoder().encode(${b}._buf).length`,
|
|
16
|
+
Cap: (b) =>
|
|
17
|
+
`Math.max(${b}._cap ?? 0, new TextEncoder().encode(${b}._buf).length)`,
|
|
18
|
+
Grow: (b, a) =>
|
|
19
|
+
`((n) => { if (n < 0) throw new Error("strings.Builder.Grow: negative count"); ${b}._cap = Math.max(${b}._cap ?? 0, new TextEncoder().encode(${b}._buf).length) + n; })(${a[0]})`,
|
|
11
20
|
};
|
|
12
21
|
const BUILDER_BYTES = {
|
|
13
22
|
WriteString: (b, a) =>
|
|
14
|
-
`(
|
|
15
|
-
WriteByte: (b, a) =>
|
|
16
|
-
|
|
23
|
+
`((buf, s) => { const bytes = new TextEncoder().encode(s); for (let i = 0; i < bytes.length; i++) buf._buf.push(bytes[i]); return [bytes.length, null]; })(${b}, ${a[0]})`,
|
|
24
|
+
WriteByte: (b, a) => `(${b}._buf.push(${a[0]}), null)`,
|
|
25
|
+
WriteRune: (b, a) =>
|
|
26
|
+
`((buf, cp) => { const r = (cp < 0 || cp > 0x10ffff || (cp >= 0xd800 && cp <= 0xdfff)) ? 0xfffd : cp; const bytes = new TextEncoder().encode(String.fromCodePoint(r)); for (let i = 0; i < bytes.length; i++) buf._buf.push(bytes[i]); return [bytes.length, null]; })(${b}, ${a[0]})`,
|
|
27
|
+
Write: (b, a) =>
|
|
28
|
+
`((buf, d) => { for (let i = 0; i < d.length; i++) buf._buf.push(d[i]); return [d.length, null]; })(${b}, ${a[0]})`,
|
|
17
29
|
String: (b) => `new TextDecoder().decode(new Uint8Array(${b}._buf))`,
|
|
18
30
|
Reset: (b) => `(${b}._buf = [])`,
|
|
31
|
+
Read: (b, a) =>
|
|
32
|
+
`((buf, p) => { if (buf._buf.length === 0) return [0, __io_eof]; const n = Math.min(p.length, buf._buf.length); for (let i = 0; i < n; i++) p[i] = buf._buf.shift(); return [n, null]; })(${b}, ${a[0]})`,
|
|
19
33
|
};
|
|
20
34
|
const BUILDER_COMMON = {
|
|
21
|
-
|
|
22
|
-
Bytes: (b) => `${b}._buf.slice()`,
|
|
35
|
+
Bytes: (b) => `new Uint8Array(${b}._buf)`,
|
|
23
36
|
Len: (b) => `${b}._buf.length`,
|
|
24
|
-
|
|
37
|
+
Cap: (b) => `Math.max(${b}._cap ?? 0, ${b}._buf.length)`,
|
|
38
|
+
Grow: (b, a) =>
|
|
39
|
+
`((n) => { if (n < 0) throw new Error("bytes.Buffer.Grow: negative count"); ${b}._cap = Math.max(${b}._cap ?? 0, ${b}._buf.length) + n; })(${a[0]})`,
|
|
25
40
|
};
|
|
26
41
|
|
|
27
42
|
/** @type {ThisType<CodeGen>} */
|
|
@@ -30,6 +45,10 @@ export const builderMethods = {
|
|
|
30
45
|
const recv = expr.func.expr;
|
|
31
46
|
const base = this._unboxWriter(this.genExpr(recv));
|
|
32
47
|
const args = expr.args.map((a) => this.genExpr(a));
|
|
48
|
+
if (method === "Read") {
|
|
49
|
+
this.useHelper("ioEOF");
|
|
50
|
+
this.useHelper("error");
|
|
51
|
+
}
|
|
33
52
|
const isStr = typeName === "strings.Builder";
|
|
34
53
|
const table = isStr ? BUILDER_STR : BUILDER_BYTES;
|
|
35
54
|
const gen = table[method] ?? BUILDER_COMMON[method];
|