gofront 0.0.8 → 1.0.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 (51) hide show
  1. package/README.md +88 -12
  2. package/package.json +8 -4
  3. package/src/codegen/expressions.js +520 -1717
  4. package/src/{codegen.js → codegen/index.js} +155 -184
  5. package/src/codegen/runtime.js +151 -0
  6. package/src/codegen/statements.js +305 -296
  7. package/src/codegen/stdlib/builder.js +36 -0
  8. package/src/codegen/stdlib/bytes.js +62 -0
  9. package/src/codegen/stdlib/errors.js +17 -0
  10. package/src/codegen/stdlib/fmt.js +101 -0
  11. package/src/codegen/stdlib/gom.js +152 -0
  12. package/src/codegen/stdlib/html.js +17 -0
  13. package/src/codegen/stdlib/index.js +95 -0
  14. package/src/codegen/stdlib/io.js +33 -0
  15. package/src/codegen/stdlib/maps.js +42 -0
  16. package/src/codegen/stdlib/math.js +53 -0
  17. package/src/codegen/stdlib/os.js +10 -0
  18. package/src/codegen/stdlib/path.js +31 -0
  19. package/src/codegen/stdlib/rand.js +24 -0
  20. package/src/codegen/stdlib/regexp.js +51 -0
  21. package/src/codegen/stdlib/slices.js +48 -0
  22. package/src/codegen/stdlib/sort.js +28 -0
  23. package/src/codegen/stdlib/strconv.js +30 -0
  24. package/src/codegen/stdlib/strings.js +83 -0
  25. package/src/codegen/stdlib/time.js +54 -0
  26. package/src/codegen/stdlib/unicode.js +22 -0
  27. package/src/codegen/stdlib/utf8.js +23 -0
  28. package/src/codegen/templ.js +281 -0
  29. package/src/compiler.js +102 -62
  30. package/src/dts-parser.js +355 -371
  31. package/src/index.js +22 -54
  32. package/src/lexer.js +200 -286
  33. package/src/minifier.js +305 -318
  34. package/src/parser/expressions.js +54 -36
  35. package/src/{parser.js → parser/index.js} +12 -5
  36. package/src/parser/statements.js +29 -35
  37. package/src/parser/types.js +31 -29
  38. package/src/templ-lexer.js +737 -0
  39. package/src/templ-parser.js +235 -0
  40. package/src/tokens.js +109 -0
  41. package/src/typechecker/assignability.js +258 -0
  42. package/src/typechecker/expressions.js +559 -549
  43. package/src/typechecker/index.js +555 -0
  44. package/src/typechecker/resolve.js +421 -0
  45. package/src/typechecker/statements.js +267 -280
  46. package/src/typechecker/stdlib/core.js +592 -0
  47. package/src/typechecker/stdlib/extended.js +332 -0
  48. package/src/typechecker/stdlib.js +9 -1060
  49. package/src/typechecker/termination.js +83 -0
  50. package/src/typechecker/types.js +6 -3
  51. package/src/typechecker.js +0 -1271
@@ -0,0 +1,36 @@
1
+ // CodeGen for `strings.Builder` and `bytes.Buffer` method calls.
2
+
3
+ const BUILDER_STR = {
4
+ WriteString: (b, a) => `(${b}._buf += ${a[0]}, [${a[0]}.length, null])`,
5
+ WriteByte: (b, a) => `(${b}._buf += String.fromCodePoint(${a[0]}))`,
6
+ Write: (b, a) => `(${b}._buf += String.fromCharCode(...${a[0]}))`,
7
+ String: (b) => `${b}._buf`,
8
+ Reset: (b) => `(${b}._buf = "")`,
9
+ };
10
+ const BUILDER_BYTES = {
11
+ WriteString: (b, a) =>
12
+ `(${b}._buf.push(...new TextEncoder().encode(${a[0]})), [${a[0]}.length, null])`,
13
+ WriteByte: (b, a) => `${b}._buf.push(${a[0]})`,
14
+ Write: (b, a) => `(${b}._buf.push(...${a[0]}), [${a[0]}.length, null])`,
15
+ String: (b) => `new TextDecoder().decode(new Uint8Array(${b}._buf))`,
16
+ Reset: (b) => `(${b}._buf = [])`,
17
+ };
18
+ const BUILDER_COMMON = {
19
+ WriteRune: (b, a) => `(${b}._buf += String.fromCodePoint(${a[0]}))`,
20
+ Bytes: (b) => `${b}._buf.slice()`,
21
+ Len: (b) => `${b}._buf.length`,
22
+ Grow: () => "undefined",
23
+ };
24
+
25
+ export const builderMethods = {
26
+ _genBuilderCall(typeName, method, expr) {
27
+ const recv = expr.func.expr;
28
+ const isPtr = recv._type?.kind === "pointer";
29
+ const base = isPtr ? `${this.genExpr(recv)}.value` : this.genExpr(recv);
30
+ const args = expr.args.map((a) => this.genExpr(a));
31
+ const isStr = typeName === "strings.Builder";
32
+ const table = isStr ? BUILDER_STR : BUILDER_BYTES;
33
+ const gen = table[method] ?? BUILDER_COMMON[method];
34
+ return gen ? gen(base, args) : undefined;
35
+ },
36
+ };
@@ -0,0 +1,62 @@
1
+ // CodeGen for Go `bytes` package.
2
+
3
+ const __bs = `(b => String.fromCharCode(...b))`;
4
+ const __sb = `(s => [...s].map(c => c.charCodeAt(0)))`;
5
+
6
+ const BYTES_DISPATCH = {
7
+ Contains: (a) => `${__bs}(${a[0]}).includes(${__bs}(${a[1]}))`,
8
+ HasPrefix: (a) =>
9
+ `((b, p) => { for (let i = 0; i < p.length; i++) if (b[i] !== p[i]) return false; return b.length >= p.length; })(${a[0]}, ${a[1]})`,
10
+ HasSuffix: (a) =>
11
+ `((b, s) => { const off = b.length - s.length; if (off < 0) return false; for (let i = 0; i < s.length; i++) if (b[off + i] !== s[i]) return false; return true; })(${a[0]}, ${a[1]})`,
12
+ Index: (a) => `${__bs}(${a[0]}).indexOf(${__bs}(${a[1]}))`,
13
+ Count: (a) =>
14
+ `((b, sep) => sep.length === 0 ? b.length + 1 : ${__bs}(b).split(${__bs}(sep)).length - 1)(${a[0]}, ${a[1]})`,
15
+ Repeat: (a) => `${__sb}(${__bs}(${a[0]}).repeat(${a[1]}))`,
16
+ Replace: (a) =>
17
+ `((b, o, n, cnt) => { let s = ${__bs}(b), os = ${__bs}(o), ns = ${__bs}(n); if (cnt < 0) return ${__sb}(s.replaceAll(os, ns)); for (let i = 0; i < cnt; i++) s = s.replace(os, ns); return ${__sb}(s); })(${a[0]}, ${a[1]}, ${a[2]}, ${a[3]})`,
18
+ ToUpper: (a) => `${__sb}(${__bs}(${a[0]}).toUpperCase())`,
19
+ ToLower: (a) => `${__sb}(${__bs}(${a[0]}).toLowerCase())`,
20
+ TrimSpace: (a) => `${__sb}(${__bs}(${a[0]}).trim())`,
21
+ Trim: (a) =>
22
+ `${__sb}(${__bs}(${a[0]}).replace(new RegExp(\`^[\${${a[1]}}]+|[\${${a[1]}}]+$\`, "g"), ""))`,
23
+ Equal: (a) =>
24
+ `((a, b) => { if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false; return true; })(${a[0]}, ${a[1]})`,
25
+ Split: (a) => `${__bs}(${a[0]}).split(${__bs}(${a[1]})).map(p => ${__sb}(p))`,
26
+ Join: (a) => `${__sb}(${a[0]}.map(p => ${__bs}(p)).join(${__bs}(${a[1]})))`,
27
+ ReplaceAll: (a) =>
28
+ `((b, o, n) => { const r = []; let i = 0; while (i <= b.length - o.length) { if (o.every((v, j) => b[i + j] === v)) { r.push(...n); i += o.length; } else r.push(b[i++]); } return r.concat(b.slice(i)); })(${a[0]}, ${a[1]}, ${a[2]})`,
29
+ TrimPrefix: (a) =>
30
+ `((b, p) => p.every((v, i) => b[i] === v) ? b.slice(p.length) : b.slice())(${a[0]}, ${a[1]})`,
31
+ TrimSuffix: (a) =>
32
+ `((b, s) => s.length && s.every((v, i) => b[b.length - s.length + i] === v) ? b.slice(0, -s.length) : b.slice())(${a[0]}, ${a[1]})`,
33
+ TrimLeft: (a) =>
34
+ `((b, c) => { let i = 0; while (i < b.length && c.includes(String.fromCharCode(b[i]))) i++; return b.slice(i); })(${a[0]}, ${a[1]})`,
35
+ TrimRight: (a) =>
36
+ `((b, c) => { let i = b.length; while (i > 0 && c.includes(String.fromCharCode(b[i - 1]))) i--; return b.slice(0, i); })(${a[0]}, ${a[1]})`,
37
+ TrimFunc: (a) =>
38
+ `((b, f) => { let l = 0, r = b.length; while (l < r && f(b[l])) l++; while (r > l && f(b[r - 1])) r--; return b.slice(l, r); })(${a[0]}, ${a[1]})`,
39
+ IndexByte: (a) => `(${a[0]}).indexOf(${a[1]})`,
40
+ LastIndex: (a) =>
41
+ `((b, s) => { for (let i = b.length - s.length; i >= 0; i--) if (s.every((v, j) => b[i + j] === v)) return i; return -1; })(${a[0]}, ${a[1]})`,
42
+ LastIndexByte: (a) => `(${a[0]}).lastIndexOf(${a[1]})`,
43
+ Fields: (a) =>
44
+ `((b) => { const s = String.fromCharCode(...b).trim(); return s === '' ? [] : s.split(/\\s+/).map(w => [...w].map(c => c.charCodeAt(0))); })(${a[0]})`,
45
+ Cut: (a) =>
46
+ `((b, sep) => { for (let i = 0; i <= b.length - sep.length; i++) if (sep.every((v, j) => b[i + j] === v)) return [b.slice(0, i), b.slice(i + sep.length), true]; return [b.slice(), [], false]; })(${a[0]}, ${a[1]})`,
47
+ ContainsAny: (a) =>
48
+ `[...(${a[1]})].some(c => (${a[0]}).includes(c.charCodeAt(0)))`,
49
+ ContainsRune: (a) => `(${a[0]}).includes(${a[1]})`,
50
+ Map: (a) => `(${a[1]}).map(v => (${a[0]})(v))`,
51
+ SplitN: (a) =>
52
+ `((b, sep, n) => { if (n === 0) return []; if (n < 0) return ((b, sep) => { const r = []; let i = 0; while (i <= b.length) { const j = b.findIndex((_, k) => k >= i && sep.every((v, l) => b[k + l] === sep[l])); if (j < 0 || j >= b.length) break; r.push(b.slice(i, j)); i = j + sep.length; } r.push(b.slice(i)); return r; })(b, sep); const r = []; let i = 0; for (let c = 1; c < n; c++) { const j = b.findIndex((_, k) => k >= i && sep.every((v, l) => b[k + l] === sep[l])); if (j < 0) break; r.push(b.slice(i, j)); i = j + sep.length; } r.push(b.slice(i)); return r; })(${a[0]}, ${a[1]}, ${a[2]})`,
53
+ NewReader: (a) =>
54
+ `{_src: ${a[0]}, _pos: 0, Read(p) { const n = Math.min(p.length, this._src.length - this._pos); for (let i = 0; i < n; i++) p[i] = this._src[this._pos + i]; this._pos += n; return [n, n === 0 ? "EOF" : null]; }, Len() { return this._src.length - this._pos; }, Reset(b) { this._src = b; this._pos = 0; }}`,
55
+ };
56
+
57
+ export const bytesMethods = {
58
+ _genBytes(fn, a) {
59
+ const gen = BYTES_DISPATCH[fn];
60
+ return gen ? gen(a()) : undefined;
61
+ },
62
+ };
@@ -0,0 +1,17 @@
1
+ // CodeGen for Go `errors` package.
2
+
3
+ export const errorsMethods = {
4
+ _genErrors(fn, a) {
5
+ const args = a();
6
+ if (fn === "New") {
7
+ this._usesError = true;
8
+ return `__error(${args[0]})`;
9
+ }
10
+ if (fn === "Is") {
11
+ this._usesErrorIs = true;
12
+ return `__errorIs(${args[0]}, ${args[1]})`;
13
+ }
14
+ if (fn === "Unwrap") return `(${args[0]}?._cause ?? null)`;
15
+ return undefined;
16
+ },
17
+ };
@@ -0,0 +1,101 @@
1
+ // CodeGen for Go `fmt` package — installed onto CodeGen.prototype via stdlibGenMethods.
2
+
3
+ const _SSCAN_LOOP =
4
+ `let n = 0; for (let i = 0; i < ptrs.length && i < tokens.length; i++) { ` +
5
+ `const t = tokens[i]; const p = ptrs[i]; ` +
6
+ `if (typeof p.value === "number") p.value = Number(t); ` +
7
+ `else if (typeof p.value === "boolean") p.value = t === "true"; ` +
8
+ `else p.value = t; n++; }`;
9
+
10
+ export const fmtMethods = {
11
+ _genFmt(fn, _a, expr) {
12
+ const fmtArgs = expr.args.map((e) => this.genExpr(e)).join(", ");
13
+ switch (fn) {
14
+ case "Sprintf":
15
+ this._usesSprintf = true;
16
+ return `__sprintf(${fmtArgs})`;
17
+ case "Errorf": {
18
+ this._usesSprintf = true;
19
+ this._usesError = true;
20
+ const fmtStr = expr.args[0];
21
+ if (fmtStr?.kind === "BasicLit" && fmtStr.value?.includes("%w")) {
22
+ const lastArg = this.genExpr(expr.args[expr.args.length - 1]);
23
+ return `__error(__sprintf(${fmtArgs}), ${lastArg})`;
24
+ }
25
+ return `__error(__sprintf(${fmtArgs}))`;
26
+ }
27
+ case "Printf":
28
+ case "Print":
29
+ this._usesSprintf = true;
30
+ return `process?.stdout?.write(__sprintf(${fmtArgs}))`;
31
+ case "Println":
32
+ this._usesSprintf = true;
33
+ return `console.log(__sprintf(${fmtArgs}))`;
34
+ case "Fprintf":
35
+ case "Fprintln":
36
+ case "Fprint":
37
+ return this._genFmtFprint(fn, expr);
38
+ case "Sscan": {
39
+ const strArg = this.genExpr(expr.args[0]);
40
+ const restArgs = expr.args
41
+ .slice(1)
42
+ .map((e) => this.genExpr(e))
43
+ .join(", ");
44
+ return `((str, ...ptrs) => { const tokens = str.trim().split(/\\s+/).filter(Boolean); ${_SSCAN_LOOP} return [n, n < ptrs.length ? "unexpected EOF" : null]; })(${strArg}, ${restArgs})`;
45
+ }
46
+ case "Sscanln": {
47
+ const strArg = this.genExpr(expr.args[0]);
48
+ const restArgs = expr.args
49
+ .slice(1)
50
+ .map((e) => this.genExpr(e))
51
+ .join(", ");
52
+ 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})`;
53
+ }
54
+ case "Sscanf": {
55
+ const strArg = this.genExpr(expr.args[0]);
56
+ const fmtArg = this.genExpr(expr.args[1]);
57
+ const restArgs = expr.args
58
+ .slice(2)
59
+ .map((e) => this.genExpr(e))
60
+ .join(", ");
61
+ 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})`;
62
+ }
63
+ default:
64
+ return undefined;
65
+ }
66
+ },
67
+
68
+ _genFmtFprint(fn, expr) {
69
+ this._usesSprintf = true;
70
+ const writerArg = expr.args[0];
71
+ const rest = expr.args.slice(1);
72
+ const restJs = rest.map((e) => this.genExpr(e)).join(", ");
73
+ const writerType = writerArg._type;
74
+ const targetTypeName =
75
+ writerType?.name ??
76
+ (writerType?.kind === "pointer" ? writerType.base?.name : null);
77
+ const sprintfCall = this._buildFprintSprintfCall(fn, rest.length, restJs);
78
+ if (targetTypeName === "strings.Builder") {
79
+ const w = this.genExpr(writerArg);
80
+ const buf =
81
+ writerType?.kind === "pointer" ? `${w}.value._buf` : `${w}._buf`;
82
+ return `(${buf} += ${sprintfCall})`;
83
+ }
84
+ if (targetTypeName === "bytes.Buffer") {
85
+ const w = this.genExpr(writerArg);
86
+ const base = writerType?.kind === "pointer" ? `${w}.value` : w;
87
+ return `((__b,__s)=>{ __b._buf.push(...new TextEncoder().encode(__s)); })(${base}, ${sprintfCall})`;
88
+ }
89
+ // Generic io.Writer fallback — call .WriteString if available
90
+ const w = this.genExpr(writerArg);
91
+ return `${w}.WriteString(${sprintfCall})`;
92
+ },
93
+
94
+ _buildFprintSprintfCall(fn, argc, restJs) {
95
+ if (fn === "Fprintf") return `__sprintf(${restJs})`;
96
+ const sep = fn === "Fprintln" ? " " : "";
97
+ const suffix = fn === "Fprintln" ? "\\n" : "";
98
+ const fmt = Array(argc).fill("%v").join(sep) + suffix;
99
+ return `__sprintf("${fmt}", ${restJs})`;
100
+ },
101
+ };
@@ -0,0 +1,152 @@
1
+ // CodeGen for the GoFront-built-in `gom` DOM-rendering package.
2
+
3
+ const GOM_ELEMENT_TAGS = {
4
+ Div: "div",
5
+ Section: "section",
6
+ Article: "article",
7
+ Aside: "aside",
8
+ Header: "header",
9
+ Footer: "footer",
10
+ Main: "main",
11
+ Nav: "nav",
12
+ Figure: "figure",
13
+ H1: "h1",
14
+ H2: "h2",
15
+ H3: "h3",
16
+ H4: "h4",
17
+ H5: "h5",
18
+ H6: "h6",
19
+ Span: "span",
20
+ A: "a",
21
+ Strong: "strong",
22
+ Em: "em",
23
+ Code: "code",
24
+ Pre: "pre",
25
+ Small: "small",
26
+ Mark: "mark",
27
+ P: "p",
28
+ Br: "br",
29
+ Hr: "hr",
30
+ Ul: "ul",
31
+ Ol: "ol",
32
+ Li: "li",
33
+ Dl: "dl",
34
+ Dt: "dt",
35
+ Dd: "dd",
36
+ Form: "form",
37
+ Input: "input",
38
+ Button: "button",
39
+ Textarea: "textarea",
40
+ Select: "select",
41
+ Option: "option",
42
+ Label: "label",
43
+ Fieldset: "fieldset",
44
+ Legend: "legend",
45
+ Img: "img",
46
+ Video: "video",
47
+ Audio: "audio",
48
+ Canvas: "canvas",
49
+ Table: "table",
50
+ Thead: "thead",
51
+ Tbody: "tbody",
52
+ Tfoot: "tfoot",
53
+ Tr: "tr",
54
+ Th: "th",
55
+ Td: "td",
56
+ };
57
+ const GOM_ATTR_HELPERS = {
58
+ For: "for",
59
+ Name: "name",
60
+ Value: "value",
61
+ Target: "target",
62
+ Rel: "rel",
63
+ Alt: "alt",
64
+ Title: "title",
65
+ Lang: "lang",
66
+ Action: "action",
67
+ Method: "method",
68
+ AutoComplete: "autocomplete",
69
+ Draggable: "draggable",
70
+ Role: "role",
71
+ StyleAttr: "style",
72
+ AriaLabel: "aria-label",
73
+ };
74
+ const GOM_BOOL_ATTRS = {
75
+ Disabled: "disabled",
76
+ Checked: "checked",
77
+ Selected: "selected",
78
+ Readonly: "readonly",
79
+ };
80
+ const GOM_PROP_SETTERS = {
81
+ Class: "className",
82
+ Type: "type",
83
+ Href: "href",
84
+ Src: "src",
85
+ Placeholder: "placeholder",
86
+ };
87
+
88
+ export const gomMethods = {
89
+ _genGom(fn, expr) {
90
+ const a = () =>
91
+ expr.args.map((e) =>
92
+ e._spread ? `...${this.genExpr(e)}` : this.genExpr(e),
93
+ );
94
+
95
+ if (GOM_ELEMENT_TAGS[fn]) {
96
+ const tag = GOM_ELEMENT_TAGS[fn];
97
+ const args = a();
98
+ if (args.length === 0)
99
+ return `(()=>({Mount(p){const e=document.createElement("${tag}");p.appendChild(e);}}))()`;
100
+ return (
101
+ `((...c)=>({Mount(p){const e=document.createElement("${tag}");c.forEach(n=>n?.Mount?.(e));p.appendChild(e);}}))` +
102
+ `(${args.join(",")})`
103
+ );
104
+ }
105
+
106
+ if (GOM_ATTR_HELPERS[fn]) {
107
+ const [v] = a();
108
+ return `((v)=>({Mount(e){e.setAttribute("${GOM_ATTR_HELPERS[fn]}",v)}}))(${v})`;
109
+ }
110
+
111
+ if (GOM_BOOL_ATTRS[fn])
112
+ return `({Mount(e){e.setAttribute("${GOM_BOOL_ATTRS[fn]}","")}})`;
113
+
114
+ const args = a();
115
+
116
+ if (GOM_PROP_SETTERS[fn])
117
+ return `((v)=>({Mount(e){e.${GOM_PROP_SETTERS[fn]}=v}}))(${args[0]})`;
118
+
119
+ switch (fn) {
120
+ case "El": {
121
+ const [tag, ...children] = args;
122
+ if (children.length === 0)
123
+ return `((t)=>({Mount(p){const e=document.createElement(t);p.appendChild(e);}})) (${tag})`;
124
+ return (
125
+ `((t,...c)=>({Mount(p){const e=document.createElement(t);c.forEach(n=>n?.Mount?.(e));p.appendChild(e);}}))` +
126
+ `(${tag},${children.join(",")})`
127
+ );
128
+ }
129
+ case "Text": {
130
+ const [s] = args;
131
+ return `((s)=>({Mount(p){p.appendChild(document.createTextNode(s))}}))(${s})`;
132
+ }
133
+ case "Attr": {
134
+ const [name, value] = args;
135
+ return `((n,v)=>({Mount(e){e.setAttribute(n,v)}}))(${name},${value})`;
136
+ }
137
+ case "DataAttr":
138
+ return `((k,v)=>({Mount(e){e.setAttribute("data-"+k,v)}}))(${args[0]},${args[1]})`;
139
+ case "If":
140
+ return `((c,n)=>c?n:{Mount(){}})(${args[0]},${args[1]})`;
141
+ case "Map":
142
+ return `((s,f)=>{const c=s.map(f);return{_items:c,Mount(p){c.forEach(n=>n.Mount(p))}}})(${args[0]},${args[1]})`;
143
+ case "Style":
144
+ return `((s)=>({Mount(p){const e=document.createElement("style");e.textContent=s;p.appendChild(e);}})) (${args[0]})`;
145
+ case "Mount":
146
+ return `((sel,n)=>{const e=document.querySelector(sel);e.innerHTML="";n.Mount(e)})(${args[0]},${args[1]})`;
147
+ case "MountTo":
148
+ return `((sel,n)=>{const e=document.querySelector(sel);n.Mount(e)})(${args[0]},${args[1]})`;
149
+ }
150
+ return undefined;
151
+ },
152
+ };
@@ -0,0 +1,17 @@
1
+ // CodeGen for Go `html` package.
2
+
3
+ export const htmlMethods = {
4
+ _genHtml(fn, a) {
5
+ switch (fn) {
6
+ case "EscapeString": {
7
+ const [s] = a();
8
+ return `${s}.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&#34;").replace(/'/g,"&#39;")`;
9
+ }
10
+ case "UnescapeString": {
11
+ const [s] = a();
12
+ return `${s}.replace(/&#39;/g,"'").replace(/&#34;/g,'"').replace(/&gt;/g,">").replace(/&lt;/g,"<").replace(/&amp;/g,"&")`;
13
+ }
14
+ }
15
+ return undefined;
16
+ },
17
+ };
@@ -0,0 +1,95 @@
1
+ // CodeGen stdlib call generation — installed as a mixin on CodeGen.prototype.
2
+ // One file per Go package under ./stdlib/. This index merges them.
3
+
4
+ import { builderMethods } from "./builder.js";
5
+ import { bytesMethods } from "./bytes.js";
6
+ import { errorsMethods } from "./errors.js";
7
+ import { fmtMethods } from "./fmt.js";
8
+ import { gomMethods } from "./gom.js";
9
+ import { htmlMethods } from "./html.js";
10
+ import { ioMethods } from "./io.js";
11
+ import { mapsMethods } from "./maps.js";
12
+ import { mathMethods } from "./math.js";
13
+ import { osMethods } from "./os.js";
14
+ import { pathMethods } from "./path.js";
15
+ import { randMethods } from "./rand.js";
16
+ import { regexpMethods } from "./regexp.js";
17
+ import { slicesMethods } from "./slices.js";
18
+ import { sortMethods } from "./sort.js";
19
+ import { strconvMethods } from "./strconv.js";
20
+ import { stringsMethods } from "./strings.js";
21
+ import { timeMethods } from "./time.js";
22
+ import { unicodeMethods } from "./unicode.js";
23
+ import { utf8Methods } from "./utf8.js";
24
+
25
+ // Stdlib namespace → handler method name. Used by _genStdlibCall to dispatch
26
+ // dynamically without creating static call edges.
27
+ const STDLIB_METHOD_MAP = {
28
+ fmt: "_genFmt",
29
+ strings: "_genStrings",
30
+ bytes: "_genBytes",
31
+ strconv: "_genStrconv",
32
+ sort: "_genSort",
33
+ math: "_genMath",
34
+ unicode: "_genUnicode",
35
+ os: "_genOs",
36
+ errors: "_genErrors",
37
+ time: "_genTime",
38
+ regexp: "_genRegexp",
39
+ slices: "_genSlices",
40
+ maps: "_genMaps",
41
+ html: "_genHtml",
42
+ io: "_genIo",
43
+ rand: "_genRand",
44
+ utf8: "_genUtf8",
45
+ path: "_genPath",
46
+ };
47
+
48
+ const dispatchMethods = {
49
+ typeComment(typeNode) {
50
+ if (!typeNode) return "unknown";
51
+ switch (typeNode.kind) {
52
+ case "TypeName":
53
+ return typeNode.name;
54
+ case "SliceType":
55
+ return `[]${this.typeComment(typeNode.elem)}`;
56
+ case "MapType":
57
+ return `map[${this.typeComment(typeNode.key)}]${this.typeComment(typeNode.value)}`;
58
+ default:
59
+ return typeNode.kind;
60
+ }
61
+ },
62
+
63
+ // Dispatch table for stdlib namespace calls (pkg.Func → inline JS).
64
+ // Returns the generated JS string, or undefined if not handled.
65
+ _genStdlibCall(ns, fn, expr) {
66
+ const a = () => expr.args.map((e) => this.genExpr(e));
67
+ if (ns === "gom") return this._genGom(fn, expr);
68
+ const method = STDLIB_METHOD_MAP[ns];
69
+ return method ? this[method](fn, a, expr) : undefined;
70
+ },
71
+ };
72
+
73
+ export const stdlibGenMethods = {
74
+ ...builderMethods,
75
+ ...bytesMethods,
76
+ ...errorsMethods,
77
+ ...fmtMethods,
78
+ ...gomMethods,
79
+ ...htmlMethods,
80
+ ...ioMethods,
81
+ ...mapsMethods,
82
+ ...mathMethods,
83
+ ...osMethods,
84
+ ...pathMethods,
85
+ ...randMethods,
86
+ ...regexpMethods,
87
+ ...slicesMethods,
88
+ ...sortMethods,
89
+ ...strconvMethods,
90
+ ...stringsMethods,
91
+ ...timeMethods,
92
+ ...unicodeMethods,
93
+ ...utf8Methods,
94
+ ...dispatchMethods,
95
+ };
@@ -0,0 +1,33 @@
1
+ // CodeGen for Go `io` package.
2
+
3
+ export const ioMethods = {
4
+ _genIo(fn, _a, expr) {
5
+ switch (fn) {
6
+ case "WriteString": {
7
+ const writerArg = expr.args[0];
8
+ const writerType = writerArg._type;
9
+ const typeName =
10
+ writerType?.name ??
11
+ (writerType?.kind === "pointer" ? writerType.base?.name : null);
12
+ const w = this.genExpr(writerArg);
13
+ const s = this.genExpr(expr.args[1]);
14
+ const isPtr = writerType?.kind === "pointer";
15
+ const base = isPtr ? `${w}.value` : w;
16
+ if (typeName === "strings.Builder") {
17
+ return `((b,s) => { b._buf += s; return [s.length, null]; })(${base}, ${s})`;
18
+ }
19
+ if (typeName === "bytes.Buffer") {
20
+ return `((b,s) => { b._buf.push(...new TextEncoder().encode(s)); return [s.length, null]; })(${base}, ${s})`;
21
+ }
22
+ // Generic: auto-dereference pointer, then dispatch on concrete writer type.
23
+ // strings.Builder has { _buf: string }, bytes.Buffer has { _buf: [] }.
24
+ 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})`;
25
+ }
26
+ case "ReadAll": {
27
+ const r = this.genExpr(expr.args[0]);
28
+ 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})`;
29
+ }
30
+ }
31
+ return undefined;
32
+ },
33
+ };
@@ -0,0 +1,42 @@
1
+ // CodeGen for Go `maps` package.
2
+
3
+ export const mapsMethods = {
4
+ _genMaps(fn, a) {
5
+ if (fn === "Equal") {
6
+ this._usesEqual = true;
7
+ const [a1, b1] = a();
8
+ return `__equal(${a1}, ${b1})`;
9
+ }
10
+ switch (fn) {
11
+ case "Keys": {
12
+ const [m] = a();
13
+ return `Object.keys(${m})`;
14
+ }
15
+ case "Values": {
16
+ const [m] = a();
17
+ return `Object.values(${m})`;
18
+ }
19
+ case "Clone": {
20
+ const [m] = a();
21
+ return `({...${m}})`;
22
+ }
23
+ case "Copy": {
24
+ const [dst, src] = a();
25
+ return `Object.assign(${dst}, ${src})`;
26
+ }
27
+ case "EqualFunc": {
28
+ const [m1, m2, eq] = a();
29
+ return `((a, b, f) => { const ka = Object.keys(a); if (ka.length !== Object.keys(b).length) return false; return ka.every(k => k in b && f(a[k], b[k])); })(${m1}, ${m2}, ${eq})`;
30
+ }
31
+ case "Delete": {
32
+ const [m, k] = a();
33
+ return `(delete ${m}[${k}], undefined)`;
34
+ }
35
+ case "DeleteFunc": {
36
+ const [m, fn2] = a();
37
+ return `Object.keys(${m}).forEach(k => { if (${fn2}(k, ${m}[k])) delete ${m}[k]; })`;
38
+ }
39
+ }
40
+ return undefined;
41
+ },
42
+ };
@@ -0,0 +1,53 @@
1
+ // CodeGen for Go `math` package.
2
+
3
+ const MATH1 = {
4
+ Abs: "abs",
5
+ Floor: "floor",
6
+ Ceil: "ceil",
7
+ Round: "round",
8
+ Sqrt: "sqrt",
9
+ Cbrt: "cbrt",
10
+ Log: "log",
11
+ Log2: "log2",
12
+ Log10: "log10",
13
+ Sin: "sin",
14
+ Cos: "cos",
15
+ Tan: "tan",
16
+ Atan: "atan",
17
+ Asin: "asin",
18
+ Acos: "acos",
19
+ Exp: "exp",
20
+ Trunc: "trunc",
21
+ };
22
+ const MATH2 = {
23
+ Pow: "pow",
24
+ Min: "min",
25
+ Max: "max",
26
+ Atan2: "atan2",
27
+ Hypot: "hypot",
28
+ };
29
+ const MATH_EXTRA = {
30
+ Mod: ([x, y]) => `${x} % ${y}`,
31
+ Inf: ([x]) => `(${x} >= 0 ? Infinity : -Infinity)`,
32
+ IsNaN: ([x]) => `Number.isNaN(${x})`,
33
+ IsInf: ([x, y]) =>
34
+ `(${y} > 0 ? ${x} === Infinity : ${y} < 0 ? ${x} === -Infinity : !Number.isFinite(${x}))`,
35
+ NaN: () => "NaN",
36
+ Exp2: ([x]) => `Math.pow(2, ${x})`,
37
+ Signbit: ([x]) => `(${x} < 0 || Object.is(${x}, -0))`,
38
+ Copysign: ([x, y]) =>
39
+ `(Math.abs(${x}) * (${y} < 0 || Object.is(${y}, -0) ? -1 : 1))`,
40
+ Dim: ([x, y]) => `Math.max(${x} - ${y}, 0)`,
41
+ Remainder: ([x, y]) => `(${x} - Math.round(${x} / ${y}) * ${y})`,
42
+ };
43
+
44
+ export const mathMethods = {
45
+ _genMath(fn, a) {
46
+ const args = a();
47
+ const [x, y] = args;
48
+ if (MATH1[fn]) return `Math.${MATH1[fn]}(${x})`;
49
+ if (MATH2[fn]) return `Math.${MATH2[fn]}(${x}, ${y})`;
50
+ const gen = MATH_EXTRA[fn];
51
+ return gen ? gen(args) : undefined;
52
+ },
53
+ };
@@ -0,0 +1,10 @@
1
+ // CodeGen for Go `os` package.
2
+
3
+ export const osMethods = {
4
+ _genOs(fn, a) {
5
+ const args = a();
6
+ if (fn === "Exit") return `process.exit(${args[0]})`;
7
+ if (fn === "Getenv") return `(process.env[${args[0]}] ?? "")`;
8
+ return undefined;
9
+ },
10
+ };
@@ -0,0 +1,31 @@
1
+ // CodeGen for Go `path` package.
2
+
3
+ const PATH_DISPATCH = {
4
+ Base: (a) =>
5
+ `((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]})`,
6
+ Dir: (a) =>
7
+ `((p) => { const i = p.lastIndexOf("/"); if (i < 0) return "."; if (i === 0) return "/"; return p.slice(0, i); })(${a[0]})`,
8
+ Ext: (a) =>
9
+ `((p) => { const b = p.slice(p.lastIndexOf("/") + 1); const i = b.lastIndexOf("."); return i <= 0 ? "" : b.slice(i); })(${a[0]})`,
10
+ IsAbs: (a) => `(${a[0]}).startsWith("/")`,
11
+ Split: (a) =>
12
+ `((p) => { const i = p.lastIndexOf("/"); return i < 0 ? ["", p] : [p.slice(0, i + 1), p.slice(i + 1)]; })(${a[0]})`,
13
+ Match: (a) =>
14
+ `((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]})`,
15
+ };
16
+
17
+ export const pathMethods = {
18
+ _genPath(fn, a, expr) {
19
+ if (fn === "Join") {
20
+ this._usesPathClean = true;
21
+ const allArgs = expr.args.map((e) => this.genExpr(e)).join(", ");
22
+ return `__pathClean([${allArgs}].filter(x => x !== "").join("/"))`;
23
+ }
24
+ if (fn === "Clean") {
25
+ this._usesPathClean = true;
26
+ return `__pathClean(${a()[0]})`;
27
+ }
28
+ const gen = PATH_DISPATCH[fn];
29
+ return gen ? gen(a()) : undefined;
30
+ },
31
+ };