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.
Files changed (91) hide show
  1. package/README.md +174 -466
  2. package/package.json +16 -20
  3. package/src/backend/js/expressions.js +288 -128
  4. package/src/backend/js/index.js +138 -56
  5. package/src/backend/js/runtime.js +1055 -53
  6. package/src/backend/js/source-map.js +32 -0
  7. package/src/backend/js/statements.js +151 -83
  8. package/src/backend/js/stdlib/base64.js +12 -0
  9. package/src/backend/js/stdlib/binary.js +102 -0
  10. package/src/backend/js/stdlib/bits.js +15 -1
  11. package/src/backend/js/stdlib/builder.js +28 -9
  12. package/src/backend/js/stdlib/bytes.js +75 -18
  13. package/src/backend/js/stdlib/errors.js +22 -3
  14. package/src/backend/js/stdlib/fmt.js +95 -20
  15. package/src/backend/js/stdlib/hex.js +17 -0
  16. package/src/backend/js/stdlib/html.js +1 -1
  17. package/src/backend/js/stdlib/index.js +19 -0
  18. package/src/backend/js/stdlib/io.js +105 -3
  19. package/src/backend/js/stdlib/maps.js +1 -1
  20. package/src/backend/js/stdlib/math.js +13 -1
  21. package/src/backend/js/stdlib/path.js +20 -6
  22. package/src/backend/js/stdlib/rand.js +10 -5
  23. package/src/backend/js/stdlib/sha256.js +12 -0
  24. package/src/backend/js/stdlib/shared.js +17 -0
  25. package/src/backend/js/stdlib/slices.js +53 -27
  26. package/src/backend/js/stdlib/sort.js +1 -1
  27. package/src/backend/js/stdlib/strconv.js +52 -11
  28. package/src/backend/js/stdlib/strings.js +152 -16
  29. package/src/backend/js/stdlib/sync.js +13 -0
  30. package/src/backend/js/stdlib/testing.js +2 -2
  31. package/src/backend/js/stdlib/time.js +93 -22
  32. package/src/backend/js/stdlib/unicode.js +2 -2
  33. package/src/backend/js/templ.js +1 -1
  34. package/src/backend/wasm/boundary.js +1677 -58
  35. package/src/backend/wasm/const-fold.js +205 -0
  36. package/src/backend/wasm/emit-builtins.js +1230 -0
  37. package/src/backend/wasm/emit-exprs.js +2096 -0
  38. package/src/backend/wasm/emit-maps.js +1999 -0
  39. package/src/backend/wasm/emit-shared.js +519 -0
  40. package/src/backend/wasm/emit-stdlib.js +13 -0
  41. package/src/backend/wasm/emit-stmts.js +2466 -0
  42. package/src/backend/wasm/emit.js +656 -5031
  43. package/src/backend/wasm/encode.js +259 -85
  44. package/src/backend/wasm/glue.js +19 -5
  45. package/src/backend/wasm/index.js +2432 -86
  46. package/src/backend/wasm/monomorph.js +711 -0
  47. package/src/backend/wasm/optimize.js +236 -0
  48. package/src/backend/wasm/stdlib/bytes.js +5039 -0
  49. package/src/backend/wasm/stdlib/core.js +8903 -0
  50. package/src/backend/wasm/stdlib/index.js +40 -0
  51. package/src/backend/wasm/stdlib/io.js +2161 -0
  52. package/src/backend/wasm/stdlib/packages.js +2400 -0
  53. package/src/backend/wasm/stdlib/pure.js +720 -0
  54. package/src/backend/wasm/stdlib/time.js +1200 -0
  55. package/src/backend/wasm/types.js +312 -36
  56. package/src/backend/wasm/wat.js +49 -2
  57. package/src/cli-core.js +276 -73
  58. package/src/compiler.js +162 -25
  59. package/src/dts-parser.js +79 -126
  60. package/src/index.js +88 -121
  61. package/src/lexer.js +80 -29
  62. package/src/lower/boxing.js +4 -6
  63. package/src/lower/captures.js +12 -23
  64. package/src/lower/escape.js +4 -9
  65. package/src/lower/functions.js +277 -5
  66. package/src/lower/globals.js +7 -15
  67. package/src/lower/index.js +5 -2
  68. package/src/lower/ownership.js +35 -19
  69. package/src/lower/range.js +2 -5
  70. package/src/lower/walk.js +25 -0
  71. package/src/minifier.js +20 -68
  72. package/src/parser/declarations.js +3 -6
  73. package/src/parser/expressions.js +3 -8
  74. package/src/parser/index.js +18 -3
  75. package/src/parser/statements.js +25 -38
  76. package/src/parser/types.js +1 -2
  77. package/src/resolver.js +3 -27
  78. package/src/templ-lexer.js +29 -63
  79. package/src/templ-parser.js +22 -45
  80. package/src/test-runner.js +20 -0
  81. package/src/typechecker/assignability.js +123 -14
  82. package/src/typechecker/expressions.js +244 -4
  83. package/src/typechecker/index.js +27 -1
  84. package/src/typechecker/resolve.js +71 -12
  85. package/src/typechecker/statements.js +0 -7
  86. package/src/typechecker/stdlib/core.js +292 -103
  87. package/src/typechecker/stdlib/extended.js +471 -4
  88. package/src/typechecker/stdlib/shared.js +53 -0
  89. package/src/typechecker/stdlib.js +2 -0
  90. package/src/typechecker/types.js +545 -8
  91. 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(...b))`;
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 s = ${__bs}(b), os = ${__bs}(o), ns = ${__bs}(n); if (cnt < 0) return ${__sb}(s.replaceAll(os, ns)); for (let i = 0; i < cnt; i++) s = s.replace(os, ns); return ${__sb}(s); })(${a[0]}, ${a[1]}, ${a[2]}, ${a[3]})`,
20
- ToUpper: (a) => `${__sb}(${__bs}(${a[0]}).toUpperCase())`,
21
- ToLower: (a) => `${__sb}(${__bs}(${a[0]}).toLowerCase())`,
22
- TrimSpace: (a) => `${__sb}(${__bs}(${a[0]}).trim())`,
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
- `${__sb}(${__bs}(${a[0]}).replace(new RegExp(\`^[\${${a[1]}}]+|[\${${a[1]}}]+$\`, "g"), ""))`,
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 ArrayBuffer.isView(b) ? new Uint8Array(r) : r; })(${a[0]}, ${a[1]}, ${a[2]})`,
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 i = 0; while (i < b.length && c.includes(String.fromCharCode(b[i]))) i++; return b.slice(i); })(${a[0]}, ${a[1]})`,
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) => { let i = b.length; while (i > 0 && c.includes(String.fromCharCode(b[i - 1]))) i--; return b.slice(0, i); })(${a[0]}, ${a[1]})`,
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 = b.length; while (l < r && f(b[l])) l++; while (r > l && f(b[r - 1])) r--; return b.slice(l, r); })(${a[0]}, ${a[1]})`,
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 = String.fromCharCode(...b).trim(); return s === '' ? [] : s.split(/\\s+/).map(w => [...w].map(c => c.charCodeAt(0))); })(${a[0]})`,
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(), [], false]; })(${a[0]}, ${a[1]})`,
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
- `[...(${a[1]})].some(c => (${a[0]}).includes(c.charCodeAt(0)))`,
51
- ContainsRune: (a) => `(${a[0]}).includes(${a[1]})`,
52
- Map: (a) => `(${a[1]}).map(v => (${a[0]})(v))`,
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) => { if (n === 0) return []; if (n < 0) return ((b, sep) => { const r = []; let i = 0; while (i <= b.length) { const j = b.findIndex((_, k) => k >= i && sep.every((v, l) => b[k + l] === sep[l])); if (j < 0 || j >= b.length) break; r.push(b.slice(i, j)); i = j + sep.length; } r.push(b.slice(i)); return r; })(b, sep); const r = []; let i = 0; for (let c = 1; c < n; c++) { const j = b.findIndex((_, k) => k >= i && sep.every((v, l) => b[k + l] === sep[l])); if (j < 0) break; r.push(b.slice(i, j)); i = j + sep.length; } r.push(b.slice(i)); return r; })(${a[0]}, ${a[1]}, ${a[2]})`,
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: ${a[0]}, _pos: 0, Read(p) { 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, n === 0 ? "EOF" : null]; }, Len() { return this._src.length - this._pos; }, Reset(b) { this._src = b; this._pos = 0; }}`,
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._usesError = true;
10
+ this.useHelper("error");
11
11
  return `__error(${args[0]})`;
12
12
  }
13
13
  if (fn === "Is") {
14
- this._usesErrorIs = true;
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 t = tokens[i]; const p = ptrs[i]; ` +
8
- `if (typeof p.value === "number") p.value = Number(t); ` +
9
- `else if (typeof p.value === "boolean") p.value = t === "true"; ` +
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.map((e) => this.genExpr(e)).join(", ");
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._usesSprintf = true;
32
+ this.useHelper("sprintf");
19
33
  return `__sprintf(${fmtArgs})`;
20
34
  case "Errorf": {
21
- this._usesSprintf = true;
22
- this._usesError = true;
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._usesSprintf = true;
33
- return `process?.stdout?.write(__sprintf(${fmtArgs}))`;
48
+ this.useHelper("sprintf");
49
+ return this._genStdoutWrite(this._genPrintOperands(expr, "", ""));
34
50
  case "Println":
35
- this._usesSprintf = true;
36
- return `console.log(__sprintf(${fmtArgs}))`;
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 `((str, _fmt, ...ptrs) => { const tokens = str.trim().split(/\\s+/).filter(Boolean); ${_SSCAN_LOOP} return [n, n < ptrs.length ? "input does not match format" : null]; })(${strArg}, ${fmtArg}, ${restArgs})`;
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._usesSprintf = true;
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.genExpr(e)).join(", ");
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 `(${base}._buf += ${sprintfCall})`;
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)=>{ __b._buf.push(...new TextEncoder().encode(__s)); })(${base}, ${sprintfCall})`;
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 `${w}.WriteString(${sprintfCall})`;
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 `${s}.replace(/&#39;/g,"'").replace(/&#34;/g,'"').replace(/&gt;/g,">").replace(/&lt;/g,"<").replace(/&amp;/g,"&")`;
15
+ return `(${s}).replace(/&(?:quot|apos|#39|#34|gt|lt|amp|#(?:[0-9]+|[xX][0-9a-fA-F]+));/g, m => { switch (m) { case "&quot;": case "&#34;": return '"'; case "&apos;": case "&#39;": return "'"; case "&gt;": return ">"; case "&lt;": return "<"; case "&amp;": 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) => { b._buf.push(...new TextEncoder().encode(s)); return [s.length, null]; })(${base}, ${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 [w.WriteString(s), null]; if (typeof w._buf === "string") { w._buf += s; return [s.length, null]; } if (Array.isArray(w._buf)) { w._buf.push(...new TextEncoder().encode(s)); return [s.length, null]; } return [0, "io.WriteString: unsupported writer"]; })(${w}, ${s})`;
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; if (typeof w._src === "string") { const s = w._src.slice(w._pos); w._pos = w._src.length; return [[...s].map(c => c.charCodeAt(0)), null]; } if (Array.isArray(w._src)) { const b = w._src.slice(w._pos); w._pos = w._src.length; return [b, null]; } const chunks = []; const buf = new Array(4096); let err = null; while (!err) { const [n, e] = w.Read(buf); if (n > 0) chunks.push(...buf.slice(0, n)); err = e; } return [chunks, err === "EOF" ? null : err]; })(${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;
@@ -6,7 +6,7 @@
6
6
  export const mapsMethods = {
7
7
  _genMaps(fn, a) {
8
8
  if (fn === "Equal") {
9
- this._usesEqual = true;
9
+ this.useHelper("equal");
10
10
  const [a1, b1] = a();
11
11
  return `__equal(${a1}, ${b1})`;
12
12
  }
@@ -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]) => `(${x} - Math.round(${x} / ${y}) * ${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>} */