gofront 1.6.1 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/README.md +45 -49
  2. package/package.json +12 -8
  3. package/src/backend/js/expressions.js +1627 -148
  4. package/src/backend/js/fmt-runtime.js +573 -0
  5. package/src/backend/js/index.js +508 -102
  6. package/src/backend/js/runtime.js +1997 -106
  7. package/src/backend/js/statements.js +931 -87
  8. package/src/backend/js/stdlib/bits.js +87 -14
  9. package/src/backend/js/stdlib/builder.js +41 -6
  10. package/src/backend/js/stdlib/bytes.js +253 -7
  11. package/src/backend/js/stdlib/errors.js +7 -1
  12. package/src/backend/js/stdlib/fmt.js +349 -10
  13. package/src/backend/js/stdlib/index.js +19 -2
  14. package/src/backend/js/stdlib/json.js +1167 -0
  15. package/src/backend/js/stdlib/maps.js +0 -8
  16. package/src/backend/js/stdlib/math.js +17 -1
  17. package/src/backend/js/stdlib/simd.js +34 -0
  18. package/src/backend/js/stdlib/slices.js +36 -6
  19. package/src/backend/js/stdlib/strconv.js +10 -5
  20. package/src/backend/js/stdlib/strings.js +83 -4
  21. package/src/backend/js/stdlib/testing.js +7 -0
  22. package/src/backend/js/stdlib/time.js +79 -55
  23. package/src/backend/js/stdlib/unicode.js +1 -1
  24. package/src/backend/js/stdlib/utf8.js +1 -1
  25. package/src/backend/js/templ.js +38 -76
  26. package/src/backend/js/type-info.js +272 -0
  27. package/src/backend/shared/fmt-types.js +188 -0
  28. package/src/backend/wasm/boundary.js +446 -72
  29. package/src/backend/wasm/emit-builtins.js +320 -13
  30. package/src/backend/wasm/emit-exprs.js +1404 -199
  31. package/src/backend/wasm/emit-maps.js +61 -13
  32. package/src/backend/wasm/emit-stmts.js +1359 -164
  33. package/src/backend/wasm/emit.js +518 -74
  34. package/src/backend/wasm/encode.js +128 -13
  35. package/src/backend/wasm/globals.js +452 -0
  36. package/src/backend/wasm/index.js +194 -2489
  37. package/src/backend/wasm/method-expr.js +381 -0
  38. package/src/backend/wasm/module-emitter.js +2240 -0
  39. package/src/backend/wasm/monomorph.js +62 -4
  40. package/src/backend/wasm/optimize.js +4 -2
  41. package/src/backend/wasm/prescan.js +397 -0
  42. package/src/backend/wasm/stdlib/bytes.js +1804 -127
  43. package/src/backend/wasm/stdlib/core.js +1574 -199
  44. package/src/backend/wasm/stdlib/index.js +3 -5
  45. package/src/backend/wasm/stdlib/io.js +1567 -150
  46. package/src/backend/wasm/stdlib/packages.js +2 -0
  47. package/src/backend/wasm/stdlib/simd.js +499 -0
  48. package/src/backend/wasm/stdlib/time.js +1041 -12
  49. package/src/backend/wasm/types.js +221 -15
  50. package/src/backend/wasm/variadic.js +93 -0
  51. package/src/backend/wasm/wat.js +84 -20
  52. package/src/{cli-core.js → cli/cli-core.js} +236 -10
  53. package/src/{test-runner.js → cli/test-runner.js} +332 -39
  54. package/src/{vendor.js → cli/vendor.js} +89 -15
  55. package/src/compiler.js +107 -269
  56. package/src/dts-parser.js +71 -14
  57. package/src/index.js +15 -169
  58. package/src/{lexer.js → lexer/lexer.js} +102 -55
  59. package/src/{tokens.js → lexer/tokens.js} +1 -0
  60. package/src/link/sourcemap.js +97 -0
  61. package/src/link/stdlib.js +515 -0
  62. package/src/link/wasm.js +294 -0
  63. package/src/lower/bounds.js +394 -0
  64. package/src/lower/boxing.js +1 -6
  65. package/src/lower/captures.js +176 -32
  66. package/src/lower/embedding.js +2 -1
  67. package/src/lower/index.js +26 -18
  68. package/src/lower/json-codecs.js +1398 -0
  69. package/src/lower/ownership.js +22 -1
  70. package/src/lower/range.js +86 -1
  71. package/src/lower/reachability.js +132 -0
  72. package/src/parser/declarations.js +58 -13
  73. package/src/parser/expressions.js +29 -7
  74. package/src/parser/index.js +2 -1
  75. package/src/parser/statements.js +37 -22
  76. package/src/parser/struct-tag.js +144 -0
  77. package/src/{templ-parser.js → parser/templ.js} +138 -15
  78. package/src/parser/types.js +130 -13
  79. package/src/resolver.js +22 -1
  80. package/src/typechecker/assignability.js +215 -11
  81. package/src/typechecker/const-fold.js +356 -0
  82. package/src/typechecker/constants.js +256 -0
  83. package/src/typechecker/expressions.js +960 -99
  84. package/src/typechecker/index.js +491 -72
  85. package/src/typechecker/init-order.js +330 -0
  86. package/src/typechecker/resolve.js +596 -52
  87. package/src/typechecker/statements.js +157 -17
  88. package/src/typechecker/stdlib/core.js +333 -55
  89. package/src/typechecker/stdlib/excluded.js +898 -0
  90. package/src/typechecker/stdlib/extended.js +359 -26
  91. package/src/typechecker/{stdlib.js → stdlib/index.js} +6 -4
  92. package/src/typechecker/stdlib/simd.js +123 -0
  93. package/src/typechecker/termination.js +1 -1
  94. package/src/typechecker/types.js +165 -26
  95. package/stdlib/bytes/iter.go +192 -0
  96. package/stdlib/bytes/search.go +240 -0
  97. package/stdlib/bytes/split.go +218 -0
  98. package/stdlib/cmp/cmp.go +65 -0
  99. package/stdlib/encoding/json/errors.go +31 -0
  100. package/stdlib/encoding/json/indent.go +71 -0
  101. package/stdlib/encoding/json/number.go +12 -0
  102. package/stdlib/encoding/json/stream.go +173 -0
  103. package/stdlib/errors/overlay.go +12 -0
  104. package/stdlib/hash/hash.go +53 -0
  105. package/stdlib/internal/jsonrt/dec.go +738 -0
  106. package/stdlib/internal/jsonrt/enc.go +366 -0
  107. package/stdlib/internal/jsonrt/indent.go +135 -0
  108. package/stdlib/internal/jsonrt/number.go +27 -0
  109. package/stdlib/internal/jsonrt/reader.go +73 -0
  110. package/stdlib/internal/jsonrt/scanner.go +649 -0
  111. package/stdlib/io/io.go +346 -0
  112. package/stdlib/iter/iter.go +18 -0
  113. package/stdlib/maps/iter.go +65 -0
  114. package/stdlib/math/extra.go +270 -0
  115. package/stdlib/slices/extra.go +73 -0
  116. package/stdlib/slices/iter.go +113 -0
  117. package/stdlib/sort/sort.go +561 -0
  118. package/stdlib/strconv/quote.go +341 -0
  119. package/stdlib/strings/extra.go +35 -0
  120. package/stdlib/strings/iter.go +122 -0
  121. package/stdlib/sync/extra.go +105 -0
  122. package/stdlib/unicode/unicode.go +112 -0
  123. package/stdlib/unicode/utf8/bytes.go +239 -0
  124. package/src/backend/wasm/const-fold.js +0 -205
  125. package/src/backend/wasm/emit-stdlib.js +0 -13
  126. /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
  127. /package/src/{colors.js → cli/colors.js} +0 -0
  128. /package/src/{dev-server.js → cli/dev-server.js} +0 -0
  129. /package/src/{minifier.js → cli/minifier.js} +0 -0
  130. /package/src/{project-config.js → cli/project-config.js} +0 -0
  131. /package/src/{pwa.js → cli/pwa.js} +0 -0
  132. /package/src/{templ-lexer.js → lexer/templ-lexer.js} +0 -0
@@ -11,14 +11,6 @@ export const mapsMethods = {
11
11
  return `__equal(${a1}, ${b1})`;
12
12
  }
13
13
  switch (fn) {
14
- case "Keys": {
15
- const [m] = a();
16
- return `Object.keys(${m})`;
17
- }
18
- case "Values": {
19
- const [m] = a();
20
- return `Object.values(${m})`;
21
- }
22
14
  case "Clone": {
23
15
  const [m] = a();
24
16
  return `({...${m}})`;
@@ -9,8 +9,10 @@ const MATH1 = {
9
9
  Sqrt: "sqrt",
10
10
  Cbrt: "cbrt",
11
11
  Log: "log",
12
+ Log1p: "log1p",
12
13
  Log2: "log2",
13
14
  Log10: "log10",
15
+ Expm1: "expm1",
14
16
  Sin: "sin",
15
17
  Cos: "cos",
16
18
  Tan: "tan",
@@ -37,7 +39,7 @@ const MATH_EXTRA = {
37
39
  Inf: ([x]) => `(${x} >= 0 ? Infinity : -Infinity)`,
38
40
  IsNaN: ([x]) => `Number.isNaN(${x})`,
39
41
  IsInf: ([x, y]) =>
40
- `(${y} > 0 ? ${x} === Infinity : ${y} < 0 ? ${x} === -Infinity : !Number.isFinite(${x}))`,
42
+ `(${y} > 0 ? ${x} === Infinity : ${y} < 0 ? ${x} === -Infinity : Math.abs(${x}) === Infinity)`,
41
43
  NaN: () => "NaN",
42
44
  Exp2: ([x]) => `Math.pow(2, ${x})`,
43
45
  Signbit: ([x]) => `(${x} < 0 || Object.is(${x}, -0))`,
@@ -46,6 +48,20 @@ const MATH_EXTRA = {
46
48
  Dim: ([x, y]) => `Math.max(${x} - ${y}, 0)`,
47
49
  Remainder: ([x, y]) =>
48
50
  `((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})`,
51
+ Frexp: ([x]) =>
52
+ `((f) => { if (f === 0 || !Number.isFinite(f)) return [f, 0]; const buf = new ArrayBuffer(8); const f64 = new Float64Array(buf); const u32 = new Uint32Array(buf); f64[0] = f; let hi = u32[1]; let exp = (hi >>> 20) & 0x7ff; if (exp === 0) { f64[0] = f * Math.pow(2, 54); hi = u32[1]; exp = ((hi >>> 20) & 0x7ff) - 54; } exp -= 1022; u32[1] = (hi & 0x800fffff) | 0x3fe00000; return [f64[0], exp]; })(${x})`,
53
+ Ldexp: ([frac, exp]) =>
54
+ `((frac, exp) => { if (frac === 0 || !Number.isFinite(frac)) return frac; if (exp > 1023) return frac < 0 ? -Infinity : Infinity; if (exp < -1074) return frac < 0 ? -0 : 0; if (exp >= -1022) return frac * Math.pow(2, exp); return frac * Math.pow(2, exp + 54) * Math.pow(2, -54); })(${frac}, ${exp})`,
55
+ Modf: ([f]) =>
56
+ `((x) => { if (Number.isNaN(x)) return [NaN, NaN]; if (!Number.isFinite(x)) return [x, NaN]; const i = Math.trunc(x); const frac = x === i ? (x < 0 || Object.is(x, -0) ? -0 : 0) : x - i; return [i, frac]; })(${f})`,
57
+ FMA: ([x, y, z]) =>
58
+ `((x, y, z) => { if (Number.isNaN(x) || Number.isNaN(y) || Number.isNaN(z)) return NaN; if ((x === 0 && !Number.isFinite(y)) || (y === 0 && !Number.isFinite(x))) return NaN; const p = x * y; if (!Number.isFinite(p) && !Number.isFinite(z) && ((p > 0 && z < 0) || (p < 0 && z > 0))) return NaN; return p + z; })(${x}, ${y}, ${z})`,
59
+ RoundToEven: ([x]) =>
60
+ `((x) => { if (x === 0 || !Number.isFinite(x)) return x; const t = Math.trunc(x); const f = Math.abs(x - t); if (f < 0.5) return Object.is(t, 0) && (x < 0 || Object.is(x, -0)) ? -0 : t; if (f > 0.5) return x > 0 ? t + 1 : t - 1; const res = t % 2 === 0 ? t : (x > 0 ? t + 1 : t - 1); return Object.is(res, 0) && (x < 0 || Object.is(x, -0)) ? -0 : res; })(${x})`,
61
+ Nextafter: ([x, y]) =>
62
+ `((x, y) => { if (Number.isNaN(x) || Number.isNaN(y)) return NaN; if (x === y) return x; if (x === 0) { const s = Number.MIN_VALUE; return y > 0 ? s : -s; } const buf = new ArrayBuffer(8); const f64 = new Float64Array(buf); const i64 = new BigInt64Array(buf); f64[0] = x; let b = i64[0]; if ((x > 0 && y > x) || (x < 0 && y > x)) b = b + (x > 0 ? 1n : -1n); else b = b + (x > 0 ? -1n : 1n); i64[0] = b; return f64[0]; })(${x}, ${y})`,
63
+ Nextafter32: ([x, y]) =>
64
+ `((x, y) => { if (Number.isNaN(x) || Number.isNaN(y)) return NaN; if (x === y) return x; if (x === 0) { const s = 1.401298464324817e-45; return y > 0 ? s : -s; } const buf = new ArrayBuffer(4); const f32 = new Float32Array(buf); const i32 = new Int32Array(buf); f32[0] = x; let b = i32[0]; if ((x > 0 && y > x) || (x < 0 && y > x)) b = b + (x > 0 ? 1 : -1); else b = b + (x > 0 ? -1 : 1); i32[0] = b; return f32[0]; })(${x}, ${y})`,
49
65
  Float64bits: ([x]) =>
50
66
  `((f) => { const b = new ArrayBuffer(8); new Float64Array(b)[0] = f; return Number(new BigUint64Array(b)[0]); })(${x})`,
51
67
  Float64frombits: ([b]) =>
@@ -0,0 +1,34 @@
1
+ // src/backend/js/stdlib/simd.js
2
+ // CodeGen for the `gofront/simd` package in JS packages.
3
+
4
+ /** @typedef {import('../index.js').CodeGen} CodeGen */
5
+
6
+ /** @type {ThisType<CodeGen>} */
7
+ export const simdMethods = {
8
+ _genSimd(fn, a) {
9
+ this.useHelper("simd");
10
+ const args = a();
11
+ switch (fn) {
12
+ case "Splat":
13
+ return `__simd_splat(${args[0]})`;
14
+ case "NewF32x4":
15
+ return `__simd_f32x4(${args[0]}, ${args[1]}, ${args[2]}, ${args[3]})`;
16
+ case "Select":
17
+ return `__simd_select(${args[0]}, ${args[1]}, ${args[2]})`;
18
+ case "Shuffle":
19
+ return `__simd_shuffle(${args.join(", ")})`;
20
+ case "LoadF32x4":
21
+ return `__simd_load(${args[0]}, ${args[1]})`;
22
+ case "StoreF32x4":
23
+ return `__simd_store(${args[0]}, ${args[1]}, ${args[2]})`;
24
+ case "LoadF32x4Slice":
25
+ return `__simd_load_slice(${args[0]}, ${args[1]})`;
26
+ case "StoreF32x4Slice":
27
+ return `__simd_store_slice(${args[0]}, ${args[1]}, ${args[2]})`;
28
+ case "Pad4":
29
+ return `(Math.floor((${args[0]} + 3) / 4) * 4)`;
30
+ default:
31
+ return undefined;
32
+ }
33
+ },
34
+ };
@@ -34,26 +34,26 @@ const SLICES_DISPATCH = {
34
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
35
  Clone: (a) => `((s) => s ? s.slice() : null)(${a[0]})`,
36
36
  Compact: (a) =>
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]})`,
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 s[__sv] !== undefined ? __slice(s, 0, k) : ArrayBuffer.isView(s) ? s.subarray(0, k) : (s.length = k, s); })(${a[0]})`,
38
38
  CompactFunc: (a) =>
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]})`,
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 s[__sv] !== undefined ? __slice(s, 0, k) : ArrayBuffer.isView(s) ? s.subarray(0, k) : (s.length = k, s); })(${a[0]}, ${a[1]})`,
40
40
  Concat: (a) =>
41
41
  a.length === 0
42
42
  ? "null"
43
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
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]})`,
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)); } if (s[__sv] !== undefined) { s.copyWithin(i, j); return __slice(s, 0, s.length - (j - i)); } s.splice(i, j - i); return s; })(${a[0]}, ${a[1]}, ${a[2]})`,
46
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]})`,
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 s[__sv] !== undefined ? __slice(s, 0, k) : ArrayBuffer.isView(s) ? s.subarray(0, k) : (s.length = k, s); })(${a[0]}, ${a[1]})`,
48
48
  Insert: (a, isTyped) => {
49
49
  const items = a.slice(2);
50
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(", ")}` : ""})`;
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; } if (s[__sv] !== undefined) s = Array.from(s); s.splice(i, 0, ...v); return s; })(${a[0]}, ${a[1]}${items.length ? `, ${items.join(", ")}` : ""})`;
52
52
  },
53
53
  Replace: (a, isTyped) => {
54
54
  const items = a.slice(3);
55
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(", ")}` : ""})`;
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; } if (s[__sv] !== undefined) s = Array.from(s); s.splice(i, j - i, ...v); return s; })(${a[0]}, ${a[1]}, ${a[2]}${items.length ? `, ${items.join(", ")}` : ""})`;
57
57
  },
58
58
  Grow: (a, isTyped) => {
59
59
  const nilInit = isTyped ? "new Uint8Array(0)" : "[]";
@@ -62,6 +62,15 @@ const SLICES_DISPATCH = {
62
62
  Clip: (a) => `((s) => s ? s.slice() : null)(${a[0]})`,
63
63
  };
64
64
 
65
+ const VIEW_AWARE = new Set([
66
+ "Compact",
67
+ "CompactFunc",
68
+ "Delete",
69
+ "DeleteFunc",
70
+ "Insert",
71
+ "Replace",
72
+ ]);
73
+
65
74
  /** @type {ThisType<CodeGen>} */
66
75
  export const slicesMethods = {
67
76
  _genSlices(fn, a, expr) {
@@ -70,8 +79,29 @@ export const slicesMethods = {
70
79
  const [a1, b1] = a();
71
80
  return `__equal(${a1}, ${b1})`;
72
81
  }
82
+ // Struct and array elements are values: compare them field by field
83
+ // (`.includes` and `.indexOf` compare object identity).
84
+ if (
85
+ (fn === "Contains" || fn === "Index") &&
86
+ this._sliceElemIsAggregate(expr)
87
+ ) {
88
+ this.useHelper("equal");
89
+ const [s1, v1] = a();
90
+ const found = fn === "Contains" ? "true" : "i";
91
+ const missing = fn === "Contains" ? "false" : "-1";
92
+ return `((s, v) => { s = s || []; for (let i = 0; i < s.length; i++) { if (__equal(s[i], v)) return ${found}; } return ${missing}; })(${s1}, ${v1})`;
93
+ }
73
94
  const isTyped = isTypedArraySlice(expr?.args?.[0]?._type);
74
95
  const gen = SLICES_DISPATCH[fn];
96
+ // These shrink or grow the slice in place; a slice view (`__sv`) has a
97
+ // fixed length, so they reslice it or copy it to a plain array.
98
+ if (VIEW_AWARE.has(fn)) this.useHelper("slice");
75
99
  return gen ? gen(a(), isTyped) : undefined;
76
100
  },
101
+
102
+ _sliceElemIsAggregate(expr) {
103
+ let t = expr?.args?.[0]?._type;
104
+ while (t?.kind === "named") t = t.underlying;
105
+ return t?.kind === "slice" && Boolean(this._aggregateBase(t.elem));
106
+ },
77
107
  };
@@ -4,25 +4,28 @@
4
4
 
5
5
  // Parsers return [value, msg|null] from the shared __strconv_* helpers
6
6
  // (runtime.js); the message becomes a Go error value.
7
- const parsed = (call, toValue = "r[0]") =>
8
- `((r) => [${toValue}, r[1] === null ? null : __error(r[1], r[1].includes("invalid syntax") ? __strconv_err_syntax : r[1].includes("value out of range") ? __strconv_err_range : null)])(${call})`;
7
+ const parsed = (fnName, numArg, call, toValue = "r[0]") =>
8
+ `((r, s) => [${toValue}, r[1] === null ? null : (typeof NumError$$strconv !== "undefined" ? ((o) => { o.__p = true; return o; })(new NumError$$strconv("${fnName}", String(s), r[1].includes("value out of range") ? __strconv_err_range : __strconv_err_syntax)) : __error(r[1], r[1].includes("invalid syntax") ? __strconv_err_syntax : r[1].includes("value out of range") ? __strconv_err_range : null))])(${call}, ${numArg})`;
9
9
 
10
10
  const STRCONV_DISPATCH = {
11
11
  Itoa: (a) => `String(${a[0]})`,
12
- Atoi: (a) => parsed(`__strconv_atoi(${a[0]})`, "Number(r[0])"),
12
+ Atoi: (a) => parsed("Atoi", a[0], `__strconv_atoi(${a[0]})`, "Number(r[0])"),
13
13
  FormatBool: (a) => `String(${a[0]})`,
14
14
  FormatInt: (a) => `(${a[0]}).toString(${a[1]})`,
15
15
  FormatFloat: (a) =>
16
16
  a.length < 3
17
17
  ? `String(${a[0]})`
18
18
  : `__strconv_format_float(${a[0]}, ${a[1]}, ${a[2]})`,
19
- ParseFloat: (a) => parsed(`__strconv_parse_float(${a[0]})`),
19
+ ParseFloat: (a) =>
20
+ parsed("ParseFloat", a[0], `__strconv_parse_float(${a[0]})`),
20
21
  ParseInt: (a) =>
21
22
  parsed(
23
+ "ParseInt",
24
+ a[0],
22
25
  `__strconv_parse_int(${a[0]}, ${a[1]}, ${a[2] ?? 64})`,
23
26
  "Number(r[0])",
24
27
  ),
25
- ParseBool: (a) => parsed(`__strconv_parse_bool(${a[0]})`),
28
+ ParseBool: (a) => parsed("ParseBool", a[0], `__strconv_parse_bool(${a[0]})`),
26
29
  Quote: (a) => `JSON.stringify(${a[0]})`,
27
30
  Unquote: (a) =>
28
31
  `((s) => { if (typeof s === "string" && s.startsWith("\`") && s.endsWith("\`") && s.length >= 2) { if (s.slice(1, -1).includes("\`")) return ["", __strconv_err_syntax]; return [s.slice(1, -1), null]; } try { const v = JSON.parse(s); if (typeof v !== "string") throw 0; return [v, null]; } catch(e) { return ["", __strconv_err_syntax]; } })(${a[0]})`,
@@ -37,6 +40,8 @@ const STRCONV_DISPATCH = {
37
40
  FormatUint: (a) => `(BigInt.asUintN(64, BigInt(${a[0]}))).toString(${a[1]})`,
38
41
  ParseUint: (a) =>
39
42
  parsed(
43
+ "ParseUint",
44
+ a[0],
40
45
  `__strconv_parse_uint(${a[0]}, ${a[1]}, ${a[2] ?? 64})`,
41
46
  "Number(r[0])",
42
47
  ),
@@ -16,9 +16,9 @@ const STRINGS_M2 = {
16
16
  LastIndex: "lastIndexOf",
17
17
  Repeat: "repeat",
18
18
  Split: "split",
19
- Join: "join",
20
19
  };
21
20
  const STRINGS_DISPATCH = {
21
+ Join: ([a, sep]) => `(${a} ?? []).join(${sep})`,
22
22
  Count: ([s, s2]) =>
23
23
  `((s, sep) => sep === "" ? s.length + 1 : s.split(sep).length - 1)(${s}, ${s2})`,
24
24
  Replace: ([s, s2, s3, n]) =>
@@ -37,7 +37,8 @@ const STRINGS_DISPATCH = {
37
37
  TrimRight: ([s, s2]) =>
38
38
  `((str, cut) => { const cs = new Set(cut); let j = str.length; while (j > 0 && cs.has(str[j - 1])) j--; return str.slice(0, j); })(${s}, ${s2})`,
39
39
  EqualFold: ([s, s2]) => `${s}.toLowerCase() === ${s2}.toLowerCase()`,
40
- Fields: ([s]) => `(${s}).trim() === '' ? [] : (${s}).trim().split(/\\s+/)`,
40
+ Fields: ([s]) =>
41
+ `(${s}).split(/[ \\t\\n\\v\\f\\r\\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+/).filter(p => p !== "")`,
41
42
  FieldsFunc: ([s, f]) =>
42
43
  `((s, fn) => { const res = []; const runes = Array.from(s ?? ""); let cur = ""; for (const ch of runes) { const cp = ch.codePointAt(0); if (fn(cp)) { if (cur.length > 0) { res.push(cur); cur = ""; } } else { cur += ch; } } if (cur.length > 0) res.push(cur); return res; })(${s}, ${f})`,
43
44
  Cut: ([s, s2]) =>
@@ -169,8 +170,83 @@ const STRINGS_DISPATCH = {
169
170
  `((s, f) => { for (let i = 0; i < s.length; i++) { const cp = s.codePointAt(i); if (f(cp)) return i; if (cp > 0xFFFF) i++; } return -1; })(${s}, ${s2})`,
170
171
  LastIndexFunc: ([s, s2]) =>
171
172
  `((s, f) => { for (let i = s.length - 1; i >= 0; i--) { let cp = s.codePointAt(i); if (i > 0 && s.charCodeAt(i) >= 0xDC00 && s.charCodeAt(i) <= 0xDFFF && s.charCodeAt(i - 1) >= 0xD800 && s.charCodeAt(i - 1) <= 0xDBFF) { cp = s.codePointAt(i - 1); i--; } if (f(cp)) return i; } return -1; })(${s}, ${s2})`,
173
+ ToValidUTF8: ([s, repl]) =>
174
+ `(${s} ? ${s}.replace(/(?:[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF])+/g, ${repl} ?? "") : (${s} ?? ""))`,
172
175
  NewReader: ([s]) =>
173
- `((s) => ({ _bytes: new TextEncoder().encode(s), _pos: 0, Read(p) { if (this._pos >= this._bytes.length) return [0, __io_eof]; const n = Math.min(p.length, this._bytes.length - this._pos); for (let i = 0; i < n; i++) p[i] = this._bytes[this._pos + i]; this._pos += n; return [n, null]; }, Len() { return Math.max(0, this._bytes.length - this._pos); }, Reset(s2) { this._bytes = new TextEncoder().encode(s2); this._pos = 0; } }))(${s})`,
176
+ `((s) => ({
177
+ _bytes: new TextEncoder().encode(s ?? ""),
178
+ _pos: 0,
179
+ _prevRune: -1,
180
+ Read(p) {
181
+ if (this._pos >= this._bytes.length) return [0, __io_eof];
182
+ const n = Math.min(p.length, this._bytes.length - this._pos);
183
+ for (let i = 0; i < n; i++) p[i] = this._bytes[this._pos + i];
184
+ this._pos += n;
185
+ this._prevRune = -1;
186
+ return [n, null];
187
+ },
188
+ ReadAt(b, off) {
189
+ const o = Number(off);
190
+ if (o < 0) return [0, __error("strings.Reader.ReadAt: negative offset")];
191
+ if (o >= this._bytes.length) return [0, __io_eof];
192
+ const n = Math.min(b.length, this._bytes.length - o);
193
+ for (let i = 0; i < n; i++) b[i] = this._bytes[o + i];
194
+ return [n, n < b.length ? __io_eof : null];
195
+ },
196
+ ReadByte() {
197
+ if (this._pos >= this._bytes.length) return [0, __io_eof];
198
+ this._prevRune = -1;
199
+ return [this._bytes[this._pos++], null];
200
+ },
201
+ UnreadByte() {
202
+ if (this._pos <= 0) return __error("strings.Reader.UnreadByte: at beginning of string");
203
+ this._prevRune = -1;
204
+ this._pos--;
205
+ return null;
206
+ },
207
+ ReadRune() {
208
+ if (this._pos >= this._bytes.length) return [0, 0, __io_eof];
209
+ const rem = this._bytes.subarray(this._pos);
210
+ const str = new TextDecoder().decode(rem);
211
+ const cp = str.codePointAt(0);
212
+ const runeStr = str.slice(0, cp > 0xffff ? 2 : 1);
213
+ const sz = new TextEncoder().encode(runeStr).length;
214
+ this._prevRune = this._pos;
215
+ this._pos += sz;
216
+ return [cp, sz, null];
217
+ },
218
+ UnreadRune() {
219
+ if (this._prevRune === undefined || this._prevRune < 0 || this._prevRune >= this._pos) {
220
+ return __error("strings.Reader.UnreadRune: previous operation was not ReadRune");
221
+ }
222
+ this._pos = this._prevRune;
223
+ this._prevRune = -1;
224
+ return null;
225
+ },
226
+ Seek(offset, whence) {
227
+ const off = BigInt(offset);
228
+ const w = Number(whence);
229
+ let newPos;
230
+ if (w === 0) newPos = off;
231
+ else if (w === 1) newPos = BigInt(this._pos) + off;
232
+ else if (w === 2) newPos = BigInt(this._bytes.length) + off;
233
+ else return [0n, __error("strings.Reader.Seek: invalid whence")];
234
+ if (newPos < 0n) return [0n, __error("strings.Reader.Seek: negative position")];
235
+ this._pos = Number(newPos);
236
+ this._prevRune = -1;
237
+ return [newPos, null];
238
+ },
239
+ Size() { return BigInt(this._bytes.length); },
240
+ WriteTo(w) {
241
+ if (this._pos >= this._bytes.length) return [0, null];
242
+ const rem = this._bytes.subarray(this._pos);
243
+ const [n, err] = w.Write(rem);
244
+ this._pos += n;
245
+ return [n, err];
246
+ },
247
+ Len() { return Math.max(0, this._bytes.length - this._pos); },
248
+ Reset(s2) { this._bytes = new TextEncoder().encode(s2 ?? ""); this._pos = 0; this._prevRune = -1; }
249
+ }))(${s})`,
174
250
  NewReplacer: (args) =>
175
251
  `((...pairs) => {
176
252
  const p = [];
@@ -211,7 +287,10 @@ const STRINGS_DISPATCH = {
211
287
  /** @type {ThisType<CodeGen>} */
212
288
  export const stringsMethods = {
213
289
  _genStrings(fn, a) {
214
- if (fn === "NewReader") this.useHelper("ioEOF");
290
+ if (fn === "NewReader") {
291
+ this.useHelper("ioEOF");
292
+ this.useHelper("error");
293
+ }
215
294
  const args = a();
216
295
  const [s, s2] = args;
217
296
  if (STRINGS_M1[fn]) return `${s}.${STRINGS_M1[fn]}()`;
@@ -10,6 +10,13 @@ export const testingMethods = {
10
10
  return "false";
11
11
  case "Verbose":
12
12
  return "Boolean(globalThis.__gofront_verbose)";
13
+ case "Testing":
14
+ return "true";
15
+ case "Init":
16
+ return "/* testing.Init */";
17
+ case "Benchmark":
18
+ this.useHelper("testing");
19
+ return `__testing_Benchmark(${_a()[0]})`;
13
20
  }
14
21
  return undefined;
15
22
  },
@@ -3,53 +3,52 @@
3
3
  /** @typedef {import('../index.js').CodeGen} CodeGen */
4
4
 
5
5
  const TIME_METHOD_DISPATCH = {
6
- Year: (r) =>
7
- `(${r}._offset === 0 ? ${r}._d.getUTCFullYear() : ${r}._d.getFullYear())`,
8
- Month: (r) =>
9
- `(${r}._offset === 0 ? ${r}._d.getUTCMonth() + 1 : ${r}._d.getMonth() + 1)`,
10
- Day: (r) => `(${r}._offset === 0 ? ${r}._d.getUTCDate() : ${r}._d.getDate())`,
11
- Hour: (r) =>
12
- `(${r}._offset === 0 ? ${r}._d.getUTCHours() : ${r}._d.getHours())`,
13
- Minute: (r) =>
14
- `(${r}._offset === 0 ? ${r}._d.getUTCMinutes() : ${r}._d.getMinutes())`,
15
- Second: (r) =>
16
- `(${r}._offset === 0 ? ${r}._d.getUTCSeconds() : ${r}._d.getSeconds())`,
17
- Weekday: (r) =>
18
- `(${r}._offset === 0 ? ${r}._d.getUTCDay() : ${r}._d.getDay())`,
6
+ Year: (r) => `__timeYear(${r})`,
7
+ Month: (r) => `__timeMonth(${r})`,
8
+ Day: (r) => `__timeDay(${r})`,
9
+ Hour: (r) => `__timeHour(${r})`,
10
+ Minute: (r) => `__timeMinute(${r})`,
11
+ Second: (r) => `__timeSecond(${r})`,
12
+ Weekday: (r) => `__timeWeekday(${r})`,
19
13
  Unix: (r) => `Math.floor(${r}._d.getTime() / 1000)`,
20
14
  UnixMilli: (r) => `${r}._d.getTime()`,
21
15
  Add: (r, a) =>
22
- `{_d: new Date(${r}._d.getTime() + Math.round(Number(${a[0]}) / 1000000))}`,
16
+ `{_d: new Date(${r}._d.getTime() + Math.round(Number(${a[0]}) / 1000000)), _offset: ${r}._offset, _loc: ${r}._loc, _ns: ${r}._ns}`,
23
17
  Sub: (r, a) =>
24
18
  `Math.round((${r}._d.getTime() - (${a[0]})._d.getTime()) * 1000000)`,
25
19
  Before: (r, a) => `(${r}._d < (${a[0]})._d)`,
26
20
  After: (r, a) => `(${r}._d > (${a[0]})._d)`,
27
- Equal: (r, a) => `(${r}._d.getTime() === (${a[0]})._d.getTime())`,
21
+ Equal: (r, a) =>
22
+ `(${r}._d.getTime() === (${a[0]})._d.getTime() && (${r}._ns || 0) === ((${a[0]})._ns || 0))`,
28
23
  IsZero: (r) =>
29
24
  `(!${r} || !${r}._d || ${r}._isZero === true || ${r}._d.getTime() === -62135596800000 || (${r}._d.getUTCFullYear() <= 1 && ${r}._d.getUTCMonth() === 0 && ${r}._d.getUTCDate() === 1 && ${r}._d.getUTCHours() === 0 && ${r}._d.getUTCMinutes() === 0 && ${r}._d.getUTCSeconds() === 0 && ${r}._d.getUTCMilliseconds() === 0))`,
30
- UnixNano: (r) => `(${r}?._d ? Math.round(${r}._d.getTime() * 1000000) : 0)`,
25
+ UnixNano: (r) =>
26
+ `(${r}?._d ? Math.round(${r}._d.getTime() * 1000000) + (${r}._ns || 0) : 0)`,
31
27
  Nanosecond: (r) =>
32
- `(${r}?._d ? (${r}._offset === 0 ? ${r}._d.getUTCMilliseconds() : ${r}._d.getMilliseconds()) * 1000000 : 0)`,
33
- UTC: (r) => `({_d: ${r}?._d ?? new Date(0), _offset: 0})`,
34
- Local: (r) => `({_d: ${r}?._d ?? new Date(0)})`,
35
- AddDate: (r, a) =>
36
- `({_d: new Date(${r}._d.getFullYear() + Number(${a[0]}), ${r}._d.getMonth() + Number(${a[1]}), ${r}._d.getDate() + Number(${a[2]}))})`,
37
- Truncate: (r, a) =>
38
- `({_d: new Date(Math.floor(${r}._d.getTime() / (Number(${a[0]}) / 1000000)) * (Number(${a[0]}) / 1000000))})`,
39
- Round: (r, a) =>
40
- `({_d: new Date(Math.round(${r}._d.getTime() / (Number(${a[0]}) / 1000000)) * (Number(${a[0]}) / 1000000))})`,
41
- Date: (r) =>
42
- `[${r}._offset === 0 ? ${r}._d.getUTCFullYear() : ${r}._d.getFullYear(), ${r}._offset === 0 ? ${r}._d.getUTCMonth() + 1 : ${r}._d.getMonth() + 1, ${r}._offset === 0 ? ${r}._d.getUTCDate() : ${r}._d.getDate()]`,
43
- Clock: (r) =>
44
- `[${r}._offset === 0 ? ${r}._d.getUTCHours() : ${r}._d.getHours(), ${r}._offset === 0 ? ${r}._d.getUTCMinutes() : ${r}._d.getMinutes(), ${r}._offset === 0 ? ${r}._d.getUTCSeconds() : ${r}._d.getSeconds()]`,
45
- YearDay: (r) =>
46
- `Math.floor((${r}._d - new Date(${r}._d.getFullYear(), 0, 0)) / 86400000)`,
28
+ `(${r}?._d ? (typeof ${r}._offset === "number" ? ${r}._d.getUTCMilliseconds() : ${r}._d.getMilliseconds()) * 1000000 + (${r}._ns || 0) : 0)`,
29
+ UTC: (r) =>
30
+ `({_d: ${r}?._d ?? new Date(0), _offset: 0, _loc: null, _ns: ${r}?._ns || 0})`,
31
+ Local: (r) =>
32
+ `({_d: ${r}?._d ?? new Date(0), _offset: undefined, _loc: null, _ns: ${r}?._ns || 0})`,
33
+ AddDate: (r, a) => `__timeAddDate(${r}, ${a[0]}, ${a[1]}, ${a[2]})`,
34
+ Truncate: (r, a) => `__timeTruncate(${r}, ${a[0]})`,
35
+ Round: (r, a) => `__timeRound(${r}, ${a[0]})`,
36
+ Date: (r) => `__timeDate(${r})`,
37
+ Clock: (r) => `__timeClock(${r})`,
38
+ YearDay: (r) => `__timeYearDay(${r})`,
47
39
  Compare: (r, a) =>
48
- `(${r}._d.getTime() < (${a[0]})._d.getTime() ? -1 : (${r}._d.getTime() > (${a[0]})._d.getTime() ? 1 : 0))`,
49
- In: (r) => `${r}`,
50
- Location: () => `null`,
40
+ `(${r}._d.getTime() < (${a[0]})._d.getTime() ? -1 : (${r}._d.getTime() > (${a[0]})._d.getTime() ? 1 : ((${r}._ns || 0) < ((${a[0]})._ns || 0) ? -1 : ((${r}._ns || 0) > ((${a[0]})._ns || 0) ? 1 : 0))))`,
41
+ ISOWeek: (r) => `__timeISOWeek(${r})`,
42
+ In: (r, a) =>
43
+ `((() => { const _loc = ${a[0]}; const _off = _loc && typeof _loc._offset === "number" ? _loc._offset : 0; return { _d: ${r}._d, _offset: _off, _loc, _ns: ${r}._ns }; })())`,
44
+ Location: (r) =>
45
+ `(${r}._loc ?? (${r}._offset === 0 ? { _name: "UTC", _offset: 0, String() { return "UTC"; } } : { _name: "Local", _offset: -${r}._d.getTimezoneOffset() * 60, String() { return "Local"; } }))`,
51
46
  Zone: (r) =>
52
- `[${r}._offset === 0 ? "UTC" : "LOCAL", ${r}._offset === 0 ? 0 : -${r}._d.getTimezoneOffset() * 60]`,
47
+ `[${r}._loc ? ${r}._loc._name : (${r}._offset === 0 ? "UTC" : "LOCAL"), ${r}._loc ? ${r}._loc._offset : (${r}._offset === 0 ? 0 : -${r}._d.getTimezoneOffset() * 60)]`,
48
+ MarshalJSON: (r) => `__timeMarshalJSON(${r})`,
49
+ UnmarshalJSON: (r, a) => `__timeUnmarshalJSON(${r}, ${a[0]})`,
50
+ MarshalText: (r) => `__timeMarshalText(${r})`,
51
+ UnmarshalText: (r, a) => `__timeUnmarshalText(${r}, ${a[0]})`,
53
52
  };
54
53
 
55
54
  const DURATION_METHOD_DISPATCH = {
@@ -60,6 +59,9 @@ const DURATION_METHOD_DISPATCH = {
60
59
  Minutes: (r) => `(Number(${r}) / 60000000000)`,
61
60
  Hours: (r) => `(Number(${r}) / 3600000000000)`,
62
61
  String: (r) => `__durationString(${r})`,
62
+ Truncate: (r, a) => `(${a[0]} <= 0 ? ${r} : ${r} - (${r} % ${a[0]}))`,
63
+ Round: (r, a) => `__durationRound(${r}, ${a[0]})`,
64
+ Abs: (r) => `(${r} >= 0 ? ${r} : -(${r}))`,
63
65
  };
64
66
 
65
67
  const TIME_DISPATCH = {
@@ -69,11 +71,16 @@ const TIME_DISPATCH = {
69
71
  `(Math.round(((typeof globalThis.__GOFRONT_CLOCK === "function" ? globalThis.__GOFRONT_CLOCK() : Date.now()) - (${a[0]})._d.getTime()) * 1000000))`,
70
72
  Sleep: (a) => `await new Promise(r => setTimeout(r, ${a[0]} / 1000000))`,
71
73
  Unix: (a) =>
72
- `{_d: new Date(Number(${a[0]}) * 1000 + Math.round(Number(${a[1] || 0}) / 1000000))}`,
73
- UnixMicro: (a) => `{_d: new Date(Math.round(Number(${a[0]}) / 1000))}`,
74
+ `{_d: new Date(Number(${a[0]}) * 1000 + Math.round(Number(${a[1] || 0}) / 1000000)), _ns: Math.round(Number(${a[1] || 0}) % 1000000)}`,
75
+ UnixMicro: (a) =>
76
+ `{_d: new Date(Math.round(Number(${a[0]}) / 1000)), _ns: Math.round((Number(${a[0]}) % 1000) * 1000)}`,
74
77
  UnixMilli: (a) => `{_d: new Date(Number(${a[0]}))}`,
75
78
  Date: (a) =>
76
- `{_d: new Date(${a[0]}, ${a[1]} - 1, ${a[2]}, ${a[3]}, ${a[4]}, ${a[5]}, Math.round(Number(${a[6] || 0}) / 1000000))}`,
79
+ `{_d: new Date(${a[0]}, ${a[1]} - 1, ${a[2]}, ${a[3]}, ${a[4]}, ${a[5]}, Math.round(Number(${a[6] || 0}) / 1000000)), _ns: Math.round(Number(${a[6] || 0}) % 1000000)}`,
80
+ ParseDuration: (a) => `__timeParseDuration(${a[0]})`,
81
+ FixedZone: (a) =>
82
+ `({ _name: ${a[0]}, _offset: ${a[1]}, String() { return this._name; } })`,
83
+ AfterFunc: (a) => `__timeAfterFunc(${a[0]}, ${a[1]})`,
77
84
  };
78
85
 
79
86
  /** @type {ThisType<CodeGen>} */
@@ -82,12 +89,13 @@ export const timeMethods = {
82
89
  const recv = expr.func.expr;
83
90
  const recvJs = this.genExpr(recv);
84
91
  const args = expr.args.map((a) => this.genExpr(a));
92
+ this.useHelper("timeFmt");
93
+ this.useHelper("duration");
94
+ this.useHelper("timeParse");
85
95
  if (method === "Format") {
86
- this.useHelper("timeFmt");
87
96
  return `__timeFmt(${recvJs}, ${args[0]})`;
88
97
  }
89
98
  if (method === "String") {
90
- this.useHelper("timeFmt");
91
99
  return `__timeFmt(${recvJs}, "2006-01-02 15:04:05.999999999 -0700 MST")`;
92
100
  }
93
101
  const gen = TIME_METHOD_DISPATCH[method];
@@ -97,30 +105,46 @@ export const timeMethods = {
97
105
  _genDurationMethodCall(method, expr) {
98
106
  const recv = expr.func.expr;
99
107
  const recvJs = this.genExpr(recv);
100
- if (method === "String") {
101
- this.useHelper("duration");
102
- }
108
+ const args = expr.args.map((a) => this.genExpr(a));
109
+ this.useHelper("duration");
103
110
  const gen = DURATION_METHOD_DISPATCH[method];
104
- return gen ? gen(recvJs) : undefined;
111
+ return gen ? gen(recvJs, args) : undefined;
112
+ },
113
+
114
+ _genTimeDate(args, expr) {
115
+ this.useHelper("timeFmt");
116
+ const locArg = expr?.args?.[7];
117
+ const isUtc =
118
+ (locArg?.kind === "SelectorExpr" &&
119
+ (locArg.sel?.name === "UTC" || locArg.field === "UTC")) ||
120
+ (locArg?.kind === "Ident" && locArg.name === "UTC") ||
121
+ args[7] === '"UTC"';
122
+ if (isUtc) {
123
+ return `{_d: new Date(Date.UTC(${args[0]}, ${args[1]} - 1, ${args[2]}, ${args[3]}, ${args[4]}, ${args[5]}, Math.floor(Number(${args[6] || 0}) / 1000000))), _offset: 0, _loc: null, _ns: Math.floor(Number(${args[6] || 0}) % 1000000)}`;
124
+ }
125
+ return `((() => { const _loc = ${args[7]}; const _off = _loc && typeof _loc._offset === "number" ? _loc._offset : undefined; const _ms = Math.floor(Number(${args[6] || 0}) / 1000000); const _remNs = Math.floor(Number(${args[6] || 0}) % 1000000); if (_off !== undefined) { const _d = new Date(Date.UTC(${args[0]}, ${args[1]} - 1, ${args[2]}, ${args[3]}, ${args[4]}, ${args[5]}, _ms) - _off * 1000); return { _d, _offset: _off, _loc, _ns: _remNs }; } return { _d: new Date(${args[0]}, ${args[1]} - 1, ${args[2]}, ${args[3]}, ${args[4]}, ${args[5]}, _ms), _offset: undefined, _loc: null, _ns: _remNs }; })())`;
105
126
  },
106
127
 
107
128
  _genTime(fn, a, expr) {
129
+ if (fn === "Date") return this._genTimeDate(a(), expr);
108
130
  if (fn === "Parse") {
109
131
  this.useHelper("timeParse");
132
+ this.useHelper("timeFmt");
110
133
  return `__timeParse(${a()[0]}, ${a()[1]})`;
111
134
  }
112
- if (fn === "Date") {
135
+ if (fn === "ParseDuration") {
136
+ this.useHelper("duration");
137
+ return `__timeParseDuration(${a()[0]})`;
138
+ }
139
+ if (fn === "FixedZone") {
140
+ this.useHelper("timeFmt");
141
+ const args = a();
142
+ return `({ _name: ${args[0]}, _offset: ${args[1]}, String() { return this._name; } })`;
143
+ }
144
+ if (fn === "AfterFunc") {
145
+ this.useHelper("timeFmt");
113
146
  const args = a();
114
- const locArg = expr?.args?.[7];
115
- const isUtc =
116
- (locArg?.kind === "SelectorExpr" &&
117
- (locArg.sel?.name === "UTC" || locArg.field === "UTC")) ||
118
- (locArg?.kind === "Ident" && locArg.name === "UTC") ||
119
- args[7] === '"UTC"';
120
- if (isUtc) {
121
- return `{_d: new Date(Date.UTC(${args[0]}, ${args[1]} - 1, ${args[2]}, ${args[3]}, ${args[4]}, ${args[5]}, Math.round(Number(${args[6] || 0}) / 1000000))), _offset: 0}`;
122
- }
123
- return `{_d: new Date(${args[0]}, ${args[1]} - 1, ${args[2]}, ${args[3]}, ${args[4]}, ${args[5]}, Math.round(Number(${args[6] || 0}) / 1000000))}`;
147
+ return `__timeAfterFunc(${args[0]}, ${args[1]})`;
124
148
  }
125
149
  const gen = TIME_DISPATCH[fn];
126
150
  return gen ? gen(a()) : undefined;
@@ -10,7 +10,7 @@ export const unicodeMethods = {
10
10
  const UNICODE_TEST = {
11
11
  IsLetter: `/\\p{L}/u.test(${cp})`,
12
12
  IsDigit: `/\\p{Nd}/u.test(${cp})`,
13
- IsSpace: `/\\s/.test(${cp})`,
13
+ IsSpace: `/[ \\t\\n\\v\\f\\r\\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]/.test(${cp})`,
14
14
  IsUpper: `/\\p{Lu}/u.test(${cp})`,
15
15
  IsLower: `/\\p{Ll}/u.test(${cp})`,
16
16
  IsPunct: `/\\p{P}/u.test(${cp})`,
@@ -9,7 +9,7 @@ const UTF8_DISPATCH = {
9
9
  ValidString: (a) =>
10
10
  `/[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/.test(${a[0]}) === false`,
11
11
  ValidRune: (a) =>
12
- `(${a[0]}) >= 0 && (${a[0]}) <= 0x10FFFF && !((${a[0]}) >= 0xD800 && (${a[0]}) <= 0xDFFF)`,
12
+ `((${a[0]}) >= 0 && (${a[0]}) <= 0x10FFFF && !((${a[0]}) >= 0xD800 && (${a[0]}) <= 0xDFFF))`,
13
13
  DecodeRuneInString: (a) =>
14
14
  `((s) => { if (!s) return [0xFFFD, 0]; const cp = s.codePointAt(0); return [cp, cp > 0xFFFF ? 2 : 1]; })(${a[0]})`,
15
15
  DecodeLastRuneInString: (a) =>