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
|
@@ -3,16 +3,30 @@
|
|
|
3
3
|
/** @typedef {import('../index.js').CodeGen} CodeGen */
|
|
4
4
|
|
|
5
5
|
const _SSCAN_LOOP =
|
|
6
|
-
`let n = 0; for (let i = 0; i < ptrs.length && i < tokens.length; i++) { ` +
|
|
7
|
-
`const
|
|
8
|
-
`if (
|
|
9
|
-
`else if (
|
|
6
|
+
`let n = 0, err = null; for (let i = 0; i < ptrs.length && i < tokens.length; i++) { ` +
|
|
7
|
+
`const item = tokens[i]; const t = typeof item === "object" && item !== null ? item.t : item; const verb = item?.verb; const p = ptrs[i]; ` +
|
|
8
|
+
`if (verb === "%c") { p.value = t.codePointAt ? t.codePointAt(0) : t; } ` +
|
|
9
|
+
`else if (verb === "%x" || verb === "%X") { const clean = t.replace(/^0[xX]/, ""); const v = parseInt(clean, 16); if (isNaN(v)) { err = __error("expected hex number"); break; } p.value = typeof p.value === "bigint" ? BigInt("0x" + clean) : v; } ` +
|
|
10
|
+
`else if (verb === "%o") { const clean = t.replace(/^0[oO]?/, ""); const v = parseInt(clean, 8); if (isNaN(v)) { err = __error("expected octal number"); break; } p.value = typeof p.value === "bigint" ? BigInt("0o" + clean) : v; } ` +
|
|
11
|
+
`else if (verb === "%b") { const clean = t.replace(/^0[bB]/, ""); const v = parseInt(clean, 2); if (isNaN(v)) { err = __error("expected binary number"); break; } p.value = typeof p.value === "bigint" ? BigInt("0b" + clean) : v; } ` +
|
|
12
|
+
`else if (typeof p.value === "number") { const v = Number(t); if (Number.isNaN(v) || !/^[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[eE][+-]?\\d+)?$/.test(t)) { err = __error("expected number"); break; } p.value = v; } ` +
|
|
13
|
+
`else if (typeof p.value === "bigint") { try { if (!/^[+-]?\\d+$/.test(t)) throw 1; p.value = BigInt(t); } catch { err = __error("expected integer"); break; } } ` +
|
|
14
|
+
`else if (typeof p.value === "boolean") { const tl = String(t).toLowerCase(); if (tl === "true" || tl === "1" || tl === "t") p.value = true; else if (tl === "false" || tl === "0" || tl === "f") p.value = false; else { err = __error("expected boolean"); break; } } ` +
|
|
10
15
|
`else p.value = t; n++; }`;
|
|
11
16
|
|
|
12
17
|
/** @type {ThisType<CodeGen>} */
|
|
13
18
|
export const fmtMethods = {
|
|
19
|
+
_fmtArgJs(e) {
|
|
20
|
+
const js = this.genExpr(e);
|
|
21
|
+
const base =
|
|
22
|
+
e?._type?.kind === "named" ? (e._type.underlying ?? e._type) : e?._type;
|
|
23
|
+
return base?.kind === "slice" ? `(${js} ?? [])` : js;
|
|
24
|
+
},
|
|
25
|
+
|
|
14
26
|
_genFmt(fn, _a, expr) {
|
|
15
|
-
const fmtArgs = expr.args
|
|
27
|
+
const fmtArgs = expr.args
|
|
28
|
+
.map((e, idx) => (idx === 0 ? this.genExpr(e) : this._fmtArgJs(e)))
|
|
29
|
+
.join(", ");
|
|
16
30
|
switch (fn) {
|
|
17
31
|
case "Sprintf":
|
|
18
32
|
this.useHelper("sprintf");
|
|
@@ -42,29 +56,72 @@ export const fmtMethods = {
|
|
|
42
56
|
case "Fprint":
|
|
43
57
|
return this._genFmtFprint(fn, expr);
|
|
44
58
|
case "Sscan": {
|
|
59
|
+
this.useHelper("error");
|
|
45
60
|
const strArg = this.genExpr(expr.args[0]);
|
|
46
61
|
const restArgs = expr.args
|
|
47
62
|
.slice(1)
|
|
48
63
|
.map((e) => this.genExpr(e))
|
|
49
64
|
.join(", ");
|
|
50
|
-
return `((str, ...ptrs) => { const tokens = str.trim().split(/\\s+/).filter(Boolean); ${_SSCAN_LOOP} return [n, n < ptrs.length ? "unexpected EOF" : null]; })(${strArg}, ${restArgs})`;
|
|
65
|
+
return `((str, ...ptrs) => { const tokens = str.trim().split(/\\s+/).filter(Boolean); ${_SSCAN_LOOP} return [n, err ? err : (n < ptrs.length ? __error("unexpected EOF") : null)]; })(${strArg}, ${restArgs})`;
|
|
51
66
|
}
|
|
52
67
|
case "Sscanln": {
|
|
68
|
+
this.useHelper("error");
|
|
53
69
|
const strArg = this.genExpr(expr.args[0]);
|
|
54
70
|
const restArgs = expr.args
|
|
55
71
|
.slice(1)
|
|
56
72
|
.map((e) => this.genExpr(e))
|
|
57
73
|
.join(", ");
|
|
58
|
-
return `((str, ...ptrs) => { const tokens = str.split("\\n")[0].trim().split(/\\s+/).filter(Boolean); ${_SSCAN_LOOP} return [n, n < ptrs.length ? "unexpected EOF" : null]; })(${strArg}, ${restArgs})`;
|
|
74
|
+
return `((str, ...ptrs) => { const tokens = str.split("\\n")[0].trim().split(/\\s+/).filter(Boolean); ${_SSCAN_LOOP} return [n, err ? err : (n < ptrs.length ? __error("unexpected EOF") : null)]; })(${strArg}, ${restArgs})`;
|
|
59
75
|
}
|
|
60
76
|
case "Sscanf": {
|
|
77
|
+
this.useHelper("error");
|
|
61
78
|
const strArg = this.genExpr(expr.args[0]);
|
|
62
79
|
const fmtArg = this.genExpr(expr.args[1]);
|
|
63
80
|
const restArgs = expr.args
|
|
64
81
|
.slice(2)
|
|
65
82
|
.map((e) => this.genExpr(e))
|
|
66
83
|
.join(", ");
|
|
67
|
-
return
|
|
84
|
+
return (
|
|
85
|
+
`((str, fmt, ...ptrs) => { ` +
|
|
86
|
+
`const s = String(str); const f = String(fmt); ` +
|
|
87
|
+
`let si = 0, fi = 0; const tokens = []; let parseErr = null; ` +
|
|
88
|
+
`while (fi < f.length) { ` +
|
|
89
|
+
`if (/\\s/.test(f[fi])) { ` +
|
|
90
|
+
`while (fi < f.length && /\\s/.test(f[fi])) fi++; ` +
|
|
91
|
+
`while (si < s.length && /\\s/.test(s[si])) si++; ` +
|
|
92
|
+
`continue; ` +
|
|
93
|
+
`} ` +
|
|
94
|
+
`if (f[fi] === "%") { ` +
|
|
95
|
+
`if (fi + 1 < f.length && f[fi + 1] === "%") { ` +
|
|
96
|
+
`if (s[si] !== "%") { parseErr = __error("input does not match format"); break; } ` +
|
|
97
|
+
`si++; fi += 2; continue; ` +
|
|
98
|
+
`} ` +
|
|
99
|
+
`const vm = f.slice(fi).match(/^%[vdsfqtxXbcoeEfFgG]/); ` +
|
|
100
|
+
`if (vm) { ` +
|
|
101
|
+
`const verb = vm[0]; fi += verb.length; ` +
|
|
102
|
+
`if (verb !== "%c") { while (si < s.length && /\\s/.test(s[si])) si++; } ` +
|
|
103
|
+
`if (si >= s.length) break; ` +
|
|
104
|
+
`let tokRe = /^\\S+/; ` +
|
|
105
|
+
`if (verb === "%d" || verb === "%i") tokRe = /^[+-]?\\d+/; ` +
|
|
106
|
+
`else if (verb === "%o") tokRe = /^[+-]?(?:0[oO])?[0-7]+/; ` +
|
|
107
|
+
`else if (verb === "%b") tokRe = /^[+-]?(?:0[bB])?[01]+/; ` +
|
|
108
|
+
`else if (verb === "%f" || verb === "%F" || verb === "%e" || verb === "%E" || verb === "%g" || verb === "%G") tokRe = /^[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[eE][+-]?\\d+)?/; ` +
|
|
109
|
+
`else if (verb === "%t") tokRe = /^(?:true|false|1|0|t|f|T|F|TRUE|FALSE)/; ` +
|
|
110
|
+
`else if (verb === "%x" || verb === "%X") tokRe = /^[+-]?(?:0x)?[0-9a-fA-F]+/; ` +
|
|
111
|
+
`else if (verb === "%c") tokRe = /^[\\s\\S]/; ` +
|
|
112
|
+
`const m = s.slice(si).match(tokRe); ` +
|
|
113
|
+
`if (!m) { parseErr = __error("input does not match format"); break; } ` +
|
|
114
|
+
`tokens.push({ t: m[0], verb }); si += m[0].length; continue; ` +
|
|
115
|
+
`} ` +
|
|
116
|
+
`} ` +
|
|
117
|
+
`if (si >= s.length) break; ` +
|
|
118
|
+
`if (s[si] !== f[fi]) { parseErr = __error("input does not match format"); break; } ` +
|
|
119
|
+
`si++; fi++; ` +
|
|
120
|
+
`} ` +
|
|
121
|
+
`${_SSCAN_LOOP} ` +
|
|
122
|
+
`return [n, parseErr || err || (n < ptrs.length ? __error("unexpected EOF") : null)]; ` +
|
|
123
|
+
`})(${strArg}, ${fmtArg}, ${restArgs})`
|
|
124
|
+
);
|
|
68
125
|
}
|
|
69
126
|
default:
|
|
70
127
|
return undefined;
|
|
@@ -75,7 +132,7 @@ export const fmtMethods = {
|
|
|
75
132
|
this.useHelper("sprintf");
|
|
76
133
|
const writerArg = expr.args[0];
|
|
77
134
|
const rest = expr.args.slice(1);
|
|
78
|
-
const restJs = rest.map((e) => this.
|
|
135
|
+
const restJs = rest.map((e) => this._fmtArgJs(e)).join(", ");
|
|
79
136
|
const writerType = writerArg._type;
|
|
80
137
|
const targetTypeName =
|
|
81
138
|
writerType?.name ??
|
|
@@ -84,16 +141,16 @@ export const fmtMethods = {
|
|
|
84
141
|
if (targetTypeName === "strings.Builder") {
|
|
85
142
|
const w = this.genExpr(writerArg);
|
|
86
143
|
const base = this._unboxWriter(w);
|
|
87
|
-
return `(
|
|
144
|
+
return `((__b, __s) => { __b._buf += __s; return [__s.length, null]; })(${base}, ${sprintfCall})`;
|
|
88
145
|
}
|
|
89
146
|
if (targetTypeName === "bytes.Buffer") {
|
|
90
147
|
const w = this.genExpr(writerArg);
|
|
91
148
|
const base = this._unboxWriter(w);
|
|
92
|
-
return `((__b,__s)=>{
|
|
149
|
+
return `((__b, __s) => { const __bytes = new TextEncoder().encode(__s); for (let i = 0; i < __bytes.length; i++) __b._buf.push(__bytes[i]); return [__bytes.length, null]; })(${base}, ${sprintfCall})`;
|
|
93
150
|
}
|
|
94
151
|
// Generic io.Writer fallback — call .WriteString if available
|
|
95
152
|
const w = this.genExpr(writerArg);
|
|
96
|
-
return
|
|
153
|
+
return `((__w, __s) => typeof __w.WriteString === "function" ? __w.WriteString(__s) : __w.Write(new TextEncoder().encode(__s)))(${w}, ${sprintfCall})`;
|
|
97
154
|
},
|
|
98
155
|
|
|
99
156
|
_genStdoutWrite(strJs) {
|
|
@@ -106,7 +163,7 @@ export const fmtMethods = {
|
|
|
106
163
|
const argc = expr.args.length;
|
|
107
164
|
if (argc === 0) return JSON.stringify(suffix);
|
|
108
165
|
const fmt = Array(argc).fill("%v").join(sep) + suffix;
|
|
109
|
-
const args = expr.args.map((e) => this.
|
|
166
|
+
const args = expr.args.map((e) => this._fmtArgJs(e)).join(", ");
|
|
110
167
|
return `__sprintf(${JSON.stringify(fmt)}, ${args})`;
|
|
111
168
|
},
|
|
112
169
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// src/backend/js/stdlib/hex.js
|
|
2
|
+
// CodeGen for Go encoding/hex package.
|
|
3
|
+
|
|
4
|
+
export const hexMethods = {
|
|
5
|
+
_genHex(fn, a) {
|
|
6
|
+
this.useHelper("hex");
|
|
7
|
+
this.useHelper("error");
|
|
8
|
+
const args = a();
|
|
9
|
+
if (fn === "EncodeToString") return `__hex_encode_to_string(${args[0]})`;
|
|
10
|
+
if (fn === "DecodeString") return `__hex_decode_string(${args[0]})`;
|
|
11
|
+
if (fn === "Encode") return `__hex_encode(${args[0]}, ${args[1]})`;
|
|
12
|
+
if (fn === "Decode") return `__hex_decode(${args[0]}, ${args[1]})`;
|
|
13
|
+
if (fn === "EncodedLen") return `(${args[0]} * 2)`;
|
|
14
|
+
if (fn === "DecodedLen") return `Math.floor(${args[0]} / 2)`;
|
|
15
|
+
return undefined;
|
|
16
|
+
},
|
|
17
|
+
};
|
|
@@ -12,7 +12,7 @@ export const htmlMethods = {
|
|
|
12
12
|
}
|
|
13
13
|
case "UnescapeString": {
|
|
14
14
|
const [s] = a();
|
|
15
|
-
return
|
|
15
|
+
return `(${s}).replace(/&(?:quot|apos|#39|#34|gt|lt|amp|#(?:[0-9]+|[xX][0-9a-fA-F]+));/g, m => { switch (m) { case """: case """: return '"'; case "'": case "'": return "'"; case ">": return ">"; case "<": return "<"; case "&": return "&"; default: { if (m.startsWith("&#")) { const raw = m.slice(2, -1); const cp = (raw.startsWith("x") || raw.startsWith("X")) ? parseInt(raw.slice(1), 16) : parseInt(raw, 10); return (cp >= 0 && cp <= 0x10FFFF && !(cp >= 0xD800 && cp <= 0xDFFF)) ? String.fromCodePoint(cp) : "\\uFFFD"; } return m; } } })`;
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
return undefined;
|
|
@@ -1,25 +1,32 @@
|
|
|
1
1
|
// CodeGen stdlib call generation — installed as a mixin on CodeGen.prototype.
|
|
2
2
|
// One file per Go package under ./stdlib/. This index merges them.
|
|
3
3
|
|
|
4
|
+
import { base64Methods } from "./base64.js";
|
|
5
|
+
import { binaryMethods } from "./binary.js";
|
|
4
6
|
import { bitsMethods } from "./bits.js";
|
|
5
7
|
import { builderMethods } from "./builder.js";
|
|
6
8
|
import { bytesMethods } from "./bytes.js";
|
|
7
9
|
import { errorsMethods } from "./errors.js";
|
|
8
10
|
import { fmtMethods } from "./fmt.js";
|
|
9
11
|
import { gomMethods } from "./gom.js";
|
|
12
|
+
import { hexMethods } from "./hex.js";
|
|
10
13
|
import { htmlMethods } from "./html.js";
|
|
11
14
|
import { ioMethods } from "./io.js";
|
|
15
|
+
import { jsonMethods } from "./json.js";
|
|
12
16
|
import { mapsMethods } from "./maps.js";
|
|
13
17
|
import { mathMethods } from "./math.js";
|
|
14
18
|
import { osMethods } from "./os.js";
|
|
15
19
|
import { pathMethods } from "./path.js";
|
|
16
20
|
import { randMethods } from "./rand.js";
|
|
17
21
|
import { regexpMethods } from "./regexp.js";
|
|
22
|
+
import { sha256Methods } from "./sha256.js";
|
|
18
23
|
import { sharedMethods } from "./shared.js";
|
|
24
|
+
import { simdMethods } from "./simd.js";
|
|
19
25
|
import { slicesMethods } from "./slices.js";
|
|
20
26
|
import { sortMethods } from "./sort.js";
|
|
21
27
|
import { strconvMethods } from "./strconv.js";
|
|
22
28
|
import { stringsMethods } from "./strings.js";
|
|
29
|
+
import { syncMethods } from "./sync.js";
|
|
23
30
|
import { testingMethods } from "./testing.js";
|
|
24
31
|
import { timeMethods } from "./time.js";
|
|
25
32
|
import { unicodeMethods } from "./unicode.js";
|
|
@@ -49,8 +56,16 @@ const STDLIB_METHOD_MAP = {
|
|
|
49
56
|
rand: "_genRand",
|
|
50
57
|
utf8: "_genUtf8",
|
|
51
58
|
path: "_genPath",
|
|
59
|
+
filepath: "_genPath",
|
|
52
60
|
testing: "_genTesting",
|
|
53
61
|
shared: "_genShared",
|
|
62
|
+
sync: "_genSync",
|
|
63
|
+
sha256: "_genSha256",
|
|
64
|
+
binary: "_genBinary",
|
|
65
|
+
hex: "_genHex",
|
|
66
|
+
base64: "_genBase64",
|
|
67
|
+
json: "_genJson",
|
|
68
|
+
simd: "_genSimd",
|
|
54
69
|
};
|
|
55
70
|
|
|
56
71
|
const dispatchMethods = {
|
|
@@ -71,6 +86,12 @@ const dispatchMethods = {
|
|
|
71
86
|
// Dispatch table for stdlib namespace calls (pkg.Func → inline JS).
|
|
72
87
|
// Returns the generated JS string, or undefined if not handled.
|
|
73
88
|
_genStdlibCall(ns, fn, expr) {
|
|
89
|
+
// Stdlib shims take raw values; only fmt and errors use the interface box
|
|
90
|
+
// of a named value (Error() dispatch, error comparisons).
|
|
91
|
+
const isNamespace = expr.func?.expr?._type?.kind === "namespace";
|
|
92
|
+
if (isNamespace && ns !== "fmt" && ns !== "errors") {
|
|
93
|
+
for (const e of expr.args) if (e) e._noNamedBox = true;
|
|
94
|
+
}
|
|
74
95
|
const a = () => expr.args.map((e) => this.genExpr(e));
|
|
75
96
|
if (ns === "gom") return this._genGom(fn, expr);
|
|
76
97
|
const method = STDLIB_METHOD_MAP[ns];
|
|
@@ -95,6 +116,7 @@ export const stdlibGenMethods = {
|
|
|
95
116
|
...randMethods,
|
|
96
117
|
...regexpMethods,
|
|
97
118
|
...sharedMethods,
|
|
119
|
+
...simdMethods,
|
|
98
120
|
...slicesMethods,
|
|
99
121
|
...sortMethods,
|
|
100
122
|
...strconvMethods,
|
|
@@ -103,5 +125,11 @@ export const stdlibGenMethods = {
|
|
|
103
125
|
...unicodeMethods,
|
|
104
126
|
...utf8Methods,
|
|
105
127
|
...testingMethods,
|
|
128
|
+
...syncMethods,
|
|
129
|
+
...sha256Methods,
|
|
130
|
+
...binaryMethods,
|
|
131
|
+
...hexMethods,
|
|
132
|
+
...base64Methods,
|
|
133
|
+
...jsonMethods,
|
|
106
134
|
...dispatchMethods,
|
|
107
135
|
};
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
/** @type {ThisType<CodeGen>} */
|
|
6
6
|
export const ioMethods = {
|
|
7
7
|
_genIo(fn, _a, expr) {
|
|
8
|
+
if (fn === "ReadAll") this.useHelper("error");
|
|
8
9
|
switch (fn) {
|
|
9
10
|
case "WriteString": {
|
|
10
11
|
const writerArg = expr.args[0];
|
|
@@ -19,15 +20,116 @@ export const ioMethods = {
|
|
|
19
20
|
return `((b,s) => { b._buf += s; return [s.length, null]; })(${base}, ${s})`;
|
|
20
21
|
}
|
|
21
22
|
if (typeName === "bytes.Buffer") {
|
|
22
|
-
return `((b,s) => {
|
|
23
|
+
return `((b,s) => { const bytes = new TextEncoder().encode(s); for (let i = 0; i < bytes.length; i++) b._buf.push(bytes[i]); return [bytes.length, null]; })(${base}, ${s})`;
|
|
23
24
|
}
|
|
24
25
|
// Generic: auto-dereference pointer, then dispatch on concrete writer type.
|
|
25
26
|
// strings.Builder has { _buf: string }, bytes.Buffer has { _buf: [] }.
|
|
26
|
-
return `((b,s) => { const w = b?.value ?? b; if (typeof w.WriteString === "function") return
|
|
27
|
+
return `((b,s) => { const w = b?.value ?? b; if (typeof w.WriteString === "function") return w.WriteString(s); if (typeof w._buf === "string") { w._buf += s; return [s.length, null]; } if (Array.isArray(w._buf)) { const bytes = new TextEncoder().encode(s); for (let i = 0; i < bytes.length; i++) w._buf.push(bytes[i]); return [bytes.length, null]; } if (typeof w.Write === "function") return w.Write(new TextEncoder().encode(s)); return [0, "io.WriteString: unsupported writer"]; })(${w}, ${s})`;
|
|
27
28
|
}
|
|
28
29
|
case "ReadAll": {
|
|
30
|
+
this.useHelper("ioEOF");
|
|
29
31
|
const r = this.genExpr(expr.args[0]);
|
|
30
|
-
return `((r) => { const w = r?.value ?? r;
|
|
32
|
+
return `((r) => { const w = r?.value ?? r; const chunks = []; const buf = new Uint8Array(512); let err = null; while (!err) { const [n, e] = w.Read(buf); if (n > 0) { for (let i = 0; i < n; i++) chunks.push(buf[i]); } if (n === 0 && !e) break; err = e; } return [new Uint8Array(chunks), (err === "EOF" || err === __io_eof || err?._msg === "EOF") ? null : err]; })(${r})`;
|
|
33
|
+
}
|
|
34
|
+
case "LimitReader": {
|
|
35
|
+
this.useHelper("ioEOF");
|
|
36
|
+
const r = this.genExpr(expr.args[0]);
|
|
37
|
+
const n = this.genExpr(expr.args[1]);
|
|
38
|
+
return `((r, n) => {
|
|
39
|
+
let rem = typeof n === "bigint" ? Number(n) : Number(n);
|
|
40
|
+
const reader = r?.value ?? r;
|
|
41
|
+
return {
|
|
42
|
+
Read(buf) {
|
|
43
|
+
if (rem <= 0) return [0, __io_eof];
|
|
44
|
+
const max = buf.length > rem ? rem : buf.length;
|
|
45
|
+
const slice = buf.subarray ? buf.subarray(0, max) : buf.slice(0, max);
|
|
46
|
+
const [readN, err] = reader.Read(slice);
|
|
47
|
+
if (readN > 0) {
|
|
48
|
+
if (buf.set && slice !== buf) buf.set(slice.subarray(0, readN), 0);
|
|
49
|
+
rem -= readN;
|
|
50
|
+
}
|
|
51
|
+
return [readN, err];
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
})(${r}, ${n})`;
|
|
55
|
+
}
|
|
56
|
+
case "Copy": {
|
|
57
|
+
this.useHelper("ioEOF");
|
|
58
|
+
const dst = this.genExpr(expr.args[0]);
|
|
59
|
+
const src = this.genExpr(expr.args[1]);
|
|
60
|
+
return `((dst, src) => {
|
|
61
|
+
const w = dst?.value ?? dst;
|
|
62
|
+
const r = src?.value ?? src;
|
|
63
|
+
const writeChunk = (chunk) => {
|
|
64
|
+
if (typeof w?.Write === "function") return w.Write(chunk);
|
|
65
|
+
if (Array.isArray(w?._buf)) {
|
|
66
|
+
for (let i = 0; i < chunk.length; i++) w._buf.push(chunk[i]);
|
|
67
|
+
return [chunk.length, null];
|
|
68
|
+
}
|
|
69
|
+
if (typeof w?._buf === "string") {
|
|
70
|
+
w._buf += new TextDecoder().decode(chunk);
|
|
71
|
+
return [chunk.length, null];
|
|
72
|
+
}
|
|
73
|
+
return [0, "unsupported writer"];
|
|
74
|
+
};
|
|
75
|
+
const buf = new Uint8Array(32 * 1024);
|
|
76
|
+
let total = 0;
|
|
77
|
+
while (true) {
|
|
78
|
+
const [n, rerr] = r.Read(buf);
|
|
79
|
+
if (n > 0) {
|
|
80
|
+
const chunk = buf.subarray(0, n);
|
|
81
|
+
const [wn, werr] = writeChunk(chunk);
|
|
82
|
+
total += wn;
|
|
83
|
+
if (werr) return [total, werr];
|
|
84
|
+
}
|
|
85
|
+
if (rerr) {
|
|
86
|
+
if (rerr === "EOF" || rerr === __io_eof || rerr?._msg === "EOF") return [total, null];
|
|
87
|
+
return [total, rerr];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
})(${dst}, ${src})`;
|
|
91
|
+
}
|
|
92
|
+
case "CopyN": {
|
|
93
|
+
this.useHelper("ioEOF");
|
|
94
|
+
const dst = this.genExpr(expr.args[0]);
|
|
95
|
+
const src = this.genExpr(expr.args[1]);
|
|
96
|
+
const n = this.genExpr(expr.args[2]);
|
|
97
|
+
return `((dst, src, n) => {
|
|
98
|
+
const w = dst?.value ?? dst;
|
|
99
|
+
const r = src?.value ?? src;
|
|
100
|
+
const writeChunk = (chunk) => {
|
|
101
|
+
if (typeof w?.Write === "function") return w.Write(chunk);
|
|
102
|
+
if (Array.isArray(w?._buf)) {
|
|
103
|
+
for (let i = 0; i < chunk.length; i++) w._buf.push(chunk[i]);
|
|
104
|
+
return [chunk.length, null];
|
|
105
|
+
}
|
|
106
|
+
if (typeof w?._buf === "string") {
|
|
107
|
+
w._buf += new TextDecoder().decode(chunk);
|
|
108
|
+
return [chunk.length, null];
|
|
109
|
+
}
|
|
110
|
+
return [0, "unsupported writer"];
|
|
111
|
+
};
|
|
112
|
+
let rem = typeof n === "bigint" ? Number(n) : Number(n);
|
|
113
|
+
let total = 0;
|
|
114
|
+
const buf = new Uint8Array(32 * 1024);
|
|
115
|
+
while (rem > 0) {
|
|
116
|
+
const toRead = rem < buf.length ? rem : buf.length;
|
|
117
|
+
const [rn, rerr] = r.Read(buf.subarray(0, toRead));
|
|
118
|
+
if (rn > 0) {
|
|
119
|
+
const [wn, werr] = writeChunk(buf.subarray(0, rn));
|
|
120
|
+
total += wn;
|
|
121
|
+
rem -= wn;
|
|
122
|
+
if (werr) return [total, werr];
|
|
123
|
+
}
|
|
124
|
+
if (rerr) {
|
|
125
|
+
if ((rerr === "EOF" || rerr === __io_eof || rerr?._msg === "EOF") && rem === 0) {
|
|
126
|
+
return [total, null];
|
|
127
|
+
}
|
|
128
|
+
return [total, rerr];
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return [total, null];
|
|
132
|
+
})(${dst}, ${src}, ${n})`;
|
|
31
133
|
}
|
|
32
134
|
}
|
|
33
135
|
return undefined;
|