gofront 1.8.0 → 1.9.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 (178) hide show
  1. package/README.md +3 -3
  2. package/package.json +6 -5
  3. package/src/backend/js/expressions.js +1157 -408
  4. package/src/backend/js/index.js +327 -153
  5. package/src/backend/js/natives.js +383 -0
  6. package/src/backend/js/runtime.js +559 -2552
  7. package/src/backend/js/statements.js +670 -158
  8. package/src/backend/js/stdlib/index.js +45 -93
  9. package/src/backend/js/templ.js +32 -45
  10. package/src/backend/js/type-info.js +298 -19
  11. package/src/backend/shared/fixed-float.js +20 -0
  12. package/src/backend/shared/fmt-types.js +91 -170
  13. package/src/backend/shared/host-unicode.js +36 -0
  14. package/src/backend/wasm/boundary.js +490 -965
  15. package/src/backend/wasm/emit-builtins.js +884 -256
  16. package/src/backend/wasm/emit-exprs.js +185 -77
  17. package/src/backend/wasm/emit-maps.js +17 -367
  18. package/src/backend/wasm/emit-shared.js +4 -1
  19. package/src/backend/wasm/emit-stmts.js +524 -240
  20. package/src/backend/wasm/emit.js +176 -38
  21. package/src/backend/wasm/globals.js +48 -8
  22. package/src/backend/wasm/glue.js +2 -4
  23. package/src/backend/wasm/index.js +44 -530
  24. package/src/backend/wasm/method-expr.js +12 -1
  25. package/src/backend/wasm/module-emitter.js +299 -770
  26. package/src/backend/wasm/monomorph.js +139 -8
  27. package/src/backend/wasm/natives.js +600 -0
  28. package/src/backend/wasm/prescan.js +5 -153
  29. package/src/backend/wasm/prune-funcs.js +89 -0
  30. package/src/backend/wasm/stdlib/index.js +2 -32
  31. package/src/backend/wasm/types.js +97 -20
  32. package/src/backend/wasm/variadic.js +9 -4
  33. package/src/cli/cli-core.js +5 -1
  34. package/src/cli/test-runner.js +115 -342
  35. package/src/compiler.js +113 -130
  36. package/src/lexer/lexer.js +106 -11
  37. package/src/lexer/templ-lexer.js +61 -18
  38. package/src/lexer/tokens.js +1 -0
  39. package/src/link/stdlib.js +355 -132
  40. package/src/link/type-names.js +204 -0
  41. package/src/link/wasm.js +30 -6
  42. package/src/lower/bounds.js +153 -0
  43. package/src/lower/captures.js +92 -33
  44. package/src/lower/embedding.js +62 -5
  45. package/src/lower/errors-as.js +196 -0
  46. package/src/lower/fmt-formatters.js +929 -0
  47. package/src/lower/functions.js +225 -7
  48. package/src/lower/gen-types.js +293 -0
  49. package/src/lower/index.js +14 -2
  50. package/src/lower/json-codecs.js +334 -245
  51. package/src/lower/ownership.js +25 -7
  52. package/src/lower/reachability.js +69 -51
  53. package/src/lower/walk.js +12 -0
  54. package/src/parser/declarations.js +30 -5
  55. package/src/parser/expressions.js +111 -57
  56. package/src/parser/statements.js +108 -0
  57. package/src/parser/templ.js +44 -5
  58. package/src/parser/types.js +12 -0
  59. package/src/resolver.js +1 -2
  60. package/src/typechecker/assignability.js +214 -19
  61. package/src/typechecker/const-fold.js +70 -27
  62. package/src/typechecker/constants.js +156 -8
  63. package/src/typechecker/expressions.js +490 -108
  64. package/src/typechecker/index.js +346 -42
  65. package/src/typechecker/init-order.js +136 -40
  66. package/src/typechecker/operand-text.js +41 -0
  67. package/src/typechecker/resolve.js +490 -65
  68. package/src/typechecker/statements.js +288 -27
  69. package/src/typechecker/stdlib/excluded.js +9 -5
  70. package/src/typechecker/stdlib/index.js +25 -9
  71. package/src/typechecker/termination.js +10 -1
  72. package/src/typechecker/types.js +287 -575
  73. package/stdlib/bytes/buffer.go +479 -0
  74. package/stdlib/bytes/bytes.go +1010 -0
  75. package/stdlib/bytes/reader.go +161 -0
  76. package/stdlib/context/context.go +115 -0
  77. package/stdlib/crypto/rand/rand.go +34 -0
  78. package/stdlib/crypto/sha256/sha256.go +249 -0
  79. package/stdlib/encoding/base64/base64.go +331 -0
  80. package/stdlib/encoding/binary/binary.go +332 -0
  81. package/stdlib/encoding/hex/hex.go +140 -0
  82. package/stdlib/encoding/json/json.go +62 -0
  83. package/stdlib/errors/errors.go +174 -0
  84. package/stdlib/fmt/errors.go +110 -0
  85. package/stdlib/fmt/format.go +732 -0
  86. package/stdlib/fmt/print.go +1232 -0
  87. package/stdlib/gom/gom.go +293 -0
  88. package/stdlib/html/html.go +251 -0
  89. package/stdlib/internal/fmtrt/fmtrt.go +163 -0
  90. package/stdlib/internal/jsonrt/dec.go +171 -38
  91. package/stdlib/internal/jsonrt/enc.go +186 -36
  92. package/stdlib/internal/jsonrt/scanner.go +17 -8
  93. package/stdlib/io/io.go +157 -1
  94. package/stdlib/maps/maps.go +131 -0
  95. package/stdlib/math/bits/bits.go +507 -0
  96. package/stdlib/math/extra.go +16 -14
  97. package/stdlib/math/math.go +439 -0
  98. package/stdlib/math/rand/rand.go +297 -0
  99. package/stdlib/os/os.go +93 -0
  100. package/stdlib/path/filepath/filepath.go +47 -0
  101. package/stdlib/path/path.go +394 -0
  102. package/stdlib/regexp/regexp.go +231 -0
  103. package/stdlib/slices/slices.go +526 -0
  104. package/stdlib/slices/sort.go +209 -0
  105. package/stdlib/slices/zsort_cmp.go +480 -0
  106. package/stdlib/slices/zsort_ordered.go +482 -0
  107. package/stdlib/sort/sort.go +391 -452
  108. package/stdlib/sort/zsort_func.go +480 -0
  109. package/stdlib/sort/zsort_iface.go +480 -0
  110. package/stdlib/strconv/float.go +1699 -0
  111. package/stdlib/strconv/isprint.go +752 -0
  112. package/stdlib/strconv/quote.go +235 -50
  113. package/stdlib/strconv/strconv.go +616 -0
  114. package/stdlib/strings/builder.go +95 -0
  115. package/stdlib/strings/reader.go +163 -0
  116. package/stdlib/strings/replacer.go +102 -0
  117. package/stdlib/strings/strings.go +807 -0
  118. package/stdlib/sync/sync.go +268 -0
  119. package/stdlib/testing/async_js.go +61 -0
  120. package/stdlib/testing/benchmark.go +297 -0
  121. package/stdlib/testing/testing.go +523 -0
  122. package/stdlib/time/duration.go +233 -0
  123. package/stdlib/time/format.go +745 -0
  124. package/stdlib/time/parse.go +790 -0
  125. package/stdlib/time/sleep_js.go +63 -0
  126. package/stdlib/time/time.go +834 -0
  127. package/stdlib/unicode/unicode.go +141 -3
  128. package/stdlib/unicode/utf8/utf8.go +464 -0
  129. package/src/backend/js/fmt-runtime.js +0 -573
  130. package/src/backend/js/stdlib/base64.js +0 -12
  131. package/src/backend/js/stdlib/binary.js +0 -102
  132. package/src/backend/js/stdlib/bits.js +0 -119
  133. package/src/backend/js/stdlib/builder.js +0 -98
  134. package/src/backend/js/stdlib/bytes.js +0 -368
  135. package/src/backend/js/stdlib/errors.js +0 -45
  136. package/src/backend/js/stdlib/fmt.js +0 -517
  137. package/src/backend/js/stdlib/gom.js +0 -155
  138. package/src/backend/js/stdlib/hex.js +0 -17
  139. package/src/backend/js/stdlib/html.js +0 -20
  140. package/src/backend/js/stdlib/io.js +0 -137
  141. package/src/backend/js/stdlib/json.js +0 -1167
  142. package/src/backend/js/stdlib/maps.js +0 -37
  143. package/src/backend/js/stdlib/math.js +0 -85
  144. package/src/backend/js/stdlib/os.js +0 -13
  145. package/src/backend/js/stdlib/path.js +0 -48
  146. package/src/backend/js/stdlib/rand.js +0 -32
  147. package/src/backend/js/stdlib/regexp.js +0 -54
  148. package/src/backend/js/stdlib/sha256.js +0 -12
  149. package/src/backend/js/stdlib/shared.js +0 -17
  150. package/src/backend/js/stdlib/simd.js +0 -34
  151. package/src/backend/js/stdlib/slices.js +0 -107
  152. package/src/backend/js/stdlib/sort.js +0 -30
  153. package/src/backend/js/stdlib/strconv.js +0 -79
  154. package/src/backend/js/stdlib/strings.js +0 -301
  155. package/src/backend/js/stdlib/sync.js +0 -13
  156. package/src/backend/js/stdlib/testing.js +0 -41
  157. package/src/backend/js/stdlib/time.js +0 -152
  158. package/src/backend/js/stdlib/unicode.js +0 -25
  159. package/src/backend/js/stdlib/utf8.js +0 -26
  160. package/src/backend/wasm/stdlib/bytes.js +0 -6716
  161. package/src/backend/wasm/stdlib/core.js +0 -10278
  162. package/src/backend/wasm/stdlib/io.js +0 -3578
  163. package/src/backend/wasm/stdlib/packages.js +0 -2402
  164. package/src/backend/wasm/stdlib/pure.js +0 -720
  165. package/src/backend/wasm/stdlib/time.js +0 -2229
  166. package/src/typechecker/stdlib/core.js +0 -1079
  167. package/src/typechecker/stdlib/extended.js +0 -1210
  168. package/stdlib/bytes/iter.go +0 -192
  169. package/stdlib/bytes/search.go +0 -240
  170. package/stdlib/bytes/split.go +0 -218
  171. package/stdlib/errors/overlay.go +0 -12
  172. package/stdlib/maps/iter.go +0 -65
  173. package/stdlib/slices/extra.go +0 -73
  174. package/stdlib/slices/iter.go +0 -113
  175. package/stdlib/strings/extra.go +0 -35
  176. package/stdlib/strings/iter.go +0 -122
  177. package/stdlib/sync/extra.go +0 -105
  178. package/stdlib/unicode/utf8/bytes.go +0 -239
@@ -1,517 +0,0 @@
1
- // CodeGen for Go `fmt` package — installed onto CodeGen.prototype via stdlibGenMethods.
2
-
3
- import {
4
- fmtDescHasFloat,
5
- fmtDescIsSeq,
6
- fmtTypeDesc,
7
- fmtWantsTypes,
8
- structOwnFields,
9
- } from "../../shared/fmt-types.js";
10
-
11
- /** @typedef {import('../index.js').CodeGen} CodeGen */
12
-
13
- const _SSCAN_LOOP =
14
- `let n = 0, err = null; for (let i = 0; i < ptrs.length && i < tokens.length; i++) { ` +
15
- `const item = tokens[i]; const t = typeof item === "object" && item !== null ? item.t : item; const verb = item?.verb; const p = ptrs[i]; ` +
16
- `if (verb === "%c") { p.value = t.codePointAt ? t.codePointAt(0) : t; } ` +
17
- `else if (verb === "%x" || verb === "%X") { const clean = t.replace(/^0[xX]/, ""); const v = parseInt(clean, 16); if (isNaN(v)) { err = __error("expected hex number"); break; } p.value = typeof p.value === "bigint" ? BigInt("0x" + clean) : v; } ` +
18
- `else if (verb === "%o") { const clean = t.replace(/^0[oO]?/, ""); const v = parseInt(clean, 8); if (isNaN(v)) { err = __error("expected octal number"); break; } p.value = typeof p.value === "bigint" ? BigInt("0o" + clean) : v; } ` +
19
- `else if (verb === "%b") { const clean = t.replace(/^0[bB]/, ""); const v = parseInt(clean, 2); if (isNaN(v)) { err = __error("expected binary number"); break; } p.value = typeof p.value === "bigint" ? BigInt("0b" + clean) : v; } ` +
20
- `else if (typeof p.value === "number") { const v = Number(t); if (Number.isNaN(v) || !/^[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[eE][+-]?\\d+)?$/.test(t)) { err = __error("expected number"); break; } p.value = v; } ` +
21
- `else if (typeof p.value === "bigint") { try { if (!/^[+-]?\\d+$/.test(t)) throw 1; p.value = BigInt(t); } catch { err = __error("expected integer"); break; } } ` +
22
- `else if (typeof p.value === "boolean") { const tl = String(t).toLowerCase(); if (tl === "true" || tl === "1" || tl === "t") p.value = true; else if (tl === "false" || tl === "0" || tl === "f") p.value = false; else { err = __error("expected boolean"); break; } } ` +
23
- `else p.value = t; n++; }`;
24
-
25
- const FMT_METHODS = ["Error", "String"];
26
- const isExportedName = (n) => /^\p{Lu}/u.test(n);
27
- // Descriptor of a struct value whose class has a pointer-receiver Error/String:
28
- // a value element or field must not be taken for a pointer because an earlier
29
- // &x tagged the same object (see isPointer in __sprintf).
30
- const FMT_STRUCT_VALUE = "{ sv: 1 }";
31
-
32
- /** @type {ThisType<CodeGen>} */
33
- export const fmtMethods = {
34
- // ── Stringer/error dispatch metadata (read by __sprintf) ─────────────
35
- //
36
- // Named non-struct values are raw numbers/strings/arrays inside slices,
37
- // maps and struct fields, and a struct and a pointer to it share one class.
38
- // The type is therefore carried two ways, both only where a method can be
39
- // called: a descriptor of the container's element types, attached when a
40
- // slice/array/map is converted to an interface (static type passing, see
41
- // __ifd), and per-class metadata for struct fields (__ff) and for
42
- // pointer-receiver Error/String methods (__pr).
43
-
44
- // JS source of the fmt descriptor for static type `t`, or null when no
45
- // value of the type needs one:
46
- // { b: Class, n } a raw value of a named type with a value-receiver
47
- // Error/String; Class boxes it, n: numeric (map keys)
48
- // { sv: 1 } a struct value with a pointer-receiver Error/String
49
- // { e } elements of a slice or array
50
- // { k, v } keys and values of a map
51
- // { np: obj } a *T whose Error/String has a pointer receiver: obj
52
- // stands in for a nil element (see _fmtNilPtrOperand)
53
- // { m: 1, ... } a map that is not boxed itself (a struct field or an
54
- // element): the object map carries no marker of its own
55
- // `bare`: the value is the operand being boxed (a map is then marked by
56
- // the boxing itself).
57
- _fmtDesc(t, seen = new Set(), bare = true) {
58
- t = this.checker?.resolveType?.(t) ?? t;
59
- if (!t || seen.has(t)) return null;
60
- const next = new Set(seen).add(t);
61
- if (t.kind === "named") return this._fmtNamedDesc(t, next, bare);
62
- if (t.kind === "slice" || t.kind === "array") {
63
- const e = this._fmtDesc(t.elem, next, false);
64
- return e ? `{ e: ${e} }` : null;
65
- }
66
- if (t.kind === "struct") return this._fmtAnonStructDesc(t, next);
67
- if (t.kind === "pointer") {
68
- if (bare) return null;
69
- const np = this._fmtNilPtrOperand(t);
70
- return np ? `{ np: ${np} }` : null;
71
- }
72
- if (t.kind !== "map") return null;
73
- const parts = [
74
- ["k", this._fmtDesc(t.key, next, false)],
75
- ["v", this._fmtDesc(t.value, next, false)],
76
- ].filter(([, d]) => d);
77
- if (!bare) parts.unshift(["m", "1"]);
78
- return parts.length
79
- ? `{ ${parts.map(([n, d]) => `${n}: ${d}`).join(", ")} }`
80
- : null;
81
- },
82
-
83
- // An anonymous struct has no class to carry field descriptors: { ff } holds
84
- // them, keyed by field name.
85
- _fmtAnonStructDesc(st, seen) {
86
- const fields = [];
87
- for (const [fname, ftype] of structOwnFields(st)) {
88
- const desc = this._fmtDesc(ftype, seen, false);
89
- if (desc) fields.push(`${JSON.stringify(fname)}: ${desc}`);
90
- }
91
- return fields.length > 0 ? `{ ff: { ${fields.join(", ")} } }` : null;
92
- },
93
-
94
- _fmtNamedDesc(t, seen, bare = true) {
95
- const u = this.checker?.resolveType?.(t.underlying) ?? t.underlying;
96
- const info = this._namedBoxInfo(t);
97
- if (
98
- info &&
99
- FMT_METHODS.some((m) => info.methods.get(m)?._ptrRecv === false)
100
- ) {
101
- const numeric = u?.kind === "basic" && /^(u?int|float)/.test(u.name);
102
- return `{ b: ${info.cls}, n: ${numeric ? 1 : 0} }`;
103
- }
104
- if (u?.kind === "struct" && this._fmtHasPtrMethod(u))
105
- return FMT_STRUCT_VALUE;
106
- if (!u || u.kind === "struct" || u.kind === "interface") return null;
107
- return this._fmtDesc(u, seen, bare);
108
- },
109
-
110
- // Whether struct `st` has a pointer-receiver Error/String, declared or
111
- // promoted from an embedded struct.
112
- _fmtHasPtrMethod(st, seen = new Set()) {
113
- if (seen.has(st)) return false;
114
- seen.add(st);
115
- if (FMT_METHODS.some((m) => st.methods?.get(m)?._ptrRecv)) return true;
116
- return (st._embeds ?? []).some((raw) => {
117
- const inner = (raw.kind === "pointer" ? raw.base : raw).underlying;
118
- return inner?.kind === "struct" && this._fmtHasPtrMethod(inner, seen);
119
- });
120
- },
121
-
122
- // Error/String promoted from embedded interface fields, as { method: field }.
123
- _fmtPromoted(st, methodDecls) {
124
- const out = {};
125
- for (const f of st._structFields ?? []) {
126
- if (!f.embedded) continue;
127
- const t = this.checker?.resolveType?.(f.type) ?? f.type;
128
- const it = t?.kind === "named" ? t.underlying : t;
129
- const key = (f.astType?.name ?? t?.name ?? "").split(".").pop();
130
- if (it?.kind !== "interface" || !key) continue;
131
- for (const mn of FMT_METHODS) {
132
- const m = it.methods?.get(mn);
133
- if (!m || m.params?.length > 0 || out[mn]) continue;
134
- if (methodDecls.some((d) => d.name === mn)) continue;
135
- out[mn] = key;
136
- }
137
- }
138
- return out;
139
- },
140
-
141
- // Per-class fmt metadata of a struct: which of Error/String have a pointer
142
- // receiver, and the descriptors of the exported fields that hold raw
143
- // Stringer values.
144
- _genFmtClassMeta(name, methodDecls) {
145
- const st = this.checker?.types.get(name)?.underlying;
146
- if (st?.kind !== "struct") return;
147
- const ptrRecv = FMT_METHODS.filter((mn) =>
148
- this._fmtPtrRecv(st, methodDecls, mn),
149
- );
150
- if (ptrRecv.length > 0)
151
- this.line(
152
- `Object.defineProperty(${name}.prototype, "__pr", { value: ${JSON.stringify(ptrRecv)} });`,
153
- );
154
- const promoted = this._fmtPromoted(st, methodDecls);
155
- if (Object.keys(promoted).length > 0)
156
- this.line(
157
- `Object.defineProperty(${name}.prototype, "__pe", { value: ${JSON.stringify(promoted)} });`,
158
- );
159
- const fields = [];
160
- const own = structOwnFields(st);
161
- // The class also carries a copy of every promoted field (see
162
- // _promotedPath); fmt lists only the fields the struct declares.
163
- if (own.length < st.fields.size)
164
- this.line(
165
- `Object.defineProperty(${name}.prototype, "__fk", { value: ${JSON.stringify(own.map(([n]) => n))} });`,
166
- );
167
- for (const [fname, ftype] of own) {
168
- const desc = this._fmtDesc(ftype, new Set(), false);
169
- // Unexported fields get no method dispatch, only the value marker
170
- // (and the map marker).
171
- if (
172
- desc &&
173
- (isExportedName(fname) ||
174
- desc === FMT_STRUCT_VALUE ||
175
- /\bm: 1\b/.test(desc))
176
- )
177
- fields.push(`${fname}: ${desc}`);
178
- }
179
- // A thunk: the descriptors name classes declared further down.
180
- if (fields.length > 0)
181
- this.line(
182
- `Object.defineProperty(${name}.prototype, "__ff", { value: () => ({ ${fields.join(", ")} }) });`,
183
- );
184
- },
185
-
186
- // Whether method `mn` of struct `st` has a pointer receiver: declared on it,
187
- // or promoted from an embedded struct (an embedded pointer promotes every
188
- // method to the value's method set).
189
- _fmtPtrRecv(st, methodDecls, mn) {
190
- const decl = methodDecls.find((d) => d.name === mn);
191
- if (decl) return Boolean(decl.recvPointer);
192
- for (const raw of st._embeds ?? []) {
193
- const isPtr = raw.kind === "pointer";
194
- const m = (isPtr ? raw.base : raw).underlying?.methods?.get(mn);
195
- if (m) return !isPtr && Boolean(m._ptrRecv);
196
- }
197
- return false;
198
- },
199
-
200
- // A nil `*T` whose Error/String has a pointer receiver still calls the method
201
- // (Go does; a panic in it, usually a nil dereference, prints <nil>). The JS
202
- // source of a stand-in for the nil pointer, or null when `t` is not such a
203
- // pointer. Only operands whose static type is the pointer are covered.
204
- _fmtNilPtrOperand(t) {
205
- t = this.checker?.resolveType?.(t) ?? t;
206
- if (t?.kind !== "pointer") return null;
207
- const base = this.checker?.resolveType?.(t.base) ?? t.base;
208
- const st =
209
- this.checker?.resolveType?.(base?.underlying) ?? base?.underlying;
210
- if (base?.kind !== "named" || st?.kind !== "struct" || !base.name)
211
- return null;
212
- for (const mn of FMT_METHODS) {
213
- const m = st.methods?.get(mn) ?? base.methods?.get(mn);
214
- // Instantiated generic methods are copies without _ptrRecv.
215
- const generic = base.typeArgs
216
- ? this.checker?.types.get(base.name)?._generic
217
- : null;
218
- const ptrRecv = m?._ptrRecv ?? generic?.methods?.get(mn)?._ptrRecv;
219
- if (!m || !ptrRecv || m.params?.length > 0) continue;
220
- const cls = this._dequalify(base.name).replace(/\[.*$/, "");
221
- if (cls.includes(".")) return null;
222
- return `{ ${mn}() { try { return ${cls}.prototype.${mn}.call(null); } catch (e) { return "<nil>"; } }, __p: true, __nilp: true }`;
223
- }
224
- return null;
225
- },
226
-
227
- // `typed`: the format string needs operand types (`%T`, `%#v`, EXTRA, see
228
- // fmtWantsTypes), so the operand travels with its static type as
229
- // `__ft(value, descriptor)`; operands of interface type carry their dynamic
230
- // type and stay bare.
231
- _fmtArgJs(e, typed = false) {
232
- // `xs...` passes each element as its own operand.
233
- if (e?._spread) return `...(${this.genExpr(e)} ?? [])`;
234
- // A multi-value call (`f()` returning a tuple) passes every result.
235
- if (e?._type?.kind === "tuple") return this._fmtTupleJs(e);
236
- const nilOperand = this._fmtNilPtrOperand(e?._type);
237
- if (nilOperand) return `(${this.genExpr(e)} ?? ${nilOperand})`;
238
- const js = this.genExpr(e);
239
- // An operand of a type parameter type: the type argument knows how fmt
240
- // should see it (a Stringer named type is boxed, a slice gets its elements).
241
- const tpf =
242
- e?._type?.kind === "typeParam"
243
- ? this._typeParamZeroFactory(e._type.name)
244
- : null;
245
- if (tpf) return `(${tpf}.fb ?? ${tpf}.b ?? ((__v) => __v))(${js})`;
246
- const base =
247
- e?._type?.kind === "named" ? (e._type.underlying ?? e._type) : e?._type;
248
- if (e?._type?.name === "time.Duration") {
249
- this.useHelper("duration");
250
- this.useHelper("sprintf");
251
- return `__ft(${js}, { k: "named", n: "time.Duration" })`;
252
- }
253
- const desc = fmtTypeDesc(
254
- e?._type,
255
- (t) => this.checker?.resolveType?.(t) ?? t,
256
- );
257
- if ((typed || fmtDescHasFloat(desc)) && desc && desc.k !== "i") {
258
- this.useHelper("sprintf");
259
- return `__ft(${js}, ${JSON.stringify(desc)})`;
260
- }
261
- return this._fmtNilValue(base, js, false);
262
- },
263
-
264
- // A nil slice or map operand prints as `[]` / `map[]`: coalesce the null
265
- // to an empty value. Shared by the single-operand and the tuple path.
266
- // `unboxed`: the map still needs its marker (the caller boxes the result).
267
- _fmtNilValue(base, js, unboxed = true) {
268
- if (base?.kind === "slice") return `(${js} ?? [])`;
269
- if (unboxed && base?.kind === "map") return `(${js} ?? {})`;
270
- return js;
271
- },
272
-
273
- // `js` (a value of static type `t`) boxed as converting it to an `any` does,
274
- // with the same boxing the single-operand path gets from the checker
275
- // (_markIfaceBox): named types with methods, pointers, slices, maps, structs
276
- // and the fmt descriptor of Stringer elements.
277
- _fmtBoxValue(js, t) {
278
- const resolve = (x) => this.checker?.resolveType?.(x) ?? x;
279
- let base = resolve(t);
280
- if (base?.kind === "named") base = resolve(base.underlying);
281
- const meta = this.checker?._ifaceBoxMeta?.(t);
282
- if (meta?.type)
283
- return this._genNamedIfaceBox(js, meta.type, meta.box === "named_ptr");
284
- let out = this._fmtNilValue(base, js);
285
- if (meta) out = this._ifaceBoxWrap(out, meta.box, meta.ptrFields);
286
- const desc = this._fmtDesc(t);
287
- return desc ? this._fmtDescWrap(out, desc) : out;
288
- },
289
-
290
- // The results of a multi-value call as separate operands. Each result is
291
- // boxed as if it were assigned to an `any`, so pointers print as `&{...}`
292
- // and floats keep their width.
293
- _fmtTupleJs(e) {
294
- const resolve = (t) => this.checker?.resolveType?.(t) ?? t;
295
- const parts = e._type.types.map((t, i) => {
296
- const boxed = this._fmtBoxValue(`__t[${i}]`, t);
297
- const desc = fmtTypeDesc(t, resolve);
298
- if (fmtDescHasFloat(desc) && desc.k !== "i") {
299
- this.useHelper("sprintf");
300
- return `__ft(${boxed}, ${JSON.stringify(desc)})`;
301
- }
302
- return boxed;
303
- });
304
- return `...((__t) => [${parts.join(", ")}])(${this.genExpr(e)})`;
305
- },
306
-
307
- // The operands of a Printf-style call whose format is args[fmtIdx].
308
- _fmtFormatArgsJs(args, fmtIdx) {
309
- const lit = args[fmtIdx];
310
- const spread = args.some((e) => e?._spread);
311
- const resolve = (t) => this.checker?.resolveType?.(t) ?? t;
312
- const seqArgs = args
313
- .slice(fmtIdx + 1)
314
- .some((e) => fmtDescIsSeq(fmtTypeDesc(e?._type, resolve)));
315
- const typed =
316
- lit?.kind === "BasicLit" &&
317
- fmtWantsTypes(lit.value, spread ? -1 : args.length - fmtIdx - 1, seqArgs);
318
- if (typed) this.useHelper("sprintf");
319
- return args.map((e, idx) =>
320
- idx < fmtIdx
321
- ? this.genExpr(e)
322
- : idx === fmtIdx
323
- ? this.genExpr(e)
324
- : this._fmtArgJs(e, typed),
325
- );
326
- },
327
-
328
- _genFmt(fn, _a, expr) {
329
- const fmtArgs = ["Sprintf", "Printf", "Errorf"].includes(fn)
330
- ? this._fmtFormatArgsJs(expr.args, 0).join(", ")
331
- : "";
332
- switch (fn) {
333
- case "Sprintf":
334
- this.useHelper("sprintf");
335
- return `__sprintf(${fmtArgs})`;
336
- case "Sprint":
337
- case "Sprintln":
338
- this.useHelper("sprint");
339
- return `__sprint(${fn === "Sprintln"}${expr.args.map((e) => `, ${this._fmtArgJs(e)}`).join("")})`;
340
- case "Append":
341
- case "Appendln":
342
- case "Appendf": {
343
- this.useHelper("sprint");
344
- const [dst, ...rest] = expr.args;
345
- const restJs = (
346
- fn === "Appendf"
347
- ? this._fmtFormatArgsJs(rest, 0)
348
- : rest.map((e) => this._fmtArgJs(e))
349
- ).join(", ");
350
- const str =
351
- fn === "Appendf"
352
- ? `__sprintf(${restJs})`
353
- : `__sprint(${fn === "Appendln"}${restJs ? `, ${restJs}` : ""})`;
354
- // Like append: write in place only when the whole result fits in
355
- // dst's spare capacity, otherwise copy into one fresh array and
356
- // leave dst's backing array untouched (never chunk the write).
357
- this.useHelper("append");
358
- return `((d, s) => { const e = new TextEncoder().encode(s); if (d == null && e.length === 0) return null; const r = d ?? new Uint8Array(0); const n = r.length + e.length; const c = __tcap.get(r); if (c !== undefined && n <= c) { const v = new Uint8Array(r.buffer, r.byteOffset, n); v.set(e, r.length); if (c > n) __tcap.set(v, c); return v; } const v = new Uint8Array(n); v.set(r); v.set(e, r.length); return v; })(${this.genExpr(dst)}, ${str})`;
359
- }
360
- case "Errorf": {
361
- this.useHelper("sprintf");
362
- this.useHelper("error");
363
- const fmtStr = expr.args[0];
364
- if (fmtStr?.kind === "BasicLit" && fmtStr.value?.includes("%w")) {
365
- const lastArg = this.genExpr(expr.args[expr.args.length - 1]);
366
- return `__error(__sprintf(${fmtArgs}), ${lastArg})`;
367
- }
368
- return `__error(__sprintf(${fmtArgs}))`;
369
- }
370
- case "Printf":
371
- this.useHelper("sprintf");
372
- return this._genStdoutWrite(`__sprintf(${fmtArgs})`);
373
- case "Print":
374
- this.useHelper("sprintf");
375
- this.useHelper("sprint");
376
- return this._genStdoutWrite(
377
- `__sprint(false${expr.args.map((e) => `, ${this._fmtArgJs(e)}`).join("")})`,
378
- );
379
- case "Println":
380
- this.useHelper("sprintf");
381
- // console.log supplies the trailing newline.
382
- return `console.log(${this._genPrintOperands(expr, " ", "")})`;
383
- case "Fprintf":
384
- case "Fprintln":
385
- case "Fprint":
386
- return this._genFmtFprint(fn, expr);
387
- case "Sscan": {
388
- this.useHelper("error");
389
- const strArg = this.genExpr(expr.args[0]);
390
- const restArgs = expr.args
391
- .slice(1)
392
- .map((e) => (e._spread ? `...${this.genExpr(e)}` : this.genExpr(e)))
393
- .join(", ");
394
- return `((str, ...ptrs) => { const tokens = str.trim().split(/\\s+/).filter(Boolean); ${_SSCAN_LOOP} return [n, err ? err : (n < ptrs.length ? __error("unexpected EOF") : null)]; })(${strArg}, ${restArgs})`;
395
- }
396
- case "Sscanln": {
397
- this.useHelper("error");
398
- const strArg = this.genExpr(expr.args[0]);
399
- const restArgs = expr.args
400
- .slice(1)
401
- .map((e) => (e._spread ? `...${this.genExpr(e)}` : this.genExpr(e)))
402
- .join(", ");
403
- return `((str, ...ptrs) => { const tokens = str.split("\\n")[0].trim().split(/\\s+/).filter(Boolean); ${_SSCAN_LOOP} return [n, err ? err : (n < ptrs.length ? __error("unexpected EOF") : null)]; })(${strArg}, ${restArgs})`;
404
- }
405
- case "Sscanf": {
406
- this.useHelper("error");
407
- const strArg = this.genExpr(expr.args[0]);
408
- const fmtArg = this.genExpr(expr.args[1]);
409
- const restArgs = expr.args
410
- .slice(2)
411
- .map((e) => (e._spread ? `...${this.genExpr(e)}` : this.genExpr(e)))
412
- .join(", ");
413
- return (
414
- `((str, fmt, ...ptrs) => { ` +
415
- `const s = String(str); const f = String(fmt); ` +
416
- `let si = 0, fi = 0; const tokens = []; let parseErr = null; ` +
417
- `while (fi < f.length) { ` +
418
- `if (/\\s/.test(f[fi])) { ` +
419
- `while (fi < f.length && /\\s/.test(f[fi])) fi++; ` +
420
- `while (si < s.length && /\\s/.test(s[si])) si++; ` +
421
- `continue; ` +
422
- `} ` +
423
- `if (f[fi] === "%") { ` +
424
- `if (fi + 1 < f.length && f[fi + 1] === "%") { ` +
425
- `if (s[si] !== "%") { parseErr = __error("input does not match format"); break; } ` +
426
- `si++; fi += 2; continue; ` +
427
- `} ` +
428
- `const vm = f.slice(fi).match(/^%[vdsfqtxXbcoeEfFgG]/); ` +
429
- `if (vm) { ` +
430
- `const verb = vm[0]; fi += verb.length; ` +
431
- `if (verb !== "%c") { while (si < s.length && /\\s/.test(s[si])) si++; } ` +
432
- `if (si >= s.length) break; ` +
433
- `let tokRe = /^\\S+/; ` +
434
- `if (verb === "%d" || verb === "%i") tokRe = /^[+-]?\\d+/; ` +
435
- `else if (verb === "%o") tokRe = /^[+-]?(?:0[oO])?[0-7]+/; ` +
436
- `else if (verb === "%b") tokRe = /^[+-]?(?:0[bB])?[01]+/; ` +
437
- `else if (verb === "%f" || verb === "%F" || verb === "%e" || verb === "%E" || verb === "%g" || verb === "%G") tokRe = /^[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[eE][+-]?\\d+)?/; ` +
438
- `else if (verb === "%t") tokRe = /^(?:true|false|1|0|t|f|T|F|TRUE|FALSE)/; ` +
439
- `else if (verb === "%x" || verb === "%X") tokRe = /^[+-]?(?:0x)?[0-9a-fA-F]+/; ` +
440
- `else if (verb === "%c") tokRe = /^[\\s\\S]/; ` +
441
- `const m = s.slice(si).match(tokRe); ` +
442
- `if (!m) { parseErr = __error("input does not match format"); break; } ` +
443
- `tokens.push({ t: m[0], verb }); si += m[0].length; continue; ` +
444
- `} ` +
445
- `} ` +
446
- `if (si >= s.length) break; ` +
447
- `if (s[si] !== f[fi]) { parseErr = __error("input does not match format"); break; } ` +
448
- `si++; fi++; ` +
449
- `} ` +
450
- `${_SSCAN_LOOP} ` +
451
- `return [n, parseErr || err || (n < ptrs.length ? __error("unexpected EOF") : null)]; ` +
452
- `})(${strArg}, ${fmtArg}, ${restArgs})`
453
- );
454
- }
455
- default:
456
- return undefined;
457
- }
458
- },
459
-
460
- _genFmtFprint(fn, expr) {
461
- this.useHelper("sprintf");
462
- const writerArg = expr.args[0];
463
- const rest = expr.args.slice(1);
464
- const restJs = (
465
- fn === "Fprintf"
466
- ? this._fmtFormatArgsJs(rest, 0)
467
- : rest.map((e) => this._fmtArgJs(e))
468
- ).join(", ");
469
- const writerType = writerArg._type;
470
- const targetTypeName =
471
- writerType?.name ??
472
- (writerType?.kind === "pointer" ? writerType.base?.name : null);
473
- const sprintfCall = this._buildFprintSprintfCall(fn, rest.length, restJs);
474
- if (targetTypeName === "strings.Builder") {
475
- const w = this.genExpr(writerArg);
476
- const base = this._unboxWriter(w);
477
- return `((__b, __s) => { __b._buf += __s; return [__s.length, null]; })(${base}, ${sprintfCall})`;
478
- }
479
- if (targetTypeName === "bytes.Buffer") {
480
- const w = this.genExpr(writerArg);
481
- const base = this._unboxWriter(w);
482
- return `((__b, __s) => { const __bytes = new TextEncoder().encode(__s); for (let i = 0; i < __bytes.length; i++) __b._buf.push(__bytes[i]); return [__bytes.length, null]; })(${base}, ${sprintfCall})`;
483
- }
484
- // Generic io.Writer fallback — call .WriteString if available
485
- const w = this.genExpr(writerArg);
486
- return `((__w, __s) => typeof __w.WriteString === "function" ? __w.WriteString(__s) : __w.Write(new TextEncoder().encode(__s)))(${w}, ${sprintfCall})`;
487
- },
488
-
489
- _genStdoutWrite(strJs) {
490
- return `((__s) => (typeof process !== "undefined" && process?.stdout?.write ? process.stdout.write(__s) : console.log(__s)))(${strJs})`;
491
- },
492
-
493
- // Formats Print/Println operands with %v so the first operand is never
494
- // mistaken for a format string.
495
- _genPrintOperands(expr, sep, suffix) {
496
- const argc = expr.args.length;
497
- if (argc === 0) return JSON.stringify(suffix);
498
- if (expr.args.some((e) => e._spread || e._type?.kind === "tuple")) {
499
- // The operand count is only known at run time: join with Sprint's rules.
500
- this.useHelper("sprint");
501
- const joined = `__sprint(${sep === " "}, ${expr.args.map((e) => this._fmtArgJs(e)).join(", ")})`;
502
- return sep === " " ? `${joined}.slice(0, -1)` : joined;
503
- }
504
- const fmt = Array(argc).fill("%v").join(sep) + suffix;
505
- const args = expr.args.map((e) => this._fmtArgJs(e)).join(", ");
506
- return `__sprintf(${JSON.stringify(fmt)}, ${args})`;
507
- },
508
-
509
- _buildFprintSprintfCall(fn, argc, restJs) {
510
- if (fn === "Fprintf") return `__sprintf(${restJs})`;
511
- if (argc === 0) return fn === "Fprintln" ? '"\\n"' : '""';
512
- const sep = fn === "Fprintln" ? " " : "";
513
- const suffix = fn === "Fprintln" ? "\\n" : "";
514
- const fmt = Array(argc).fill("%v").join(sep) + suffix;
515
- return `__sprintf("${fmt}", ${restJs})`;
516
- },
517
- };
@@ -1,155 +0,0 @@
1
- // CodeGen for the GoFront-built-in `gom` DOM-rendering package.
2
-
3
- /** @typedef {import('../index.js').CodeGen} CodeGen */
4
-
5
- const GOM_ELEMENT_TAGS = {
6
- Div: "div",
7
- Section: "section",
8
- Article: "article",
9
- Aside: "aside",
10
- Header: "header",
11
- Footer: "footer",
12
- Main: "main",
13
- Nav: "nav",
14
- Figure: "figure",
15
- H1: "h1",
16
- H2: "h2",
17
- H3: "h3",
18
- H4: "h4",
19
- H5: "h5",
20
- H6: "h6",
21
- Span: "span",
22
- A: "a",
23
- Strong: "strong",
24
- Em: "em",
25
- Code: "code",
26
- Pre: "pre",
27
- Small: "small",
28
- Mark: "mark",
29
- P: "p",
30
- Br: "br",
31
- Hr: "hr",
32
- Ul: "ul",
33
- Ol: "ol",
34
- Li: "li",
35
- Dl: "dl",
36
- Dt: "dt",
37
- Dd: "dd",
38
- Form: "form",
39
- Input: "input",
40
- Button: "button",
41
- Textarea: "textarea",
42
- Select: "select",
43
- Option: "option",
44
- Label: "label",
45
- Fieldset: "fieldset",
46
- Legend: "legend",
47
- Img: "img",
48
- Video: "video",
49
- Audio: "audio",
50
- Canvas: "canvas",
51
- Table: "table",
52
- Thead: "thead",
53
- Tbody: "tbody",
54
- Tfoot: "tfoot",
55
- Tr: "tr",
56
- Th: "th",
57
- Td: "td",
58
- };
59
- const GOM_ATTR_HELPERS = {
60
- For: "for",
61
- Name: "name",
62
- Value: "value",
63
- Target: "target",
64
- Rel: "rel",
65
- Alt: "alt",
66
- Title: "title",
67
- Lang: "lang",
68
- Action: "action",
69
- Method: "method",
70
- AutoComplete: "autocomplete",
71
- Draggable: "draggable",
72
- Role: "role",
73
- StyleAttr: "style",
74
- AriaLabel: "aria-label",
75
- };
76
- const GOM_BOOL_ATTRS = {
77
- Disabled: "disabled",
78
- Checked: "checked",
79
- Selected: "selected",
80
- Readonly: "readonly",
81
- };
82
- const GOM_PROP_SETTERS = {
83
- Class: "className",
84
- Type: "type",
85
- Href: "href",
86
- Src: "src",
87
- Placeholder: "placeholder",
88
- };
89
-
90
- /** @type {ThisType<CodeGen>} */
91
- export const gomMethods = {
92
- _genGom(fn, expr) {
93
- const a = () =>
94
- expr.args.map((e) =>
95
- e._spread ? `...${this.genExpr(e)}` : this.genExpr(e),
96
- );
97
-
98
- if (GOM_ELEMENT_TAGS[fn]) {
99
- const tag = GOM_ELEMENT_TAGS[fn];
100
- const args = a();
101
- if (args.length === 0)
102
- return `(()=>({Mount(p){const e=document.createElement("${tag}");p.appendChild(e);}}))()`;
103
- return (
104
- `((...c)=>({Mount(p){const e=document.createElement("${tag}");c.forEach(n=>n?.Mount?.(e));p.appendChild(e);}}))` +
105
- `(${args.join(",")})`
106
- );
107
- }
108
-
109
- if (GOM_ATTR_HELPERS[fn]) {
110
- const [v] = a();
111
- return `((v)=>({Mount(e){e.setAttribute("${GOM_ATTR_HELPERS[fn]}",v)}}))(${v})`;
112
- }
113
-
114
- if (GOM_BOOL_ATTRS[fn])
115
- return `({Mount(e){e.setAttribute("${GOM_BOOL_ATTRS[fn]}","")}})`;
116
-
117
- const args = a();
118
-
119
- if (GOM_PROP_SETTERS[fn])
120
- return `((v)=>({Mount(e){e.${GOM_PROP_SETTERS[fn]}=v}}))(${args[0]})`;
121
-
122
- switch (fn) {
123
- case "El": {
124
- const [tag, ...children] = args;
125
- if (children.length === 0)
126
- return `((t)=>({Mount(p){const e=document.createElement(t);p.appendChild(e);}})) (${tag})`;
127
- return (
128
- `((t,...c)=>({Mount(p){const e=document.createElement(t);c.forEach(n=>n?.Mount?.(e));p.appendChild(e);}}))` +
129
- `(${tag},${children.join(",")})`
130
- );
131
- }
132
- case "Text": {
133
- const [s] = args;
134
- return `((s)=>({Mount(p){p.appendChild(document.createTextNode(s))}}))(${s})`;
135
- }
136
- case "Attr": {
137
- const [name, value] = args;
138
- return `((n,v)=>({Mount(e){e.setAttribute(n,v)}}))(${name},${value})`;
139
- }
140
- case "DataAttr":
141
- return `((k,v)=>({Mount(e){e.setAttribute("data-"+k,v)}}))(${args[0]},${args[1]})`;
142
- case "If":
143
- return `((c,n)=>c?n:{Mount(){}})(${args[0]},${args[1]})`;
144
- case "Map":
145
- return `((s,f)=>{const c=s.map(f);return{_items:c,Mount(p){c.forEach(n=>n.Mount(p))}}})(${args[0]},${args[1]})`;
146
- case "Style":
147
- return `((s)=>({Mount(p){const e=document.createElement("style");e.textContent=s;p.appendChild(e);}})) (${args[0]})`;
148
- case "Mount":
149
- return `((sel,n,r)=>{const e=document.querySelector(sel);e.innerHTML="";n.Mount(e,r)})(${args[0]},${args[1]},${args[2] ?? "undefined"})`;
150
- case "MountTo":
151
- return `((sel,n,r)=>{const e=document.querySelector(sel);n.Mount(e,r)})(${args[0]},${args[1]},${args[2] ?? "undefined"})`;
152
- }
153
- return undefined;
154
- },
155
- };
@@ -1,17 +0,0 @@
1
- // src/backend/js/stdlib/hex.js
2
- // CodeGen for Go encoding/hex package.
3
-
4
- export const hexMethods = {
5
- _genHex(fn, a) {
6
- this.useHelper("hex");
7
- this.useHelper("error");
8
- const args = a();
9
- if (fn === "EncodeToString") return `__hex_encode_to_string(${args[0]})`;
10
- if (fn === "DecodeString") return `__hex_decode_string(${args[0]})`;
11
- if (fn === "Encode") return `__hex_encode(${args[0]}, ${args[1]})`;
12
- if (fn === "Decode") return `__hex_decode(${args[0]}, ${args[1]})`;
13
- if (fn === "EncodedLen") return `(${args[0]} * 2)`;
14
- if (fn === "DecodedLen") return `Math.floor(${args[0]} / 2)`;
15
- return undefined;
16
- },
17
- };