gofront 1.6.0 → 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/package.json +1 -1
- package/src/backend/js/expressions.js +238 -109
- package/src/backend/js/index.js +38 -1
- package/src/backend/js/runtime.js +953 -53
- package/src/backend/js/statements.js +55 -67
- 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 +20 -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 +16 -0
- package/src/backend/js/stdlib/io.js +105 -3
- 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/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 +1207 -41
- package/src/backend/wasm/const-fold.js +205 -0
- package/src/backend/wasm/emit-builtins.js +203 -76
- package/src/backend/wasm/emit-exprs.js +464 -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 +115 -87
- package/src/backend/wasm/encode.js +55 -29
- package/src/backend/wasm/index.js +1001 -32
- package/src/backend/wasm/optimize.js +13 -4
- 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 +153 -1
- package/src/cli-core.js +1 -1
- package/src/compiler.js +18 -4
- package/src/dts-parser.js +79 -126
- package/src/index.js +2 -6
- package/src/lexer.js +80 -29
- package/src/lower/boxing.js +1 -2
- package/src/lower/captures.js +2 -6
- 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/types.js +1 -2
- 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 +81 -13
- package/src/typechecker/expressions.js +102 -2
- package/src/typechecker/resolve.js +36 -6
- package/src/typechecker/stdlib/core.js +280 -89
- package/src/typechecker/stdlib/extended.js +453 -1
- package/src/typechecker/types.js +344 -6
|
@@ -696,6 +696,39 @@ export const statementGenMethods = {
|
|
|
696
696
|
return nodeAssigns(node, name);
|
|
697
697
|
},
|
|
698
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
|
+
|
|
699
732
|
_genIterFor(init, iterType, iteree, lhs, body) {
|
|
700
733
|
const iterExpr = this._genRangeIterExpr(iterType, iteree, lhs);
|
|
701
734
|
const binding =
|
|
@@ -725,12 +758,17 @@ export const statementGenMethods = {
|
|
|
725
758
|
return;
|
|
726
759
|
}
|
|
727
760
|
|
|
728
|
-
if (
|
|
729
|
-
this.
|
|
761
|
+
if (this._isStringRangeType(iterType)) {
|
|
762
|
+
this._genStringRangeFor(stmt, iteree, init.kind === "AssignStmt");
|
|
730
763
|
return;
|
|
731
764
|
}
|
|
732
765
|
|
|
733
|
-
this.
|
|
766
|
+
if (this._isMapRangeType(iterType)) {
|
|
767
|
+
this._genIterFor(init, iterType, iteree, lhs, stmt.body);
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
this._genSliceRangeFor(stmt, iteree, init.kind === "AssignStmt");
|
|
734
772
|
},
|
|
735
773
|
|
|
736
774
|
_genRangeIterExpr(iterType, iteree, lhs) {
|
|
@@ -738,23 +776,14 @@ export const statementGenMethods = {
|
|
|
738
776
|
if (lhs.length === 1) return `Object.keys(${iteree})`;
|
|
739
777
|
return `Object.entries(${iteree})`;
|
|
740
778
|
}
|
|
741
|
-
if (this._isStringRangeType(iterType)) {
|
|
742
|
-
if (lhs.length === 1) return `Array.from(${iteree}).keys()`;
|
|
743
|
-
return `Array.from(${iteree}, (__c, __i) => [__i, __c.codePointAt(0)])`;
|
|
744
|
-
}
|
|
745
779
|
this.useHelper("sliceGuard");
|
|
746
780
|
if (lhs.length === 1) return `__s(${iteree}).keys()`;
|
|
747
781
|
return `__s(${iteree}).entries()`;
|
|
748
782
|
},
|
|
749
783
|
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
let iteree = this.genExpr(range.expr);
|
|
754
|
-
const yieldParams = range._yieldParams;
|
|
755
|
-
|
|
756
|
-
// Wrap bare function expressions to avoid "Function statements require a name"
|
|
757
|
-
if (range.expr.kind === "FuncLit") {
|
|
784
|
+
_genIteratorLoop(itereeExpr, paramsStr, body) {
|
|
785
|
+
let iteree = this.genExpr(itereeExpr);
|
|
786
|
+
if (itereeExpr.kind === "FuncLit") {
|
|
758
787
|
iteree = `(${iteree})`;
|
|
759
788
|
}
|
|
760
789
|
|
|
@@ -763,17 +792,13 @@ export const statementGenMethods = {
|
|
|
763
792
|
const retFlag = `__returned${d}`;
|
|
764
793
|
const retVar = `__retVal${d}`;
|
|
765
794
|
|
|
766
|
-
// Yield callback param names (blank vars get _$N to avoid JS syntax error)
|
|
767
|
-
const cbParams = lhs.map((n, i) => (n === "_" ? `_$${i}` : n));
|
|
768
|
-
|
|
769
795
|
this.line("{");
|
|
770
796
|
this.indented(() => {
|
|
771
797
|
this.line(`let ${breakFlag} = false;`);
|
|
772
798
|
this.line(`let ${retFlag} = false;`);
|
|
773
799
|
this.line(`let ${retVar};`);
|
|
774
800
|
|
|
775
|
-
|
|
776
|
-
this.line(`${iteree}(function(${params}) {`);
|
|
801
|
+
this.line(`${iteree}(function(${paramsStr}) {`);
|
|
777
802
|
this.indented(() => {
|
|
778
803
|
this.line(`if (${breakFlag}) return false;`);
|
|
779
804
|
const prev = {
|
|
@@ -787,7 +812,7 @@ export const statementGenMethods = {
|
|
|
787
812
|
this._iterReturnFlag = retFlag;
|
|
788
813
|
this._iterReturnVar = retVar;
|
|
789
814
|
|
|
790
|
-
this.genBlock(
|
|
815
|
+
this.genBlock(body);
|
|
791
816
|
|
|
792
817
|
this._inIteratorBody = prev.in;
|
|
793
818
|
this._iterBreakFlag = prev.break;
|
|
@@ -803,54 +828,17 @@ export const statementGenMethods = {
|
|
|
803
828
|
this._iterDepth--;
|
|
804
829
|
},
|
|
805
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
|
+
|
|
806
839
|
// 0-param iterator: for range iter { body }
|
|
807
840
|
genIteratorForCond(stmt) {
|
|
808
|
-
|
|
809
|
-
let iteree = this.genExpr(range.expr);
|
|
810
|
-
|
|
811
|
-
if (range.expr.kind === "FuncLit") {
|
|
812
|
-
iteree = `(${iteree})`;
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
const d = this._iterDepth++;
|
|
816
|
-
const breakFlag = `__broke${d}`;
|
|
817
|
-
const retFlag = `__returned${d}`;
|
|
818
|
-
const retVar = `__retVal${d}`;
|
|
819
|
-
|
|
820
|
-
this.line("{");
|
|
821
|
-
this.indented(() => {
|
|
822
|
-
this.line(`let ${breakFlag} = false;`);
|
|
823
|
-
this.line(`let ${retFlag} = false;`);
|
|
824
|
-
this.line(`let ${retVar};`);
|
|
825
|
-
|
|
826
|
-
this.line(`${iteree}(function() {`);
|
|
827
|
-
this.indented(() => {
|
|
828
|
-
this.line(`if (${breakFlag}) return false;`);
|
|
829
|
-
const prev = {
|
|
830
|
-
in: this._inIteratorBody,
|
|
831
|
-
break: this._iterBreakFlag,
|
|
832
|
-
ret: this._iterReturnFlag,
|
|
833
|
-
retVar: this._iterReturnVar,
|
|
834
|
-
};
|
|
835
|
-
this._inIteratorBody = true;
|
|
836
|
-
this._iterBreakFlag = breakFlag;
|
|
837
|
-
this._iterReturnFlag = retFlag;
|
|
838
|
-
this._iterReturnVar = retVar;
|
|
839
|
-
|
|
840
|
-
this.genBlock(stmt.body);
|
|
841
|
-
|
|
842
|
-
this._inIteratorBody = prev.in;
|
|
843
|
-
this._iterBreakFlag = prev.break;
|
|
844
|
-
this._iterReturnFlag = prev.ret;
|
|
845
|
-
this._iterReturnVar = prev.retVar;
|
|
846
|
-
|
|
847
|
-
this.line("return true;");
|
|
848
|
-
});
|
|
849
|
-
this.line("});");
|
|
850
|
-
this.line(`if (${retFlag}) return ${retVar};`);
|
|
851
|
-
});
|
|
852
|
-
this.line("}");
|
|
853
|
-
this._iterDepth--;
|
|
841
|
+
this._genIteratorLoop(stmt.cond.expr, "", stmt.body);
|
|
854
842
|
},
|
|
855
843
|
|
|
856
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];
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
/** @typedef {import('../index.js').CodeGen} CodeGen */
|
|
4
4
|
|
|
5
|
-
const __bs = `(b => String.fromCharCode(
|
|
6
|
-
const __sb = `(s => [...s].map(c => c.charCodeAt(0)))`;
|
|
5
|
+
const __bs = `(b => typeof TextDecoder !== "undefined" ? new TextDecoder().decode(b instanceof Uint8Array ? b : new Uint8Array(b)) : String.fromCharCode.apply(null, b))`;
|
|
6
|
+
const __sb = `(s => typeof TextEncoder !== "undefined" ? new TextEncoder().encode(s) : new Uint8Array([...s].map(c => c.charCodeAt(0))))`;
|
|
7
7
|
|
|
8
8
|
const BYTES_DISPATCH = {
|
|
9
9
|
Contains: (a) => `${__bs}(${a[0]}).includes(${__bs}(${a[1]}))`,
|
|
@@ -16,49 +16,106 @@ const BYTES_DISPATCH = {
|
|
|
16
16
|
`((b, sep) => sep.length === 0 ? b.length + 1 : ${__bs}(b).split(${__bs}(sep)).length - 1)(${a[0]}, ${a[1]})`,
|
|
17
17
|
Repeat: (a) => `${__sb}(${__bs}(${a[0]}).repeat(${a[1]}))`,
|
|
18
18
|
Replace: (a) =>
|
|
19
|
-
`((b, o, n, cnt) => { let
|
|
20
|
-
ToUpper: (a) =>
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
`((b, o, n, cnt) => { let str = ${__bs}(b), os = ${__bs}(o), nw = ${__bs}(n); if (cnt < 0) return ${__sb}(str.replaceAll(os, () => nw)); let r = ""; let i = 0; for (; cnt > 0; cnt--) { const j = str.indexOf(os, i); if (j < 0) break; r += str.slice(i, j) + nw; i = j + os.length; if (os.length === 0) { if (i >= str.length) break; r += str[i]; i++; } } return ${__sb}(r + str.slice(i)); })(${a[0]}, ${a[1]}, ${a[2]}, ${a[3]})`,
|
|
20
|
+
ToUpper: (a) =>
|
|
21
|
+
`new TextEncoder().encode(new TextDecoder().decode(new Uint8Array(${a[0]})).toUpperCase())`,
|
|
22
|
+
ToLower: (a) =>
|
|
23
|
+
`new TextEncoder().encode(new TextDecoder().decode(new Uint8Array(${a[0]})).toLowerCase())`,
|
|
24
|
+
ToTitle: (a) =>
|
|
25
|
+
`new TextEncoder().encode(new TextDecoder().decode(new Uint8Array(${a[0]})).toUpperCase())`,
|
|
26
|
+
TrimSpace: (a) =>
|
|
27
|
+
`new TextEncoder().encode(new TextDecoder().decode(new Uint8Array(${a[0]})).trim())`,
|
|
23
28
|
Trim: (a) =>
|
|
24
|
-
|
|
29
|
+
`((b, c) => { const s = new TextDecoder().decode(new Uint8Array(b)); const cs = new Set(Array.from(c)); const chars = Array.from(s); let l = 0, r = chars.length; while (l < r && cs.has(chars[l])) l++; while (r > l && cs.has(chars[r - 1])) r--; return new TextEncoder().encode(chars.slice(l, r).join("")); })(${a[0]}, ${a[1]})`,
|
|
25
30
|
Equal: (a) =>
|
|
26
31
|
`((a, b) => { if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false; return true; })(${a[0]}, ${a[1]})`,
|
|
27
32
|
Split: (a) => `${__bs}(${a[0]}).split(${__bs}(${a[1]})).map(p => ${__sb}(p))`,
|
|
28
33
|
Join: (a) => `${__sb}(${a[0]}.map(p => ${__bs}(p)).join(${__bs}(${a[1]})))`,
|
|
29
34
|
ReplaceAll: (a) =>
|
|
30
|
-
`((b, o, n) => { const r = []; let i = 0; while (i <= b.length - o.length) { if (o.length > 0 && o.every((v, j) => b[i + j] === v)) { r.push(...n); i += o.length; } else { r.push(b[i++]); } } for (; i < b.length; i++) r.push(b[i]); return
|
|
35
|
+
`((b, o, n) => { const r = []; let i = 0; while (i <= b.length - o.length) { if (o.length > 0 && o.every((v, j) => b[i + j] === v)) { r.push(...n); i += o.length; } else { r.push(b[i++]); } } for (; i < b.length; i++) r.push(b[i]); return new Uint8Array(r); })(${a[0]}, ${a[1]}, ${a[2]})`,
|
|
31
36
|
TrimPrefix: (a) =>
|
|
32
37
|
`((b, p) => p.every((v, i) => b[i] === v) ? b.slice(p.length) : b.slice())(${a[0]}, ${a[1]})`,
|
|
33
38
|
TrimSuffix: (a) =>
|
|
34
39
|
`((b, s) => s.length && s.every((v, i) => b[b.length - s.length + i] === v) ? b.slice(0, -s.length) : b.slice())(${a[0]}, ${a[1]})`,
|
|
35
40
|
TrimLeft: (a) =>
|
|
36
|
-
`((b, c) => { let
|
|
41
|
+
`((b, c) => { const s = new TextDecoder().decode(new Uint8Array(b)); const cs = new Set(Array.from(c)); const chars = Array.from(s); let l = 0, r = chars.length; while (l < r && cs.has(chars[l])) l++; return new TextEncoder().encode(chars.slice(l, r).join("")); })(${a[0]}, ${a[1]})`,
|
|
37
42
|
TrimRight: (a) =>
|
|
38
|
-
`((b, c) => {
|
|
43
|
+
`((b, c) => { const s = new TextDecoder().decode(new Uint8Array(b)); const cs = new Set(Array.from(c)); const chars = Array.from(s); let l = 0, r = chars.length; while (r > l && cs.has(chars[r - 1])) r--; return new TextEncoder().encode(chars.slice(l, r).join("")); })(${a[0]}, ${a[1]})`,
|
|
39
44
|
TrimFunc: (a) =>
|
|
40
|
-
`((b, f) => { let l = 0, r =
|
|
45
|
+
`((b, f) => { const s = new TextDecoder().decode(new Uint8Array(b)); const chars = Array.from(s); let l = 0, r = chars.length; while (l < r && f(chars[l].codePointAt(0))) l++; while (r > l && f(chars[r - 1].codePointAt(0))) r--; return new TextEncoder().encode(chars.slice(l, r).join("")); })(${a[0]}, ${a[1]})`,
|
|
41
46
|
IndexByte: (a) => `(${a[0]}).indexOf(${a[1]})`,
|
|
42
47
|
LastIndex: (a) =>
|
|
43
48
|
`((b, s) => { for (let i = b.length - s.length; i >= 0; i--) if (s.every((v, j) => b[i + j] === v)) return i; return -1; })(${a[0]}, ${a[1]})`,
|
|
44
49
|
LastIndexByte: (a) => `(${a[0]}).lastIndexOf(${a[1]})`,
|
|
45
50
|
Fields: (a) =>
|
|
46
|
-
`((b) => { const s =
|
|
51
|
+
`((b) => { const s = new TextDecoder().decode(new Uint8Array(b ?? [])).trim(); return s === '' ? [] : s.split(/\\s+/).map(w => new TextEncoder().encode(w)); })(${a[0]})`,
|
|
52
|
+
FieldsFunc: (a) =>
|
|
53
|
+
`((b, fn) => { const s = new TextDecoder().decode(new Uint8Array(b ?? [])); const res = []; let cur = ""; for (const ch of s) { const cp = ch.codePointAt(0); if (fn(cp)) { if (cur.length > 0) { res.push(new TextEncoder().encode(cur)); cur = ""; } } else { cur += ch; } } if (cur.length > 0) res.push(new TextEncoder().encode(cur)); return res; })(${a[0]}, ${a[1]})`,
|
|
54
|
+
Clone: (a) =>
|
|
55
|
+
`(${a[0]} ? (${a[0]}.slice ? ${a[0]}.slice() : Array.from(${a[0]})) : null)`,
|
|
47
56
|
Cut: (a) =>
|
|
48
|
-
`((b, sep) => { for (let i = 0; i <= b.length - sep.length; i++) if (sep.every((v, j) => b[i + j] === v)) return [b.slice(0, i), b.slice(i + sep.length), true]; return [b.slice(),
|
|
57
|
+
`((b, sep) => { for (let i = 0; i <= b.length - sep.length; i++) if (sep.every((v, j) => b[i + j] === v)) return [b.slice(0, i), b.slice(i + sep.length), true]; return [b.slice(), new Uint8Array(0), false]; })(${a[0]}, ${a[1]})`,
|
|
49
58
|
ContainsAny: (a) =>
|
|
50
|
-
`
|
|
51
|
-
ContainsRune: (a) =>
|
|
52
|
-
|
|
59
|
+
`((b, chars) => { const s = new TextDecoder().decode(new Uint8Array(b)); for (const c of chars) if (s.includes(c)) return true; return false; })(${a[0]}, ${a[1]})`,
|
|
60
|
+
ContainsRune: (a) =>
|
|
61
|
+
`((b, r) => { const s = new TextDecoder().decode(new Uint8Array(b)); return s.includes(String.fromCodePoint(r < 0 || r > 0x10ffff || (r >= 0xd800 && r <= 0xdfff) ? 0xfffd : r)); })(${a[0]}, ${a[1]})`,
|
|
62
|
+
Map: (a) =>
|
|
63
|
+
`((f, b) => { const s = new TextDecoder().decode(new Uint8Array(b)); let res = ""; for (const c of s) { const r = f(c.codePointAt(0)); if (r >= 0) res += String.fromCodePoint(r); } return new TextEncoder().encode(res); })(${a[0]}, ${a[1]})`,
|
|
53
64
|
SplitN: (a) =>
|
|
54
|
-
`((b, sep, n) => {
|
|
65
|
+
`((b, sep, n) => {
|
|
66
|
+
if (n === 0) return null;
|
|
67
|
+
if (sep.length === 0) {
|
|
68
|
+
if (n < 0 || b.length <= n) {
|
|
69
|
+
const r = [];
|
|
70
|
+
for (let k = 0; k < b.length; k++) r.push(b.slice(k, k + 1));
|
|
71
|
+
return r;
|
|
72
|
+
}
|
|
73
|
+
const r = [];
|
|
74
|
+
for (let k = 0; k < n - 1; k++) r.push(b.slice(k, k + 1));
|
|
75
|
+
r.push(b.slice(n - 1));
|
|
76
|
+
return r;
|
|
77
|
+
}
|
|
78
|
+
const findNext = (start) => {
|
|
79
|
+
for (let k = start; k <= b.length - sep.length; k++) {
|
|
80
|
+
let match = true;
|
|
81
|
+
for (let l = 0; l < sep.length; l++) {
|
|
82
|
+
if (b[k + l] !== sep[l]) { match = false; break; }
|
|
83
|
+
}
|
|
84
|
+
if (match) return k;
|
|
85
|
+
}
|
|
86
|
+
return -1;
|
|
87
|
+
};
|
|
88
|
+
if (n < 0) {
|
|
89
|
+
const r = [];
|
|
90
|
+
let i = 0;
|
|
91
|
+
while (i <= b.length) {
|
|
92
|
+
const j = findNext(i);
|
|
93
|
+
if (j < 0) break;
|
|
94
|
+
r.push(b.slice(i, j));
|
|
95
|
+
i = j + sep.length;
|
|
96
|
+
}
|
|
97
|
+
r.push(b.slice(i));
|
|
98
|
+
return r;
|
|
99
|
+
}
|
|
100
|
+
const r = [];
|
|
101
|
+
let i = 0;
|
|
102
|
+
for (let c = 1; c < n; c++) {
|
|
103
|
+
const j = findNext(i);
|
|
104
|
+
if (j < 0) break;
|
|
105
|
+
r.push(b.slice(i, j));
|
|
106
|
+
i = j + sep.length;
|
|
107
|
+
}
|
|
108
|
+
r.push(b.slice(i));
|
|
109
|
+
return r;
|
|
110
|
+
})(${a[0]}, ${a[1]}, ${a[2]})`,
|
|
55
111
|
NewReader: (a) =>
|
|
56
|
-
`{_src:
|
|
112
|
+
`((b) => ({ _src: b, _pos: 0, Read(p) { if (this._pos >= this._src.length) return [0, __io_eof]; const n = Math.min(p.length, this._src.length - this._pos); for (let i = 0; i < n; i++) p[i] = this._src[this._pos + i]; this._pos += n; return [n, null]; }, Len() { return Math.max(0, this._src.length - this._pos); }, Reset(b2) { this._src = b2; this._pos = 0; } }))(${a[0]})`,
|
|
57
113
|
};
|
|
58
114
|
|
|
59
115
|
/** @type {ThisType<CodeGen>} */
|
|
60
116
|
export const bytesMethods = {
|
|
61
117
|
_genBytes(fn, a) {
|
|
118
|
+
if (fn === "NewReader") this.useHelper("ioEOF");
|
|
62
119
|
const gen = BYTES_DISPATCH[fn];
|
|
63
120
|
return gen ? gen(a()) : undefined;
|
|
64
121
|
},
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
/** @type {ThisType<CodeGen>} */
|
|
6
6
|
export const errorsMethods = {
|
|
7
|
-
_genErrors(fn, a) {
|
|
7
|
+
_genErrors(fn, a, expr) {
|
|
8
8
|
const args = a();
|
|
9
9
|
if (fn === "New") {
|
|
10
10
|
this.useHelper("error");
|
|
@@ -15,6 +15,25 @@ export const errorsMethods = {
|
|
|
15
15
|
return `__errorIs(${args[0]}, ${args[1]})`;
|
|
16
16
|
}
|
|
17
17
|
if (fn === "Unwrap") return `(${args[0]}?._cause ?? null)`;
|
|
18
|
+
if (fn === "As") {
|
|
19
|
+
this.useHelper("errorAs");
|
|
20
|
+
const targetGoType = expr?.args?.[1]?._type;
|
|
21
|
+
const baseGoType = targetGoType?.base ?? targetGoType;
|
|
22
|
+
const concreteGoType = baseGoType?.base ?? baseGoType;
|
|
23
|
+
const typeName = concreteGoType?.name;
|
|
24
|
+
if (concreteGoType?.kind === "interface" || typeName === "error") {
|
|
25
|
+
return `__errorAs(${args[0]}, ${args[1]}, (x) => x !== null && (typeof x === "object" ? typeof x.Error === "function" : true))`;
|
|
26
|
+
}
|
|
27
|
+
if (typeName) {
|
|
28
|
+
return `__errorAs(${args[0]}, ${args[1]}, (x) => (typeof ${typeName} === "function" && x instanceof ${typeName}) || x?.constructor?.name === "${typeName}" || x?.__struct === "${typeName}")`;
|
|
29
|
+
}
|
|
30
|
+
return `__errorAs(${args[0]}, ${args[1]})`;
|
|
31
|
+
}
|
|
32
|
+
if (fn === "Join") {
|
|
33
|
+
this.useHelper("error");
|
|
34
|
+
this.useHelper("errorJoin");
|
|
35
|
+
return `__errorJoin(${args.join(", ")})`;
|
|
36
|
+
}
|
|
18
37
|
return undefined;
|
|
19
38
|
},
|
|
20
39
|
};
|