gofront 0.0.9 → 1.0.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 (53) hide show
  1. package/README.md +5 -5
  2. package/package.json +7 -4
  3. package/src/cli-core.js +65 -0
  4. package/src/codegen/expressions.js +523 -1717
  5. package/src/codegen/index.js +576 -0
  6. package/src/codegen/runtime.js +151 -0
  7. package/src/codegen/statements.js +308 -296
  8. package/src/codegen/stdlib/builder.js +39 -0
  9. package/src/codegen/stdlib/bytes.js +65 -0
  10. package/src/codegen/stdlib/errors.js +20 -0
  11. package/src/codegen/stdlib/fmt.js +104 -0
  12. package/src/codegen/stdlib/gom.js +155 -0
  13. package/src/codegen/stdlib/html.js +20 -0
  14. package/src/codegen/stdlib/index.js +98 -0
  15. package/src/codegen/stdlib/io.js +36 -0
  16. package/src/codegen/stdlib/maps.js +45 -0
  17. package/src/codegen/stdlib/math.js +56 -0
  18. package/src/codegen/stdlib/os.js +13 -0
  19. package/src/codegen/stdlib/path.js +34 -0
  20. package/src/codegen/stdlib/rand.js +27 -0
  21. package/src/codegen/stdlib/regexp.js +54 -0
  22. package/src/codegen/stdlib/slices.js +51 -0
  23. package/src/codegen/stdlib/sort.js +31 -0
  24. package/src/codegen/stdlib/strconv.js +33 -0
  25. package/src/codegen/stdlib/strings.js +86 -0
  26. package/src/codegen/stdlib/time.js +57 -0
  27. package/src/codegen/stdlib/unicode.js +25 -0
  28. package/src/codegen/stdlib/utf8.js +26 -0
  29. package/src/codegen/templ.js +284 -0
  30. package/src/compiler.js +142 -77
  31. package/src/dts-parser.js +355 -371
  32. package/src/index.js +32 -162
  33. package/src/lexer.js +186 -272
  34. package/src/minifier.js +305 -318
  35. package/src/{parser.js → parser/declarations.js} +18 -175
  36. package/src/parser/expressions.js +51 -34
  37. package/src/parser/index.js +161 -0
  38. package/src/parser/statements.js +24 -34
  39. package/src/parser/types.js +31 -29
  40. package/src/templ-parser.js +2 -2
  41. package/src/tokens.js +109 -0
  42. package/src/typechecker/assignability.js +261 -0
  43. package/src/typechecker/expressions.js +568 -549
  44. package/src/typechecker/index.js +556 -0
  45. package/src/typechecker/resolve.js +428 -0
  46. package/src/typechecker/statements.js +270 -280
  47. package/src/typechecker/stdlib/core.js +592 -0
  48. package/src/typechecker/stdlib/extended.js +332 -0
  49. package/src/typechecker/stdlib.js +9 -1060
  50. package/src/typechecker/termination.js +86 -0
  51. package/src/typechecker/types.js +1 -0
  52. package/src/codegen.js +0 -882
  53. package/src/typechecker.js +0 -1299
@@ -0,0 +1,34 @@
1
+ // CodeGen for Go `path` package.
2
+
3
+ /** @typedef {import('../index.js').CodeGen} CodeGen */
4
+
5
+ const PATH_DISPATCH = {
6
+ Base: (a) =>
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
+ Dir: (a) =>
9
+ `((p) => { const i = p.lastIndexOf("/"); if (i < 0) return "."; if (i === 0) return "/"; return p.slice(0, i); })(${a[0]})`,
10
+ Ext: (a) =>
11
+ `((p) => { const b = p.slice(p.lastIndexOf("/") + 1); const i = b.lastIndexOf("."); return i <= 0 ? "" : b.slice(i); })(${a[0]})`,
12
+ IsAbs: (a) => `(${a[0]}).startsWith("/")`,
13
+ Split: (a) =>
14
+ `((p) => { const i = p.lastIndexOf("/"); return i < 0 ? ["", p] : [p.slice(0, i + 1), p.slice(i + 1)]; })(${a[0]})`,
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]})`,
17
+ };
18
+
19
+ /** @type {ThisType<CodeGen>} */
20
+ export const pathMethods = {
21
+ _genPath(fn, a, expr) {
22
+ if (fn === "Join") {
23
+ this._usesPathClean = true;
24
+ const allArgs = expr.args.map((e) => this.genExpr(e)).join(", ");
25
+ return `__pathClean([${allArgs}].filter(x => x !== "").join("/"))`;
26
+ }
27
+ if (fn === "Clean") {
28
+ this._usesPathClean = true;
29
+ return `__pathClean(${a()[0]})`;
30
+ }
31
+ const gen = PATH_DISPATCH[fn];
32
+ return gen ? gen(a()) : undefined;
33
+ },
34
+ };
@@ -0,0 +1,27 @@
1
+ // CodeGen for Go `math/rand` package.
2
+
3
+ /** @typedef {import('../index.js').CodeGen} CodeGen */
4
+
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]})`,
9
+ Float64: () => "Math.random()",
10
+ Float32: () => "Math.random()",
11
+ Int: () => "Math.floor(Math.random() * 2147483647)",
12
+ Int31: () => "Math.floor(Math.random() * 2147483647)",
13
+ Int63: () => "Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)",
14
+ Seed: () => "(void 0)",
15
+ 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]})`,
17
+ 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]})`,
19
+ };
20
+
21
+ /** @type {ThisType<CodeGen>} */
22
+ export const randMethods = {
23
+ _genRand(fn, a) {
24
+ const gen = RAND_DISPATCH[fn];
25
+ return gen ? gen(a()) : undefined;
26
+ },
27
+ };
@@ -0,0 +1,54 @@
1
+ // CodeGen for Go `regexp` package and `*Regexp` methods.
2
+
3
+ /** @typedef {import('../index.js').CodeGen} CodeGen */
4
+
5
+ const REGEXP_METHOD = {
6
+ MatchString: (re, a) => `${re}.test(${a[0]})`,
7
+ FindString: (re, a) => `(${re}.exec(${a[0]})?.[0] ?? "")`,
8
+ FindStringIndex: (re, a) =>
9
+ `((m => m ? [m.index, m.index + m[0].length] : null)(${re}.exec(${a[0]})))`,
10
+ FindAllString: (re, a) =>
11
+ `[...${a[0]}.matchAll(new RegExp(${re}.source, ${re}.flags.includes("g") ? ${re}.flags : ${re}.flags + "g"))].slice(0, ${a[1]} < 0 ? undefined : ${a[1]}).map(m => m[0])`,
12
+ FindStringSubmatch: (re, a) => `[...(${re}.exec(${a[0]}) ?? [])]`,
13
+ FindAllStringSubmatch: (re, a) =>
14
+ `[...${a[0]}.matchAll(new RegExp(${re}.source, ${re}.flags.includes("g") ? ${re}.flags : ${re}.flags + "g"))].slice(0, ${a[1]} < 0 ? undefined : ${a[1]}).map(m => [...m])`,
15
+ ReplaceAllString: (re, a) =>
16
+ `${a[0]}.replaceAll(new RegExp(${re}.source, ${re}.flags.includes("g") ? ${re}.flags : ${re}.flags + "g"), ${a[1]})`,
17
+ ReplaceAllLiteralString: (re, a) =>
18
+ `${a[0]}.replaceAll(new RegExp(${re}.source, ${re}.flags.includes("g") ? ${re}.flags : ${re}.flags + "g"), ${a[1]}.replace(/\\$/g, '$$$$'))`,
19
+ Split: (re, a) =>
20
+ `${a[0]}.split(${re}).slice(0, ${a[1]} < 0 ? undefined : ${a[1]})`,
21
+ String: (re) => `${re}.source`,
22
+ };
23
+
24
+ /** @type {ThisType<CodeGen>} */
25
+ export const regexpMethods = {
26
+ _genRegexp(fn, a) {
27
+ // Converts a Go regexp pattern string (which may contain inline flags like (?i))
28
+ // into a JS RegExp, extracting the flags into the second constructor argument.
29
+ const makeRegExp = (pat) =>
30
+ `((p) => { const m = /^\\(\\?([gimsuy]+)\\)/.exec(p); return m ? new RegExp(p.slice(m[0].length), m[1]) : new RegExp(p); })(${pat})`;
31
+ switch (fn) {
32
+ case "MustCompile":
33
+ return makeRegExp(a()[0]);
34
+ case "Compile":
35
+ return `[${makeRegExp(a()[0])}, null]`;
36
+ case "MatchString": {
37
+ const [pat, s] = a();
38
+ return `[new RegExp(${pat}).test(${s}), null]`;
39
+ }
40
+ case "QuoteMeta":
41
+ return `${a()[0]}.replace(/[.*+?^\${}()|[\\]\\\\]/g, '\\\\$&')`;
42
+ }
43
+ return undefined;
44
+ },
45
+
46
+ _genRegexpMethodCall(method, expr) {
47
+ const recv = expr.func.expr;
48
+ // *Regexp is a plain JS RegExp — no .value boxing needed
49
+ const re = this.genExpr(recv);
50
+ const args = expr.args.map((a) => this.genExpr(a));
51
+ const gen = REGEXP_METHOD[method];
52
+ return gen ? gen(re, args) : undefined;
53
+ },
54
+ };
@@ -0,0 +1,51 @@
1
+ // CodeGen for Go `slices` package.
2
+
3
+ /** @typedef {import('../index.js').CodeGen} CodeGen */
4
+
5
+ const SLICES_DISPATCH = {
6
+ Contains: (a) => `${a[0]}.includes(${a[1]})`,
7
+ Index: (a) => `${a[0]}.indexOf(${a[1]})`,
8
+ 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]})`,
13
+ IsSorted: (a) =>
14
+ `((s) => { for (let i = 1; i < s.length; i++) { if (s[i] < s[i-1]) return false; } return true; })(${a[0]})`,
15
+ 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]})`,
20
+ MaxFunc: (a) =>
21
+ `((s, f) => s.reduce((m, x) => f(x, m) > 0 ? x : m))(${a[0]}, ${a[1]})`,
22
+ 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()`,
25
+ Compact: (a) =>
26
+ `((s) => s.filter((v, i) => i === 0 || v !== s[i-1]))(${a[0]})`,
27
+ 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()`,
38
+ };
39
+
40
+ /** @type {ThisType<CodeGen>} */
41
+ export const slicesMethods = {
42
+ _genSlices(fn, a) {
43
+ if (fn === "Equal") {
44
+ this._usesEqual = true;
45
+ const [a1, b1] = a();
46
+ return `__equal(${a1}, ${b1})`;
47
+ }
48
+ const gen = SLICES_DISPATCH[fn];
49
+ return gen ? gen(a()) : undefined;
50
+ },
51
+ };
@@ -0,0 +1,31 @@
1
+ // CodeGen for Go `sort` package.
2
+
3
+ /** @typedef {import('../index.js').CodeGen} CodeGen */
4
+
5
+ const SORT_DISPATCH = {
6
+ Ints: (a) => `${a[0]}.sort((a, b) => a - b)`,
7
+ Float64s: (a) => `${a[0]}.sort((a, b) => a - b)`,
8
+ Strings: (a) => `${a[0]}.sort()`,
9
+ Slice: (a) =>
10
+ `${a[0]}.sort((a, b) => ${a[1]}(a, b) ? -1 : ${a[1]}(b, a) ? 1 : 0)`,
11
+ SliceStable: (a) =>
12
+ `${a[0]}.sort((a, b) => ${a[1]}(a, b) ? -1 : ${a[1]}(b, a) ? 1 : 0)`,
13
+ SliceIsSorted: (a) =>
14
+ `${a[0]}.every((v, i, a) => i === 0 || ${a[1]}(a[i - 1], v))`,
15
+ Search: (a) =>
16
+ `((n, f) => { let lo = 0, hi = n; while (lo < hi) { const mid = (lo + hi) >>> 1; if (f(mid)) hi = mid; else lo = mid + 1; } return lo; })(${a[0]}, ${a[1]})`,
17
+ IntsAreSorted: (a) =>
18
+ `(${a[0]}).every((v, i, a) => i === 0 || a[i - 1] <= v)`,
19
+ Float64sAreSorted: (a) =>
20
+ `(${a[0]}).every((v, i, a) => i === 0 || a[i - 1] <= v)`,
21
+ StringsAreSorted: (a) =>
22
+ `(${a[0]}).every((v, i, a) => i === 0 || a[i - 1] <= v)`,
23
+ };
24
+
25
+ /** @type {ThisType<CodeGen>} */
26
+ export const sortMethods = {
27
+ _genSort(fn, a) {
28
+ const gen = SORT_DISPATCH[fn];
29
+ return gen ? gen(a()) : undefined;
30
+ },
31
+ };
@@ -0,0 +1,33 @@
1
+ // CodeGen for Go `strconv` package.
2
+
3
+ /** @typedef {import('../index.js').CodeGen} CodeGen */
4
+
5
+ const STRCONV_DISPATCH = {
6
+ Itoa: (a) => `String(${a[0]})`,
7
+ Atoi: (a) =>
8
+ `(Number.isNaN(Number(${a[0]})) ? [0, "invalid syntax"] : [Number(${a[0]}) | 0, null])`,
9
+ FormatBool: (a) => `String(${a[0]})`,
10
+ FormatInt: (a) => `(${a[0]}).toString(${a[1]})`,
11
+ FormatFloat: (a) => `String(${a[0]})`,
12
+ ParseFloat: (a) =>
13
+ `(Number.isNaN(Number(${a[0]})) ? [0, "invalid syntax"] : [Number(${a[0]}), null])`,
14
+ ParseInt: (a) =>
15
+ `(Number.isNaN(parseInt(${a[0]}, ${a[1]} || 10)) ? [0, "invalid syntax"] : [parseInt(${a[0]}, ${a[1]} || 10), null])`,
16
+ ParseBool: (a) =>
17
+ `(${a[0]} === "true" || ${a[0]} === "1" ? [true, null] : ${a[0]} === "false" || ${a[0]} === "0" ? [false, null] : [false, "invalid syntax"])`,
18
+ Quote: (a) => `JSON.stringify(${a[0]})`,
19
+ Unquote: (a) =>
20
+ `((s) => { try { const v = JSON.parse(s); return [v, null]; } catch(e) { return ["", "invalid syntax"]; } })(${a[0]})`,
21
+ AppendInt: (a) =>
22
+ `[...(${a[0]}), ...new TextEncoder().encode((${a[1]}).toString(${a[2]}))]`,
23
+ AppendFloat: (a) =>
24
+ `[...(${a[0]}), ...new TextEncoder().encode(${a[1]}.toFixed(${a[3]} < 0 ? 6 : ${a[3]}))]`,
25
+ };
26
+
27
+ /** @type {ThisType<CodeGen>} */
28
+ export const strconvMethods = {
29
+ _genStrconv(fn, a) {
30
+ const gen = STRCONV_DISPATCH[fn];
31
+ return gen ? gen(a()) : undefined;
32
+ },
33
+ };
@@ -0,0 +1,86 @@
1
+ // CodeGen for Go `strings` package.
2
+
3
+ /** @typedef {import('../index.js').CodeGen} CodeGen */
4
+
5
+ const STRINGS_M1 = {
6
+ ToUpper: "toUpperCase",
7
+ ToLower: "toLowerCase",
8
+ TrimSpace: "trim",
9
+ ToTitle: "toUpperCase",
10
+ };
11
+ const STRINGS_M2 = {
12
+ Contains: "includes",
13
+ HasPrefix: "startsWith",
14
+ HasSuffix: "endsWith",
15
+ Index: "indexOf",
16
+ LastIndex: "lastIndexOf",
17
+ Repeat: "repeat",
18
+ Split: "split",
19
+ Join: "join",
20
+ };
21
+ const STRINGS_DISPATCH = {
22
+ Count: ([s, s2]) =>
23
+ `((s, sep) => sep === "" ? s.length + 1 : s.split(sep).length - 1)(${s}, ${s2})`,
24
+ Replace: ([s, s2, s3]) => `${s}.replace(${s2}, ${s3})`,
25
+ ReplaceAll: ([s, s2, s3]) => `${s}.replaceAll(${s2}, ${s3})`,
26
+ Trim: ([s, s2]) =>
27
+ `${s}.replace(new RegExp(\`^[\${${s2}}]+|[\${${s2}}]+$\`, "g"), "")`,
28
+ TrimPrefix: ([s, s2]) =>
29
+ `((s, pre) => s.startsWith(pre) ? s.slice(pre.length) : s)(${s}, ${s2})`,
30
+ TrimSuffix: ([s, s2]) =>
31
+ `((s, suf) => !suf.length || !s.endsWith(suf) ? s : s.slice(0, -suf.length))(${s}, ${s2})`,
32
+ TrimLeft: ([s, s2]) => `${s}.replace(new RegExp(\`^[\${${s2}}]+\`), "")`,
33
+ TrimRight: ([s, s2]) => `${s}.replace(new RegExp(\`[\${${s2}}]+$\`), "")`,
34
+ EqualFold: ([s, s2]) => `${s}.toLowerCase() === ${s2}.toLowerCase()`,
35
+ Fields: ([s]) => `(${s}).trim() === '' ? [] : (${s}).trim().split(/\\s+/)`,
36
+ Cut: ([s, s2]) =>
37
+ `((s, sep) => { const i = s.indexOf(sep); return i < 0 ? [s, "", false] : [s.slice(0, i), s.slice(i + sep.length), true]; })(${s}, ${s2})`,
38
+ CutPrefix: ([s, s2]) =>
39
+ `(${s}).startsWith(${s2}) ? [(${s}).slice((${s2}).length), true] : [${s}, false]`,
40
+ CutSuffix: ([s, s2]) =>
41
+ `(${s}).endsWith(${s2}) ? [(${s}).slice(0, -(${s2}).length), true] : [${s}, false]`,
42
+ SplitN: ([s, s2, s3]) =>
43
+ `((s, sep, n) => { if (n === 0) return []; if (n < 0) return s.split(sep); const r = []; let cur = s; for (let i = 1; i < n && cur.length; i++) { const j = cur.indexOf(sep); if (j < 0) break; r.push(cur.slice(0, j)); cur = cur.slice(j + sep.length); } r.push(cur); return r; })(${s}, ${s2}, ${s3})`,
44
+ SplitAfter: ([s, s2]) =>
45
+ `((s, sep) => { if (sep === "") return [...s]; const r = []; let cur = s; while (cur.length) { const j = cur.indexOf(sep); if (j < 0) { r.push(cur); break; } r.push(cur.slice(0, j + sep.length)); cur = cur.slice(j + sep.length); } return r; })(${s}, ${s2})`,
46
+ SplitAfterN: ([s, s2, s3]) =>
47
+ `((s, sep, n) => { if (n === 0) return []; if (n < 0 || sep === "") return ((s, sep) => { if (sep === "") return [...s]; const r = []; let cur = s; while (cur.length) { const j = cur.indexOf(sep); if (j < 0) { r.push(cur); break; } r.push(cur.slice(0, j + sep.length)); cur = cur.slice(j + sep.length); } return r; })(s, sep); const r = []; let cur = s; for (let i = 1; i < n && cur.length; i++) { const j = cur.indexOf(sep); if (j < 0) break; r.push(cur.slice(0, j + sep.length)); cur = cur.slice(j + sep.length); } r.push(cur); return r; })(${s}, ${s2}, ${s3})`,
48
+ IndexAny: ([s, s2]) =>
49
+ `((s, chars) => { let m = -1; for (const c of chars) { const i = s.indexOf(c); if (i >= 0 && (m < 0 || i < m)) m = i; } return m; })(${s}, ${s2})`,
50
+ LastIndexAny: ([s, s2]) =>
51
+ `((s, chars) => { let m = -1; for (const c of chars) { const i = s.lastIndexOf(c); if (i > m) m = i; } return m; })(${s}, ${s2})`,
52
+ ContainsAny: ([s, s2]) => `[...(${s2})].some(c => (${s}).includes(c))`,
53
+ ContainsRune: ([s, s2]) => `(${s}).includes(String.fromCodePoint(${s2}))`,
54
+ IndexRune: ([s, s2]) => `(${s}).indexOf(String.fromCodePoint(${s2}))`,
55
+ IndexByte: ([s, s2]) => `(${s}).indexOf(String.fromCharCode(${s2}))`,
56
+ LastIndexByte: ([s, s2]) => `(${s}).lastIndexOf(String.fromCharCode(${s2}))`,
57
+ Map: ([s, s2]) =>
58
+ `[...(${s2})].map(c => String.fromCodePoint((${s})(c.codePointAt(0)))).join("")`,
59
+ Title: ([s]) => `(${s}).replace(/\\b\\w/g, c => c.toUpperCase())`,
60
+ TrimFunc: ([s, s2]) =>
61
+ `((s, f) => { let l = 0, r = s.length; while (l < r && f(s.codePointAt(l))) l++; while (r > l && f(s.codePointAt(r - 1))) r--; return s.slice(l, r); })(${s}, ${s2})`,
62
+ TrimLeftFunc: ([s, s2]) =>
63
+ `((s, f) => { let l = 0; while (l < s.length && f(s.codePointAt(l))) l++; return s.slice(l); })(${s}, ${s2})`,
64
+ TrimRightFunc: ([s, s2]) =>
65
+ `((s, f) => { let r = s.length; while (r > 0 && f(s.codePointAt(r - 1))) r--; return s.slice(0, r); })(${s}, ${s2})`,
66
+ IndexFunc: ([s, s2]) =>
67
+ `((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})`,
68
+ LastIndexFunc: ([s, s2]) =>
69
+ `((s, f) => { for (let i = s.length - 1; i >= 0; i--) { const cp = s.codePointAt(i); if (f(cp)) return i; } return -1; })(${s}, ${s2})`,
70
+ NewReader: ([s]) =>
71
+ `{_src: ${s}, _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.charCodeAt(this._pos + i); this._pos += n; return [n, n === 0 ? "EOF" : null]; }, Len() { return this._src.length - this._pos; }, Reset(s) { this._src = s; this._pos = 0; }}`,
72
+ NewReplacer: (args) =>
73
+ `((...pairs) => { const p = []; for (let i = 0; i < pairs.length; i += 2) p.push([pairs[i], pairs[i+1]]); return { _p: p, Replace(s) { let r = s; for (const [o, n] of this._p) r = r.split(o).join(n); return r; } }; })(${args.join(", ")})`,
74
+ };
75
+
76
+ /** @type {ThisType<CodeGen>} */
77
+ export const stringsMethods = {
78
+ _genStrings(fn, a) {
79
+ const args = a();
80
+ const [s, s2] = args;
81
+ if (STRINGS_M1[fn]) return `${s}.${STRINGS_M1[fn]}()`;
82
+ if (STRINGS_M2[fn]) return `${s}.${STRINGS_M2[fn]}(${s2})`;
83
+ const gen = STRINGS_DISPATCH[fn];
84
+ return gen ? gen(args) : undefined;
85
+ },
86
+ };
@@ -0,0 +1,57 @@
1
+ // CodeGen for Go `time` package — `time.Now`, `time.Since`, etc., plus `*Time` methods.
2
+
3
+ /** @typedef {import('../index.js').CodeGen} CodeGen */
4
+
5
+ const TIME_METHOD_DISPATCH = {
6
+ Year: (r) => `${r}._d.getFullYear()`,
7
+ Month: (r) => `${r}._d.getMonth() + 1`,
8
+ Day: (r) => `${r}._d.getDate()`,
9
+ Hour: (r) => `${r}._d.getHours()`,
10
+ Minute: (r) => `${r}._d.getMinutes()`,
11
+ Second: (r) => `${r}._d.getSeconds()`,
12
+ Weekday: (r) => `${r}._d.getDay()`,
13
+ Unix: (r) => `Math.floor(${r}._d.getTime() / 1000)`,
14
+ UnixMilli: (r) => `${r}._d.getTime()`,
15
+ Add: (r, a) => `{_d: new Date(${r}._d.getTime() + (${a[0]}))}`,
16
+ Sub: (r, a) => `${r}._d.getTime() - (${a[0]})._d.getTime()`,
17
+ Before: (r, a) => `${r}._d < (${a[0]})._d`,
18
+ After: (r, a) => `${r}._d > (${a[0]})._d`,
19
+ Equal: (r, a) => `${r}._d.getTime() === (${a[0]})._d.getTime()`,
20
+ };
21
+
22
+ const TIME_DISPATCH = {
23
+ Now: () => "{_d: new Date()}",
24
+ Since: (a) => `(Date.now() - (${a[0]})._d.getTime())`,
25
+ Sleep: (a) => `await new Promise(r => setTimeout(r, ${a[0]} / 1000000))`,
26
+ Unix: (a) => `{_d: new Date((${a[0]}) * 1000)}`,
27
+ Date: (a) =>
28
+ `{_d: new Date(${a[0]}, ${a[1]} - 1, ${a[2]}, ${a[3]}, ${a[4]}, ${a[5]})}`,
29
+ };
30
+
31
+ /** @type {ThisType<CodeGen>} */
32
+ export const timeMethods = {
33
+ _genTimeMethodCall(method, expr) {
34
+ const recv = expr.func.expr;
35
+ const recvJs = this.genExpr(recv);
36
+ const args = expr.args.map((a) => this.genExpr(a));
37
+ if (method === "Format") {
38
+ this._usesTimeFmt = true;
39
+ return `__timeFmt(${recvJs}._d, ${args[0]})`;
40
+ }
41
+ if (method === "String") {
42
+ this._usesTimeFmt = true;
43
+ return `__timeFmt(${recvJs}._d, "2006-01-02T15:04:05Z07:00")`;
44
+ }
45
+ const gen = TIME_METHOD_DISPATCH[method];
46
+ return gen ? gen(recvJs, args) : undefined;
47
+ },
48
+
49
+ _genTime(fn, a) {
50
+ if (fn === "Parse") {
51
+ this._usesTimeParse = true;
52
+ return `__timeParse(${a()[0]}, ${a()[1]})`;
53
+ }
54
+ const gen = TIME_DISPATCH[fn];
55
+ return gen ? gen(a()) : undefined;
56
+ },
57
+ };
@@ -0,0 +1,25 @@
1
+ // CodeGen for Go `unicode` package.
2
+
3
+ /** @typedef {import('../index.js').CodeGen} CodeGen */
4
+
5
+ /** @type {ThisType<CodeGen>} */
6
+ export const unicodeMethods = {
7
+ _genUnicode(fn, a) {
8
+ const [arg] = a();
9
+ const cp = `String.fromCodePoint(${arg})`;
10
+ const UNICODE_TEST = {
11
+ IsLetter: `/\\p{L}/u.test(${cp})`,
12
+ IsDigit: `/\\p{Nd}/u.test(${cp})`,
13
+ IsSpace: `/\\s/.test(${cp})`,
14
+ IsUpper: `((__c) => __c === __c.toUpperCase() && /\\p{L}/u.test(__c))(${cp})`,
15
+ IsLower: `((__c) => __c === __c.toLowerCase() && /\\p{L}/u.test(__c))(${cp})`,
16
+ IsPunct: `/\\p{P}/u.test(${cp})`,
17
+ IsControl: `/\\p{Cc}/u.test(${cp})`,
18
+ IsPrint: `!/\\p{Cc}/u.test(${cp})`,
19
+ IsGraphic: `!/\\p{Cc}/u.test(${cp})`,
20
+ ToUpper: `${cp}.toUpperCase().codePointAt(0)`,
21
+ ToLower: `${cp}.toLowerCase().codePointAt(0)`,
22
+ };
23
+ return UNICODE_TEST[fn] ?? undefined;
24
+ },
25
+ };
@@ -0,0 +1,26 @@
1
+ // CodeGen for Go `unicode/utf8` package.
2
+
3
+ /** @typedef {import('../index.js').CodeGen} CodeGen */
4
+
5
+ const UTF8_DISPATCH = {
6
+ RuneCountInString: (a) => `[...(${a[0]})].length`,
7
+ RuneLen: (a) =>
8
+ `((r) => r < 0 ? -1 : r <= 0x7F ? 1 : r <= 0x7FF ? 2 : r <= 0xFFFF ? (r >= 0xD800 && r <= 0xDFFF ? -1 : 3) : r <= 0x10FFFF ? 4 : -1)(${a[0]})`,
9
+ ValidString: (a) =>
10
+ `/[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/.test(${a[0]}) === false`,
11
+ ValidRune: (a) =>
12
+ `(${a[0]}) >= 0 && (${a[0]}) <= 0x10FFFF && !((${a[0]}) >= 0xD800 && (${a[0]}) <= 0xDFFF)`,
13
+ DecodeRuneInString: (a) =>
14
+ `((s) => { if (!s) return [0xFFFD, 0]; const cp = s.codePointAt(0); return [cp, cp > 0xFFFF ? 2 : 1]; })(${a[0]})`,
15
+ DecodeLastRuneInString: (a) =>
16
+ `((s) => { if (!s) return [0xFFFD, 0]; const i = s.length > 1 && s.charCodeAt(s.length - 1) >= 0xDC00 && s.charCodeAt(s.length - 1) <= 0xDFFF ? s.length - 2 : s.length - 1; const cp = s.codePointAt(i); return [cp, cp > 0xFFFF ? 2 : 1]; })(${a[0]})`,
17
+ FullRuneInString: (a) => `(${a[0]}).length > 0`,
18
+ };
19
+
20
+ /** @type {ThisType<CodeGen>} */
21
+ export const utf8Methods = {
22
+ _genUtf8(fn, a) {
23
+ const gen = UTF8_DISPATCH[fn];
24
+ return gen ? gen(a()) : undefined;
25
+ },
26
+ };