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
|
@@ -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,17 +4,36 @@
|
|
|
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
|
-
this.
|
|
10
|
+
this.useHelper("error");
|
|
11
11
|
return `__error(${args[0]})`;
|
|
12
12
|
}
|
|
13
13
|
if (fn === "Is") {
|
|
14
|
-
this.
|
|
14
|
+
this.useHelper("errorIs");
|
|
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
|
};
|
|
@@ -3,23 +3,37 @@
|
|
|
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
|
-
this.
|
|
32
|
+
this.useHelper("sprintf");
|
|
19
33
|
return `__sprintf(${fmtArgs})`;
|
|
20
34
|
case "Errorf": {
|
|
21
|
-
this.
|
|
22
|
-
this.
|
|
35
|
+
this.useHelper("sprintf");
|
|
36
|
+
this.useHelper("error");
|
|
23
37
|
const fmtStr = expr.args[0];
|
|
24
38
|
if (fmtStr?.kind === "BasicLit" && fmtStr.value?.includes("%w")) {
|
|
25
39
|
const lastArg = this.genExpr(expr.args[expr.args.length - 1]);
|
|
@@ -28,40 +42,86 @@ export const fmtMethods = {
|
|
|
28
42
|
return `__error(__sprintf(${fmtArgs}))`;
|
|
29
43
|
}
|
|
30
44
|
case "Printf":
|
|
45
|
+
this.useHelper("sprintf");
|
|
46
|
+
return this._genStdoutWrite(`__sprintf(${fmtArgs})`);
|
|
31
47
|
case "Print":
|
|
32
|
-
this.
|
|
33
|
-
return
|
|
48
|
+
this.useHelper("sprintf");
|
|
49
|
+
return this._genStdoutWrite(this._genPrintOperands(expr, "", ""));
|
|
34
50
|
case "Println":
|
|
35
|
-
this.
|
|
36
|
-
|
|
51
|
+
this.useHelper("sprintf");
|
|
52
|
+
// console.log supplies the trailing newline.
|
|
53
|
+
return `console.log(${this._genPrintOperands(expr, " ", "")})`;
|
|
37
54
|
case "Fprintf":
|
|
38
55
|
case "Fprintln":
|
|
39
56
|
case "Fprint":
|
|
40
57
|
return this._genFmtFprint(fn, expr);
|
|
41
58
|
case "Sscan": {
|
|
59
|
+
this.useHelper("error");
|
|
42
60
|
const strArg = this.genExpr(expr.args[0]);
|
|
43
61
|
const restArgs = expr.args
|
|
44
62
|
.slice(1)
|
|
45
63
|
.map((e) => this.genExpr(e))
|
|
46
64
|
.join(", ");
|
|
47
|
-
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})`;
|
|
48
66
|
}
|
|
49
67
|
case "Sscanln": {
|
|
68
|
+
this.useHelper("error");
|
|
50
69
|
const strArg = this.genExpr(expr.args[0]);
|
|
51
70
|
const restArgs = expr.args
|
|
52
71
|
.slice(1)
|
|
53
72
|
.map((e) => this.genExpr(e))
|
|
54
73
|
.join(", ");
|
|
55
|
-
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})`;
|
|
56
75
|
}
|
|
57
76
|
case "Sscanf": {
|
|
77
|
+
this.useHelper("error");
|
|
58
78
|
const strArg = this.genExpr(expr.args[0]);
|
|
59
79
|
const fmtArg = this.genExpr(expr.args[1]);
|
|
60
80
|
const restArgs = expr.args
|
|
61
81
|
.slice(2)
|
|
62
82
|
.map((e) => this.genExpr(e))
|
|
63
83
|
.join(", ");
|
|
64
|
-
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
|
+
);
|
|
65
125
|
}
|
|
66
126
|
default:
|
|
67
127
|
return undefined;
|
|
@@ -69,10 +129,10 @@ export const fmtMethods = {
|
|
|
69
129
|
},
|
|
70
130
|
|
|
71
131
|
_genFmtFprint(fn, expr) {
|
|
72
|
-
this.
|
|
132
|
+
this.useHelper("sprintf");
|
|
73
133
|
const writerArg = expr.args[0];
|
|
74
134
|
const rest = expr.args.slice(1);
|
|
75
|
-
const restJs = rest.map((e) => this.
|
|
135
|
+
const restJs = rest.map((e) => this._fmtArgJs(e)).join(", ");
|
|
76
136
|
const writerType = writerArg._type;
|
|
77
137
|
const targetTypeName =
|
|
78
138
|
writerType?.name ??
|
|
@@ -81,20 +141,35 @@ export const fmtMethods = {
|
|
|
81
141
|
if (targetTypeName === "strings.Builder") {
|
|
82
142
|
const w = this.genExpr(writerArg);
|
|
83
143
|
const base = this._unboxWriter(w);
|
|
84
|
-
return `(
|
|
144
|
+
return `((__b, __s) => { __b._buf += __s; return [__s.length, null]; })(${base}, ${sprintfCall})`;
|
|
85
145
|
}
|
|
86
146
|
if (targetTypeName === "bytes.Buffer") {
|
|
87
147
|
const w = this.genExpr(writerArg);
|
|
88
148
|
const base = this._unboxWriter(w);
|
|
89
|
-
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})`;
|
|
90
150
|
}
|
|
91
151
|
// Generic io.Writer fallback — call .WriteString if available
|
|
92
152
|
const w = this.genExpr(writerArg);
|
|
93
|
-
return
|
|
153
|
+
return `((__w, __s) => typeof __w.WriteString === "function" ? __w.WriteString(__s) : __w.Write(new TextEncoder().encode(__s)))(${w}, ${sprintfCall})`;
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
_genStdoutWrite(strJs) {
|
|
157
|
+
return `((__s) => (typeof process !== "undefined" && process?.stdout?.write ? process.stdout.write(__s) : console.log(__s)))(${strJs})`;
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
// Formats Print/Println operands with %v so the first operand is never
|
|
161
|
+
// mistaken for a format string.
|
|
162
|
+
_genPrintOperands(expr, sep, suffix) {
|
|
163
|
+
const argc = expr.args.length;
|
|
164
|
+
if (argc === 0) return JSON.stringify(suffix);
|
|
165
|
+
const fmt = Array(argc).fill("%v").join(sep) + suffix;
|
|
166
|
+
const args = expr.args.map((e) => this._fmtArgJs(e)).join(", ");
|
|
167
|
+
return `__sprintf(${JSON.stringify(fmt)}, ${args})`;
|
|
94
168
|
},
|
|
95
169
|
|
|
96
170
|
_buildFprintSprintfCall(fn, argc, restJs) {
|
|
97
171
|
if (fn === "Fprintf") return `__sprintf(${restJs})`;
|
|
172
|
+
if (argc === 0) return fn === "Fprintln" ? '"\\n"' : '""';
|
|
98
173
|
const sep = fn === "Fprintln" ? " " : "";
|
|
99
174
|
const suffix = fn === "Fprintln" ? "\\n" : "";
|
|
100
175
|
const fmt = Array(argc).fill("%v").join(sep) + suffix;
|
|
@@ -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,12 +1,15 @@
|
|
|
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";
|
|
12
15
|
import { mapsMethods } from "./maps.js";
|
|
@@ -15,10 +18,13 @@ import { osMethods } from "./os.js";
|
|
|
15
18
|
import { pathMethods } from "./path.js";
|
|
16
19
|
import { randMethods } from "./rand.js";
|
|
17
20
|
import { regexpMethods } from "./regexp.js";
|
|
21
|
+
import { sha256Methods } from "./sha256.js";
|
|
22
|
+
import { sharedMethods } from "./shared.js";
|
|
18
23
|
import { slicesMethods } from "./slices.js";
|
|
19
24
|
import { sortMethods } from "./sort.js";
|
|
20
25
|
import { strconvMethods } from "./strconv.js";
|
|
21
26
|
import { stringsMethods } from "./strings.js";
|
|
27
|
+
import { syncMethods } from "./sync.js";
|
|
22
28
|
import { testingMethods } from "./testing.js";
|
|
23
29
|
import { timeMethods } from "./time.js";
|
|
24
30
|
import { unicodeMethods } from "./unicode.js";
|
|
@@ -48,7 +54,14 @@ const STDLIB_METHOD_MAP = {
|
|
|
48
54
|
rand: "_genRand",
|
|
49
55
|
utf8: "_genUtf8",
|
|
50
56
|
path: "_genPath",
|
|
57
|
+
filepath: "_genPath",
|
|
51
58
|
testing: "_genTesting",
|
|
59
|
+
shared: "_genShared",
|
|
60
|
+
sync: "_genSync",
|
|
61
|
+
sha256: "_genSha256",
|
|
62
|
+
binary: "_genBinary",
|
|
63
|
+
hex: "_genHex",
|
|
64
|
+
base64: "_genBase64",
|
|
52
65
|
};
|
|
53
66
|
|
|
54
67
|
const dispatchMethods = {
|
|
@@ -92,6 +105,7 @@ export const stdlibGenMethods = {
|
|
|
92
105
|
...pathMethods,
|
|
93
106
|
...randMethods,
|
|
94
107
|
...regexpMethods,
|
|
108
|
+
...sharedMethods,
|
|
95
109
|
...slicesMethods,
|
|
96
110
|
...sortMethods,
|
|
97
111
|
...strconvMethods,
|
|
@@ -100,5 +114,10 @@ export const stdlibGenMethods = {
|
|
|
100
114
|
...unicodeMethods,
|
|
101
115
|
...utf8Methods,
|
|
102
116
|
...testingMethods,
|
|
117
|
+
...syncMethods,
|
|
118
|
+
...sha256Methods,
|
|
119
|
+
...binaryMethods,
|
|
120
|
+
...hexMethods,
|
|
121
|
+
...base64Methods,
|
|
103
122
|
...dispatchMethods,
|
|
104
123
|
};
|
|
@@ -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;
|
|
@@ -19,6 +19,9 @@ const MATH1 = {
|
|
|
19
19
|
Acos: "acos",
|
|
20
20
|
Exp: "exp",
|
|
21
21
|
Trunc: "trunc",
|
|
22
|
+
Sinh: "sinh",
|
|
23
|
+
Cosh: "cosh",
|
|
24
|
+
Tanh: "tanh",
|
|
22
25
|
};
|
|
23
26
|
const MATH2 = {
|
|
24
27
|
Pow: "pow",
|
|
@@ -41,7 +44,16 @@ const MATH_EXTRA = {
|
|
|
41
44
|
Copysign: ([x, y]) =>
|
|
42
45
|
`(Math.abs(${x}) * (${y} < 0 || Object.is(${y}, -0) ? -1 : 1))`,
|
|
43
46
|
Dim: ([x, y]) => `Math.max(${x} - ${y}, 0)`,
|
|
44
|
-
Remainder: ([x, y]) =>
|
|
47
|
+
Remainder: ([x, y]) =>
|
|
48
|
+
`((x, y) => { if (isNaN(x) || isNaN(y) || y === 0 || !isFinite(x)) return NaN; if (!isFinite(y)) return x; const q = x / y; const r = Math.round(q); const diff = Math.abs(q - r); const n = (diff === 0.5 && (r % 2 !== 0)) ? (r < q ? r + 1 : r - 1) : r; return x - n * y; })(${x}, ${y})`,
|
|
49
|
+
Float64bits: ([x]) =>
|
|
50
|
+
`((f) => { const b = new ArrayBuffer(8); new Float64Array(b)[0] = f; return Number(new BigUint64Array(b)[0]); })(${x})`,
|
|
51
|
+
Float64frombits: ([b]) =>
|
|
52
|
+
`((u) => { const buf = new ArrayBuffer(8); new BigUint64Array(buf)[0] = BigInt(u); return new Float64Array(buf)[0]; })(${b})`,
|
|
53
|
+
Float32bits: ([x]) =>
|
|
54
|
+
`((f) => { const b = new ArrayBuffer(4); new Float32Array(b)[0] = f; return new Uint32Array(b)[0]; })(${x})`,
|
|
55
|
+
Float32frombits: ([b]) =>
|
|
56
|
+
`((u) => { const buf = new ArrayBuffer(4); new Uint32Array(buf)[0] = Number(u) >>> 0; return new Float32Array(buf)[0]; })(${b})`,
|
|
45
57
|
};
|
|
46
58
|
|
|
47
59
|
/** @type {ThisType<CodeGen>} */
|