gofront 1.6.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/package.json +1 -1
  2. package/src/backend/js/expressions.js +238 -109
  3. package/src/backend/js/index.js +38 -1
  4. package/src/backend/js/runtime.js +953 -53
  5. package/src/backend/js/statements.js +55 -67
  6. package/src/backend/js/stdlib/base64.js +12 -0
  7. package/src/backend/js/stdlib/binary.js +102 -0
  8. package/src/backend/js/stdlib/bits.js +15 -1
  9. package/src/backend/js/stdlib/builder.js +28 -9
  10. package/src/backend/js/stdlib/bytes.js +75 -18
  11. package/src/backend/js/stdlib/errors.js +20 -1
  12. package/src/backend/js/stdlib/fmt.js +70 -13
  13. package/src/backend/js/stdlib/hex.js +17 -0
  14. package/src/backend/js/stdlib/html.js +1 -1
  15. package/src/backend/js/stdlib/index.js +16 -0
  16. package/src/backend/js/stdlib/io.js +105 -3
  17. package/src/backend/js/stdlib/math.js +13 -1
  18. package/src/backend/js/stdlib/path.js +18 -4
  19. package/src/backend/js/stdlib/rand.js +10 -5
  20. package/src/backend/js/stdlib/sha256.js +12 -0
  21. package/src/backend/js/stdlib/slices.js +52 -26
  22. package/src/backend/js/stdlib/strconv.js +21 -5
  23. package/src/backend/js/stdlib/strings.js +148 -15
  24. package/src/backend/js/stdlib/sync.js +13 -0
  25. package/src/backend/js/stdlib/time.js +90 -19
  26. package/src/backend/js/stdlib/unicode.js +2 -2
  27. package/src/backend/wasm/boundary.js +1207 -41
  28. package/src/backend/wasm/const-fold.js +205 -0
  29. package/src/backend/wasm/emit-builtins.js +203 -76
  30. package/src/backend/wasm/emit-exprs.js +464 -276
  31. package/src/backend/wasm/emit-maps.js +144 -8
  32. package/src/backend/wasm/emit-stdlib.js +12 -3005
  33. package/src/backend/wasm/emit-stmts.js +264 -270
  34. package/src/backend/wasm/emit.js +115 -87
  35. package/src/backend/wasm/encode.js +55 -29
  36. package/src/backend/wasm/index.js +1001 -32
  37. package/src/backend/wasm/optimize.js +13 -4
  38. package/src/backend/wasm/stdlib/bytes.js +5039 -0
  39. package/src/backend/wasm/stdlib/core.js +8903 -0
  40. package/src/backend/wasm/stdlib/index.js +40 -0
  41. package/src/backend/wasm/stdlib/io.js +2161 -0
  42. package/src/backend/wasm/stdlib/packages.js +2400 -0
  43. package/src/backend/wasm/stdlib/pure.js +720 -0
  44. package/src/backend/wasm/stdlib/time.js +1200 -0
  45. package/src/backend/wasm/types.js +153 -1
  46. package/src/cli-core.js +1 -1
  47. package/src/compiler.js +18 -4
  48. package/src/dts-parser.js +79 -126
  49. package/src/index.js +2 -6
  50. package/src/lexer.js +80 -29
  51. package/src/lower/boxing.js +1 -2
  52. package/src/lower/captures.js +2 -6
  53. package/src/lower/ownership.js +30 -9
  54. package/src/minifier.js +20 -68
  55. package/src/parser/declarations.js +3 -6
  56. package/src/parser/expressions.js +3 -8
  57. package/src/parser/index.js +18 -3
  58. package/src/parser/statements.js +25 -38
  59. package/src/parser/types.js +1 -2
  60. package/src/resolver.js +2 -27
  61. package/src/templ-lexer.js +29 -63
  62. package/src/templ-parser.js +22 -45
  63. package/src/typechecker/assignability.js +81 -13
  64. package/src/typechecker/expressions.js +102 -2
  65. package/src/typechecker/resolve.js +36 -6
  66. package/src/typechecker/stdlib/core.js +280 -89
  67. package/src/typechecker/stdlib/extended.js +453 -1
  68. package/src/typechecker/types.js +344 -6
@@ -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 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
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 `((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
+ );
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.genExpr(e)).join(", ");
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 `(${base}._buf += ${sprintfCall})`;
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)=>{ __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})`;
93
150
  }
94
151
  // Generic io.Writer fallback — call .WriteString if available
95
152
  const w = this.genExpr(writerArg);
96
- return `${w}.WriteString(${sprintfCall})`;
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.genExpr(e)).join(", ");
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 `${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,11 +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";
18
22
  import { sharedMethods } from "./shared.js";
19
23
  import { slicesMethods } from "./slices.js";
20
24
  import { sortMethods } from "./sort.js";
21
25
  import { strconvMethods } from "./strconv.js";
22
26
  import { stringsMethods } from "./strings.js";
27
+ import { syncMethods } from "./sync.js";
23
28
  import { testingMethods } from "./testing.js";
24
29
  import { timeMethods } from "./time.js";
25
30
  import { unicodeMethods } from "./unicode.js";
@@ -49,8 +54,14 @@ const STDLIB_METHOD_MAP = {
49
54
  rand: "_genRand",
50
55
  utf8: "_genUtf8",
51
56
  path: "_genPath",
57
+ filepath: "_genPath",
52
58
  testing: "_genTesting",
53
59
  shared: "_genShared",
60
+ sync: "_genSync",
61
+ sha256: "_genSha256",
62
+ binary: "_genBinary",
63
+ hex: "_genHex",
64
+ base64: "_genBase64",
54
65
  };
55
66
 
56
67
  const dispatchMethods = {
@@ -103,5 +114,10 @@ export const stdlibGenMethods = {
103
114
  ...unicodeMethods,
104
115
  ...utf8Methods,
105
116
  ...testingMethods,
117
+ ...syncMethods,
118
+ ...sha256Methods,
119
+ ...binaryMethods,
120
+ ...hexMethods,
121
+ ...base64Methods,
106
122
  ...dispatchMethods,
107
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;
@@ -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>} */
@@ -6,23 +6,37 @@ const PATH_DISPATCH = {
6
6
  Base: (a) =>
7
7
  `((p) => { if (!p) return "."; const stripped = p.replace(/\\/+$/, ""); if (!stripped) return "/"; const i = stripped.lastIndexOf("/"); return i < 0 ? stripped : stripped.slice(i + 1) || "/"; })(${a[0]})`,
8
8
  Dir: (a) =>
9
- `((p) => { const i = p.lastIndexOf("/"); if (i < 0) return "."; if (i === 0) return "/"; return p.slice(0, i); })(${a[0]})`,
9
+ `((p) => { const i = p.lastIndexOf("/"); if (i < 0) return "."; const res = p.slice(0, i); return res === "" ? "/" : __pathClean(res); })(${a[0]})`,
10
10
  Ext: (a) =>
11
11
  `((p) => { const b = p.slice(p.lastIndexOf("/") + 1); const i = b.lastIndexOf("."); return i <= 0 ? "" : b.slice(i); })(${a[0]})`,
12
12
  IsAbs: (a) => `(${a[0]}).startsWith("/")`,
13
13
  Split: (a) =>
14
14
  `((p) => { const i = p.lastIndexOf("/"); return i < 0 ? ["", p] : [p.slice(0, i + 1), p.slice(i + 1)]; })(${a[0]})`,
15
15
  Match: (a) =>
16
- `((pat, name) => { try { const sp=/[.+^$()|[\\]\\\\]/g; const re = new RegExp("^" + pat.replace(sp, "\\\\$&").replace(/\\*/g, "[^/]*").replace(/\\?/g, "[^/]") + "$"); return [re.test(name), null]; } catch(e) { return [false, "syntax error in pattern"]; } })(${a[0]}, ${a[1]})`,
16
+ `((pat, name) => { const [m, err] = __pathMatch(pat, name); return [m, err ? __path_err_bad_pattern : null]; })(${a[0]}, ${a[1]})`,
17
17
  };
18
18
 
19
19
  /** @type {ThisType<CodeGen>} */
20
20
  export const pathMethods = {
21
21
  _genPath(fn, a, expr) {
22
+ if (fn === "Match") {
23
+ this.useHelper("error");
24
+ this.useHelper("pathError");
25
+ this.useHelper("pathClean");
26
+ }
27
+ if (fn === "Dir") {
28
+ this.useHelper("pathClean");
29
+ }
22
30
  if (fn === "Join") {
23
31
  this.useHelper("pathClean");
24
- const allArgs = expr.args.map((e) => this.genExpr(e)).join(", ");
25
- return `__pathClean([${allArgs}].filter(x => x !== "").join("/"))`;
32
+ const allArgs = expr.args
33
+ .map((e) =>
34
+ e._spread || expr.ellipsis
35
+ ? `...(${this.genExpr(e)})`
36
+ : this.genExpr(e),
37
+ )
38
+ .join(", ");
39
+ return `((arr) => arr.length === 0 ? "" : __pathClean(arr.join("/")))([${allArgs}].filter(x => x !== ""))`;
26
40
  }
27
41
  if (fn === "Clean") {
28
42
  this.useHelper("pathClean");
@@ -3,9 +3,12 @@
3
3
  /** @typedef {import('../index.js').CodeGen} CodeGen */
4
4
 
5
5
  const RAND_DISPATCH = {
6
- Intn: (a) => `Math.floor(Math.random() * ${a[0]})`,
7
- Int63n: (a) => `Math.floor(Math.random() * ${a[0]})`,
8
- Int31n: (a) => `Math.floor(Math.random() * ${a[0]})`,
6
+ Intn: (a) =>
7
+ `((n) => { if (n <= 0) throw new Error("invalid argument to Intn"); return Math.floor(Math.random() * n); })(${a[0]})`,
8
+ Int63n: (a) =>
9
+ `((n) => { if (n <= 0) throw new Error("invalid argument to Int63n"); return Math.floor(Math.random() * n); })(${a[0]})`,
10
+ Int31n: (a) =>
11
+ `((n) => { if (n <= 0) throw new Error("invalid argument to Int31n"); return Math.floor(Math.random() * n); })(${a[0]})`,
9
12
  Float64: () => "Math.random()",
10
13
  Float32: () => "Math.random()",
11
14
  Int: () => "Math.floor(Math.random() * 2147483647)",
@@ -13,14 +16,16 @@ const RAND_DISPATCH = {
13
16
  Int63: () => "Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)",
14
17
  Seed: () => "(void 0)",
15
18
  Shuffle: (a) =>
16
- `((n, f) => { for (let i = n - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); f(i, j); } })(${a[0]}, ${a[1]})`,
19
+ `((n, f) => { if (n < 0) throw new Error("invalid argument to Shuffle"); for (let i = n - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); f(i, j); } })(${a[0]}, ${a[1]})`,
17
20
  Perm: (a) =>
18
- `((n) => { const a = Array.from({length: n}, (_, i) => i); for (let i = n - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [a[i], a[j]] = [a[j], a[i]]; } return a; })(${a[0]})`,
21
+ `((n) => { if (n < 0) throw new Error("invalid argument to Perm"); const a = Array.from({length: n}, (_, i) => i); for (let i = n - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [a[i], a[j]] = [a[j], a[i]]; } return a; })(${a[0]})`,
22
+ Read: (a) => `__crypto_rand_read(${a[0]})`,
19
23
  };
20
24
 
21
25
  /** @type {ThisType<CodeGen>} */
22
26
  export const randMethods = {
23
27
  _genRand(fn, a) {
28
+ if (fn === "Read") this.useHelper("cryptoRand");
24
29
  const gen = RAND_DISPATCH[fn];
25
30
  return gen ? gen(a()) : undefined;
26
31
  },
@@ -0,0 +1,12 @@
1
+ // src/backend/js/stdlib/sha256.js
2
+ // CodeGen for Go crypto/sha256 package.
3
+
4
+ export const sha256Methods = {
5
+ _genSha256(fn, a) {
6
+ this.useHelper("sha256");
7
+ const args = a();
8
+ if (fn === "Sum256") return `__sha256.Sum256(${args[0]})`;
9
+ if (fn === "New") return "__sha256.New()";
10
+ return undefined;
11
+ },
12
+ };
@@ -1,51 +1,77 @@
1
- // CodeGen for Go `slices` package.
1
+ import { isTypedArraySlice } from "../../../typechecker/types.js";
2
2
 
3
3
  /** @typedef {import('../index.js').CodeGen} CodeGen */
4
4
 
5
5
  const SLICES_DISPATCH = {
6
6
  Contains: (a) => `${a[0]}.includes(${a[1]})`,
7
+ ContainsFunc: (a) =>
8
+ `((s, f) => { s = s || []; for (let i = 0; i < s.length; i++) { if (f(s[i])) return true; } return false; })(${a[0]}, ${a[1]})`,
7
9
  Index: (a) => `${a[0]}.indexOf(${a[1]})`,
10
+ IndexFunc: (a) =>
11
+ `((s, f) => { s = s || []; for (let i = 0; i < s.length; i++) { if (f(s[i])) return i; } return -1; })(${a[0]}, ${a[1]})`,
12
+ BinarySearch: (a) =>
13
+ `((s, target) => { s = s || []; let i = 0, j = s.length; while (i < j) { const h = (i + j) >>> 1; if (s[h] < target) i = h + 1; else j = h; } return [i, i < s.length && s[i] === target]; })(${a[0]}, ${a[1]})`,
14
+ BinarySearchFunc: (a) =>
15
+ `((s, target, cmp) => { s = s || []; let i = 0, j = s.length; while (i < j) { const h = (i + j) >>> 1; if (cmp(s[h], target) < 0) i = h + 1; else j = h; } return [i, i < s.length && cmp(s[i], target) === 0]; })(${a[0]}, ${a[1]}, ${a[2]})`,
8
16
  Compare: (a) =>
9
- `((a, b) => { for (let i = 0; i < a.length && i < b.length; i++) { if (a[i] < b[i]) return -1; if (a[i] > b[i]) return 1; } return a.length - b.length; })(${a[0]}, ${a[1]})`,
10
- Sort: (a) => `${a[0]}.sort((a, b) => a < b ? -1 : a > b ? 1 : 0)`,
11
- SortFunc: (a) => `${a[0]}.sort(${a[1]})`,
12
- SortStableFunc: (a) => `${a[0]}.sort(${a[1]})`,
17
+ `((a, b) => { a = a || []; b = b || []; for (let i = 0; i < a.length && i < b.length; i++) { const x = a[i], y = b[i]; const xN = typeof x === "number" && isNaN(x), yN = typeof y === "number" && isNaN(y); if (xN && yN) continue; if (xN) return -1; if (yN) return 1; if (x < y) return -1; if (x > y) return 1; } return a.length < b.length ? -1 : a.length > b.length ? 1 : 0; })(${a[0]}, ${a[1]})`,
18
+ Sort: (a) =>
19
+ `((s) => s ? s.sort((a, b) => a < b ? -1 : a > b ? 1 : 0) : null)(${a[0]})`,
20
+ SortFunc: (a) => `((s, f) => s ? s.sort(f) : null)(${a[0]}, ${a[1]})`,
21
+ SortStableFunc: (a) => `((s, f) => s ? s.sort(f) : null)(${a[0]}, ${a[1]})`,
13
22
  IsSorted: (a) =>
14
- `((s) => { for (let i = 1; i < s.length; i++) { if (s[i] < s[i-1]) return false; } return true; })(${a[0]})`,
23
+ `((s) => { s = s || []; for (let i = 0; i < s.length; i++) { if (typeof s[i] === "number" && isNaN(s[i])) return false; if (i > 0 && s[i] < s[i-1]) return false; } return true; })(${a[0]})`,
15
24
  IsSortedFunc: (a) =>
16
- `((s, f) => { for (let i = 1; i < s.length; i++) { if (f(s[i], s[i-1]) < 0) return false; } return true; })(${a[0]}, ${a[1]})`,
17
- Reverse: (a) => `${a[0]}.reverse()`,
18
- Max: (a) => `Math.max(...${a[0]})`,
19
- Min: (a) => `Math.min(...${a[0]})`,
25
+ `((s, f) => { s = s || []; for (let i = 1; i < s.length; i++) { if (f(s[i], s[i-1]) < 0) return false; } return true; })(${a[0]}, ${a[1]})`,
26
+ Reverse: (a) => `((s) => s ? s.reverse() : null)(${a[0]})`,
27
+ Max: (a) =>
28
+ `((s) => { if (!s || s.length === 0) throw new Error("slices.Max: empty list"); let m = s[0]; for (let i = 1; i < s.length; i++) { const x = s[i]; if ((typeof x === "number" && isNaN(x)) || x > m || (x === 0 && m === 0 && Object.is(m, -0) && !Object.is(x, -0))) m = x; } return m; })(${a[0]})`,
29
+ Min: (a) =>
30
+ `((s) => { if (!s || s.length === 0) throw new Error("slices.Min: empty list"); let m = s[0]; for (let i = 1; i < s.length; i++) { const x = s[i]; if ((typeof x === "number" && isNaN(x)) || x < m || (x === 0 && m === 0 && Object.is(x, -0))) m = x; } return m; })(${a[0]})`,
20
31
  MaxFunc: (a) =>
21
- `((s, f) => s.reduce((m, x) => f(x, m) > 0 ? x : m))(${a[0]}, ${a[1]})`,
32
+ `((s, f) => { if (!s || s.length === 0) throw new Error("slices.MaxFunc: empty list"); return s.reduce((m, x) => f(x, m) > 0 ? x : m); })(${a[0]}, ${a[1]})`,
22
33
  MinFunc: (a) =>
23
- `((s, f) => s.reduce((m, x) => f(x, m) < 0 ? x : m))(${a[0]}, ${a[1]})`,
24
- Clone: (a) => `${a[0]}.slice()`,
34
+ `((s, f) => { if (!s || s.length === 0) throw new Error("slices.MinFunc: empty list"); return s.reduce((m, x) => f(x, m) < 0 ? x : m); })(${a[0]}, ${a[1]})`,
35
+ Clone: (a) => `((s) => s ? s.slice() : null)(${a[0]})`,
25
36
  Compact: (a) =>
26
- `((s) => s.filter((v, i) => i === 0 || v !== s[i-1]))(${a[0]})`,
37
+ `((s) => { if (!s || s.length === 0) return s; let k = 1; for (let i = 1; i < s.length; i++) { if (s[i] !== s[k - 1]) s[k++] = s[i]; } return ArrayBuffer.isView(s) ? s.subarray(0, k) : (s.length = k, s); })(${a[0]})`,
27
38
  CompactFunc: (a) =>
28
- `((s, f) => s.filter((v, i) => i === 0 || !f(v, s[i-1])))(${a[0]}, ${a[1]})`,
29
- Concat: (a) => `[].concat(${a.join(", ")})`,
30
- Delete: (a) => `[...${a[0]}.slice(0, ${a[1]}), ...${a[0]}.slice(${a[2]})]`,
31
- DeleteFunc: (a) => `${a[0]}.filter((v) => !${a[1]}(v))`,
32
- Insert: (a) =>
33
- `[...${a[0]}.slice(0, ${a[1]}), ${a.slice(2).join(", ")}, ...${a[0]}.slice(${a[1]})]`,
34
- Replace: (a) =>
35
- `[...${a[0]}.slice(0, ${a[1]}), ${a.slice(3).join(", ")}, ...${a[0]}.slice(${a[2]})]`,
36
- Grow: (a) => `${a[0]}.slice()`,
37
- Clip: (a) => `${a[0]}.slice()`,
39
+ `((s, f) => { if (!s || s.length === 0) return s; let k = 1; for (let i = 1; i < s.length; i++) { if (!f(s[i], s[k - 1])) s[k++] = s[i]; } return ArrayBuffer.isView(s) ? s.subarray(0, k) : (s.length = k, s); })(${a[0]}, ${a[1]})`,
40
+ Concat: (a) =>
41
+ a.length === 0
42
+ ? "null"
43
+ : `((...slices) => { const nonNull = slices.filter(Boolean); if (nonNull.length === 0) return slices[0] === null ? null : []; if (ArrayBuffer.isView(nonNull[0])) { const totalLen = nonNull.reduce((sum, s) => sum + s.length, 0); const out = new nonNull[0].constructor(totalLen); let off = 0; for (const s of nonNull) { out.set(s, off); off += s.length; } return out; } return [].concat(...slices.map(s => s ? (ArrayBuffer.isView(s) ? Array.from(s) : s) : [])); })(${a.map((x) => `(${x})`).join(", ")})`,
44
+ Delete: (a) =>
45
+ `((s, i, j) => { if (!s && i === 0 && j === 0) return s; s = s || []; if (i < 0 || j < i || j > s.length) throw new Error("runtime error: slice bounds out of range"); if (ArrayBuffer.isView(s)) { s.copyWithin(i, j); return s.subarray(0, s.length - (j - i)); } s.splice(i, j - i); return s; })(${a[0]}, ${a[1]}, ${a[2]})`,
46
+ DeleteFunc: (a) =>
47
+ `((s, f) => { if (!s || s.length === 0) return s; let k = 0; for (let i = 0; i < s.length; i++) { if (!f(s[i])) s[k++] = s[i]; } return ArrayBuffer.isView(s) ? s.subarray(0, k) : (s.length = k, s); })(${a[0]}, ${a[1]})`,
48
+ Insert: (a, isTyped) => {
49
+ const items = a.slice(2);
50
+ const nilInit = isTyped ? "new Uint8Array(0)" : "[]";
51
+ return `((s, i, ...v) => { if (!s && i === 0) s = ${nilInit}; if (!s || i < 0 || i > s.length) throw new Error("runtime error: slice bounds out of range"); if (ArrayBuffer.isView(s)) { const res = new s.constructor(s.length + v.length); res.set(s.subarray(0, i), 0); res.set(v, i); res.set(s.subarray(i), i + v.length); return res; } s.splice(i, 0, ...v); return s; })(${a[0]}, ${a[1]}${items.length ? `, ${items.join(", ")}` : ""})`;
52
+ },
53
+ Replace: (a, isTyped) => {
54
+ const items = a.slice(3);
55
+ const nilInit = isTyped ? "new Uint8Array(0)" : "[]";
56
+ return `((s, i, j, ...v) => { if (!s && i === 0 && j === 0) s = ${nilInit}; if (!s || i < 0 || j < i || j > s.length) throw new Error("runtime error: slice bounds out of range"); if (ArrayBuffer.isView(s)) { const res = new s.constructor(s.length - (j - i) + v.length); res.set(s.subarray(0, i), 0); res.set(v, i); res.set(s.subarray(j), i + v.length); return res; } s.splice(i, j - i, ...v); return s; })(${a[0]}, ${a[1]}, ${a[2]}${items.length ? `, ${items.join(", ")}` : ""})`;
57
+ },
58
+ Grow: (a, isTyped) => {
59
+ const nilInit = isTyped ? "new Uint8Array(0)" : "[]";
60
+ return `((s, n) => { if (n < 0) throw new Error("runtime error: makeslice: len out of range"); if (!s) return ${nilInit}; return s.slice(); })(${a[0]}, ${a[1]})`;
61
+ },
62
+ Clip: (a) => `((s) => s ? s.slice() : null)(${a[0]})`,
38
63
  };
39
64
 
40
65
  /** @type {ThisType<CodeGen>} */
41
66
  export const slicesMethods = {
42
- _genSlices(fn, a) {
67
+ _genSlices(fn, a, expr) {
43
68
  if (fn === "Equal") {
44
69
  this.useHelper("equal");
45
70
  const [a1, b1] = a();
46
71
  return `__equal(${a1}, ${b1})`;
47
72
  }
73
+ const isTyped = isTypedArraySlice(expr?.args?.[0]?._type);
48
74
  const gen = SLICES_DISPATCH[fn];
49
- return gen ? gen(a()) : undefined;
75
+ return gen ? gen(a(), isTyped) : undefined;
50
76
  },
51
77
  };