gofront 1.7.0 → 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.
- package/README.md +13 -13
- package/package.json +8 -37
- package/src/backend/js/expressions.js +1341 -148
- package/src/backend/js/fmt-runtime.js +573 -0
- package/src/backend/js/index.js +375 -57
- package/src/backend/js/runtime.js +1460 -133
- package/src/backend/js/statements.js +900 -86
- package/src/backend/js/stdlib/bits.js +87 -14
- package/src/backend/js/stdlib/builder.js +41 -6
- package/src/backend/js/stdlib/bytes.js +253 -7
- package/src/backend/js/stdlib/errors.js +2 -1
- package/src/backend/js/stdlib/fmt.js +349 -10
- package/src/backend/js/stdlib/index.js +8 -3
- package/src/backend/js/stdlib/json.js +247 -52
- package/src/backend/js/stdlib/maps.js +0 -8
- package/src/backend/js/stdlib/math.js +17 -1
- package/src/backend/js/stdlib/simd.js +10 -0
- package/src/backend/js/stdlib/slices.js +36 -6
- package/src/backend/js/stdlib/strconv.js +10 -5
- package/src/backend/js/stdlib/strings.js +83 -4
- package/src/backend/js/stdlib/testing.js +7 -0
- package/src/backend/js/stdlib/time.js +79 -55
- package/src/backend/js/stdlib/unicode.js +1 -1
- package/src/backend/js/stdlib/utf8.js +1 -1
- package/src/backend/js/templ.js +38 -76
- package/src/backend/js/type-info.js +272 -0
- package/src/backend/shared/fmt-types.js +188 -0
- package/src/backend/wasm/boundary.js +436 -80
- package/src/backend/wasm/emit-builtins.js +303 -13
- package/src/backend/wasm/emit-exprs.js +1397 -203
- package/src/backend/wasm/emit-maps.js +61 -13
- package/src/backend/wasm/emit-stmts.js +1359 -164
- package/src/backend/wasm/emit.js +512 -77
- package/src/backend/wasm/encode.js +43 -13
- package/src/backend/wasm/globals.js +452 -0
- package/src/backend/wasm/index.js +194 -2489
- package/src/backend/wasm/method-expr.js +381 -0
- package/src/backend/wasm/module-emitter.js +2240 -0
- package/src/backend/wasm/monomorph.js +62 -4
- package/src/backend/wasm/prescan.js +397 -0
- package/src/backend/wasm/stdlib/bytes.js +1804 -127
- package/src/backend/wasm/stdlib/core.js +1574 -199
- package/src/backend/wasm/stdlib/index.js +0 -5
- package/src/backend/wasm/stdlib/io.js +1567 -150
- package/src/backend/wasm/stdlib/packages.js +2 -0
- package/src/backend/wasm/stdlib/simd.js +293 -28
- package/src/backend/wasm/stdlib/time.js +1041 -12
- package/src/backend/wasm/types.js +200 -15
- package/src/backend/wasm/variadic.js +93 -0
- package/src/backend/wasm/wat.js +47 -20
- package/src/{cli-core.js → cli/cli-core.js} +236 -10
- package/src/{test-runner.js → cli/test-runner.js} +332 -39
- package/src/{vendor.js → cli/vendor.js} +3 -4
- package/src/compiler.js +107 -269
- package/src/index.js +15 -169
- package/src/{lexer.js → lexer/lexer.js} +102 -55
- package/src/{tokens.js → lexer/tokens.js} +1 -0
- package/src/link/sourcemap.js +97 -0
- package/src/link/stdlib.js +515 -0
- package/src/link/wasm.js +294 -0
- package/src/lower/bounds.js +394 -0
- package/src/lower/boxing.js +1 -1
- package/src/lower/captures.js +176 -32
- package/src/lower/index.js +26 -18
- package/src/lower/json-codecs.js +1398 -0
- package/src/lower/ownership.js +22 -1
- package/src/lower/range.js +86 -1
- package/src/lower/reachability.js +132 -0
- package/src/parser/declarations.js +58 -13
- package/src/parser/expressions.js +29 -7
- package/src/parser/index.js +2 -1
- package/src/parser/statements.js +37 -22
- package/src/{templ-parser.js → parser/templ.js} +138 -15
- package/src/parser/types.js +69 -9
- package/src/resolver.js +22 -1
- package/src/typechecker/assignability.js +176 -17
- package/src/typechecker/const-fold.js +356 -0
- package/src/typechecker/constants.js +256 -0
- package/src/typechecker/expressions.js +931 -122
- package/src/typechecker/index.js +459 -67
- package/src/typechecker/init-order.js +330 -0
- package/src/typechecker/resolve.js +451 -56
- package/src/typechecker/statements.js +90 -9
- package/src/typechecker/stdlib/core.js +333 -55
- package/src/typechecker/stdlib/excluded.js +898 -0
- package/src/typechecker/stdlib/extended.js +322 -26
- package/src/typechecker/{stdlib.js → stdlib/index.js} +5 -5
- package/src/typechecker/stdlib/simd.js +65 -15
- package/src/typechecker/termination.js +1 -1
- package/src/typechecker/types.js +149 -25
- package/stdlib/bytes/iter.go +192 -0
- package/stdlib/bytes/search.go +240 -0
- package/stdlib/bytes/split.go +218 -0
- package/stdlib/cmp/cmp.go +65 -0
- package/stdlib/encoding/json/errors.go +31 -0
- package/stdlib/encoding/json/indent.go +71 -0
- package/stdlib/encoding/json/number.go +12 -0
- package/stdlib/encoding/json/stream.go +173 -0
- package/stdlib/errors/overlay.go +12 -0
- package/stdlib/hash/hash.go +53 -0
- package/stdlib/internal/jsonrt/dec.go +738 -0
- package/stdlib/internal/jsonrt/enc.go +366 -0
- package/stdlib/internal/jsonrt/indent.go +135 -0
- package/stdlib/internal/jsonrt/number.go +27 -0
- package/stdlib/internal/jsonrt/reader.go +73 -0
- package/stdlib/internal/jsonrt/scanner.go +649 -0
- package/stdlib/io/io.go +346 -0
- package/stdlib/iter/iter.go +18 -0
- package/stdlib/maps/iter.go +65 -0
- package/stdlib/math/extra.go +270 -0
- package/stdlib/slices/extra.go +73 -0
- package/stdlib/slices/iter.go +113 -0
- package/stdlib/sort/sort.go +561 -0
- package/stdlib/strconv/quote.go +341 -0
- package/stdlib/strings/extra.go +35 -0
- package/stdlib/strings/iter.go +122 -0
- package/stdlib/sync/extra.go +105 -0
- package/stdlib/unicode/unicode.go +112 -0
- package/stdlib/unicode/utf8/bytes.go +239 -0
- package/src/backend/wasm/const-fold.js +0 -205
- package/src/backend/wasm/emit-stdlib.js +0 -13
- /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
- /package/src/{colors.js → cli/colors.js} +0 -0
- /package/src/{dev-server.js → cli/dev-server.js} +0 -0
- /package/src/{minifier.js → cli/minifier.js} +0 -0
- /package/src/{project-config.js → cli/project-config.js} +0 -0
- /package/src/{pwa.js → cli/pwa.js} +0 -0
- /package/src/{templ-lexer.js → lexer/templ-lexer.js} +0 -0
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
// Runtime support for `fmt` verbs (Task 3.1c/3.1d): quoting, integer and float
|
|
2
|
+
// formatting, Go type names, Go-syntax (`%#v`) printing and the format-string
|
|
3
|
+
// scanner (flags, widths, `[n]` argument indexes, `*`, MISSING/EXTRA/BADINDEX
|
|
4
|
+
// forms). Shared by the JS backend and the WASM host (`__sprintf` is the one
|
|
5
|
+
// format engine of both). The text is plain JavaScript in String.raw so the
|
|
6
|
+
// regular expressions and escapes below are written as they run; it must not
|
|
7
|
+
// contain backticks or dollar-brace sequences.
|
|
8
|
+
|
|
9
|
+
// Utilities that need no access to the value formatter. Operands whose
|
|
10
|
+
// static type matters (`%T`, `%#v`, unknown verbs, EXTRA) arrive wrapped by
|
|
11
|
+
// `__ft(value, typeDescriptor)` (descriptors: see fmt-types.js).
|
|
12
|
+
export const HELPER_FMT_UTIL = String.raw`var __FT = __FT || class FmtTyped { constructor(v, t) { this.v = v; this.t = t; } };
|
|
13
|
+
var __ft = __ft || function(v, t) { return new __FT(v, t); };
|
|
14
|
+
var __fmtu = __fmtu || (() => {
|
|
15
|
+
const runes = (s) => { let n = 0; for (const _ of s) n++; return n; };
|
|
16
|
+
const spaces = (n) => " ".repeat(Math.max(0, n));
|
|
17
|
+
const pad = (s, fl, wid) => {
|
|
18
|
+
const n = wid - runes(s);
|
|
19
|
+
if (n <= 0) return s;
|
|
20
|
+
return fl.minus ? s + spaces(n) : spaces(n) + s;
|
|
21
|
+
};
|
|
22
|
+
const hex = (c, w) => c.toString(16).padStart(w, "0");
|
|
23
|
+
const PRINTABLE = /^[\p{L}\p{M}\p{N}\p{P}\p{S}]$/u;
|
|
24
|
+
const ESC = { 7: "\\a", 8: "\\b", 12: "\\f", 10: "\\n", 13: "\\r", 9: "\\t", 11: "\\v" };
|
|
25
|
+
const quote = (s, ascii, q) => {
|
|
26
|
+
let out = q;
|
|
27
|
+
for (const ch of s) {
|
|
28
|
+
const c = ch.codePointAt(0);
|
|
29
|
+
if (ch === q || ch === "\\") out += "\\" + ch;
|
|
30
|
+
else if (ESC[c]) out += ESC[c];
|
|
31
|
+
else if (c < 0x20 || c === 0x7f) out += "\\x" + hex(c, 2);
|
|
32
|
+
else if (c < 0x7f) out += ch;
|
|
33
|
+
else if (ascii || !PRINTABLE.test(ch)) out += c < 0x10000 ? "\\u" + hex(c, 4) : "\\U" + hex(c, 8);
|
|
34
|
+
else out += ch;
|
|
35
|
+
}
|
|
36
|
+
return out + q;
|
|
37
|
+
};
|
|
38
|
+
const validRune = (c) => c >= 0 && c <= 0x10ffff && !(c >= 0xd800 && c < 0xe000);
|
|
39
|
+
const runeStr = (c) => String.fromCodePoint(validRune(c) ? c : 0xfffd);
|
|
40
|
+
const quoteRune = (c, ascii) => quote(runeStr(c), ascii, "'");
|
|
41
|
+
const toBig = (n) => (typeof n === "bigint" ? n : BigInt(Math.trunc(n)));
|
|
42
|
+
const fmtInt = (n, base, upper, verbO, fl, wid, hasWid, prec, hasPrec) => {
|
|
43
|
+
let b = toBig(n);
|
|
44
|
+
const neg = b < 0n;
|
|
45
|
+
if (neg) b = -b;
|
|
46
|
+
let ds = b.toString(base);
|
|
47
|
+
if (upper) ds = ds.toUpperCase();
|
|
48
|
+
let pre = "";
|
|
49
|
+
if (fl.sharp) {
|
|
50
|
+
if (base === 16) pre = upper ? "0X" : "0x";
|
|
51
|
+
else if (base === 2) pre = "0b";
|
|
52
|
+
else if (base === 8 && ds[0] !== "0") pre = "0";
|
|
53
|
+
}
|
|
54
|
+
if (verbO) pre = "0o";
|
|
55
|
+
if (hasPrec) {
|
|
56
|
+
ds = prec === 0 && b === 0n ? "" : ds.padStart(prec, "0");
|
|
57
|
+
} else if (fl.zero && !fl.minus && hasWid) {
|
|
58
|
+
let p = wid - pre.length;
|
|
59
|
+
if (neg || fl.plus || fl.space) p--;
|
|
60
|
+
if (p > ds.length) ds = ds.padStart(p, "0");
|
|
61
|
+
}
|
|
62
|
+
const sign = neg ? "-" : fl.plus ? "+" : fl.space ? " " : "";
|
|
63
|
+
return pad(sign + pre + ds, fl, wid);
|
|
64
|
+
};
|
|
65
|
+
const expParts = (s) => {
|
|
66
|
+
const m = /^(\d)(?:\.(\d+))?e([+-]\d+)$/.exec(s);
|
|
67
|
+
return [m[1] + (m[2] ?? ""), Number(m[3])];
|
|
68
|
+
};
|
|
69
|
+
const expStr = (x, upper) => (upper ? "E" : "e") + (x < 0 ? "-" : "+") + String(Math.abs(x)).padStart(2, "0");
|
|
70
|
+
const shortest32 = (v) => {
|
|
71
|
+
for (let p = 1; p <= 9; p++) {
|
|
72
|
+
const s = v.toExponential(p - 1);
|
|
73
|
+
if (Math.fround(Number(s)) === v) return s;
|
|
74
|
+
}
|
|
75
|
+
return v.toExponential();
|
|
76
|
+
};
|
|
77
|
+
const fmtE = (abs, prec, upper) => {
|
|
78
|
+
const [ds, x] = expParts(abs.toExponential(Math.min(prec, 100)));
|
|
79
|
+
return ds[0] + (prec > 0 ? "." + ds.slice(1).padEnd(prec, "0") : "") + expStr(x, upper);
|
|
80
|
+
};
|
|
81
|
+
const fmtF = (abs, prec) => {
|
|
82
|
+
if (abs >= 1e21) return BigInt(abs).toString() + (prec > 0 ? "." + "0".repeat(prec) : "");
|
|
83
|
+
return abs.toFixed(Math.min(prec, 100));
|
|
84
|
+
};
|
|
85
|
+
const fmtG = (abs, prec, upper, f32) => {
|
|
86
|
+
if (prec === 0) prec = 1;
|
|
87
|
+
const [d0, x] = expParts(prec < 0 ? (f32 ? shortest32(abs) : abs.toExponential()) : abs.toExponential(Math.min(prec - 1, 100)));
|
|
88
|
+
const ds = d0.replace(/0+$/, "") || "0";
|
|
89
|
+
let eprec = prec < 0 ? 6 : prec;
|
|
90
|
+
if (prec >= 0 && eprec > ds.length && ds.length >= x + 1) eprec = ds.length;
|
|
91
|
+
if (abs !== 0 && (x < -4 || x >= eprec)) {
|
|
92
|
+
return ds[0] + (ds.length > 1 ? "." + ds.slice(1) : "") + expStr(x, upper);
|
|
93
|
+
}
|
|
94
|
+
if (abs === 0) return "0";
|
|
95
|
+
if (x >= 0) return ds.slice(0, x + 1).padEnd(x + 1, "0") + (ds.length > x + 1 ? "." + ds.slice(x + 1) : "");
|
|
96
|
+
return "0." + "0".repeat(-x - 1) + ds;
|
|
97
|
+
};
|
|
98
|
+
// %x of a float: 0x1.8p+01, mantissa digits rounded to prec (shortest when absent).
|
|
99
|
+
const fmtHexFloat = (abs, prec, upper, f32) => {
|
|
100
|
+
let body;
|
|
101
|
+
if (abs === 0) {
|
|
102
|
+
body = "0x0" + (prec > 0 ? "." + "0".repeat(prec) : "") + "p+00";
|
|
103
|
+
} else {
|
|
104
|
+
const dv = new DataView(new ArrayBuffer(8));
|
|
105
|
+
dv.setFloat64(0, abs);
|
|
106
|
+
const bits = dv.getBigUint64(0);
|
|
107
|
+
let e = Number((bits >> 52n) & 0x7ffn);
|
|
108
|
+
let m = bits & 0xfffffffffffffn;
|
|
109
|
+
if (e === 0) {
|
|
110
|
+
// Subnormal: normalise so the leading bit is the implicit 1.
|
|
111
|
+
e = -1022;
|
|
112
|
+
while (m < (1n << 52n)) { m <<= 1n; e--; }
|
|
113
|
+
m &= 0xfffffffffffffn;
|
|
114
|
+
} else e -= 1023;
|
|
115
|
+
let frac = m; // 52 bits = 13 hex digits
|
|
116
|
+
let digits = 13;
|
|
117
|
+
let lead = 1n;
|
|
118
|
+
if (prec >= 0 && prec < 13) {
|
|
119
|
+
const drop = BigInt((13 - prec) * 4);
|
|
120
|
+
const full = (1n << 52n) | m;
|
|
121
|
+
let q = full >> drop;
|
|
122
|
+
const rem = full & ((1n << drop) - 1n);
|
|
123
|
+
const half = 1n << (drop - 1n);
|
|
124
|
+
if (rem > half || (rem === half && (q & 1n) === 1n)) q += 1n;
|
|
125
|
+
if (q >> BigInt(prec * 4) >= 2n) { q >>= 1n; e++; }
|
|
126
|
+
lead = q >> BigInt(prec * 4);
|
|
127
|
+
frac = q & ((1n << BigInt(prec * 4)) - 1n);
|
|
128
|
+
digits = prec;
|
|
129
|
+
}
|
|
130
|
+
let hs = digits > 0 ? frac.toString(16).padStart(digits, "0") : "";
|
|
131
|
+
if (prec < 0) hs = hs.replace(/0+$/, "");
|
|
132
|
+
else if (prec > 13) hs = hs.padEnd(prec, "0");
|
|
133
|
+
body = "0x" + lead + (hs ? "." + hs : "") + "p" + (e < 0 ? "-" : "+") + String(Math.abs(e)).padStart(2, "0");
|
|
134
|
+
}
|
|
135
|
+
return upper ? body.toUpperCase() : body;
|
|
136
|
+
};
|
|
137
|
+
// %b of a float: mantissa "p" exponent, as strconv 'b'.
|
|
138
|
+
const fmtBinFloat = (abs, f32) => {
|
|
139
|
+
if (abs === 0) return "0p-" + (f32 ? 149 : 1074);
|
|
140
|
+
const dv = new DataView(new ArrayBuffer(8));
|
|
141
|
+
let mant, ex;
|
|
142
|
+
if (f32) {
|
|
143
|
+
dv.setFloat32(0, abs);
|
|
144
|
+
const b = dv.getUint32(0);
|
|
145
|
+
ex = (b >>> 23) & 0xff;
|
|
146
|
+
mant = BigInt(b & 0x7fffff);
|
|
147
|
+
if (ex === 0) ex++; else mant |= 1n << 23n;
|
|
148
|
+
ex += -127 - 23;
|
|
149
|
+
} else {
|
|
150
|
+
dv.setFloat64(0, abs);
|
|
151
|
+
const b = dv.getBigUint64(0);
|
|
152
|
+
ex = Number((b >> 52n) & 0x7ffn);
|
|
153
|
+
mant = b & 0xfffffffffffffn;
|
|
154
|
+
if (ex === 0) ex++; else mant |= 1n << 52n;
|
|
155
|
+
ex += -1023 - 52;
|
|
156
|
+
}
|
|
157
|
+
return mant.toString() + "p" + (ex >= 0 ? "+" : "") + ex;
|
|
158
|
+
};
|
|
159
|
+
const fmtFloat = (n, verb, fl, wid, hasWid, prec, hasPrec, f32) => {
|
|
160
|
+
n = Number(n);
|
|
161
|
+
if (Number.isNaN(n)) return pad(fl.plus ? "+NaN" : fl.space ? " NaN" : "NaN", fl, wid);
|
|
162
|
+
const neg = n < 0 || Object.is(n, -0);
|
|
163
|
+
const abs = Math.abs(n);
|
|
164
|
+
if (abs === Infinity) return pad(neg ? "-Inf" : fl.space && !fl.plus ? " Inf" : "+Inf", fl, wid);
|
|
165
|
+
const upper = verb === "E" || verb === "G";
|
|
166
|
+
let body;
|
|
167
|
+
if (verb === "x" || verb === "X") body = fmtHexFloat(abs, hasPrec ? prec : -1, verb === "X", f32);
|
|
168
|
+
else if (verb === "b") body = fmtBinFloat(abs, f32);
|
|
169
|
+
else if (verb === "e" || verb === "E") body = fmtE(abs, hasPrec ? prec : 6, upper);
|
|
170
|
+
else if (verb === "f" || verb === "F") body = fmtF(abs, hasPrec ? prec : 6);
|
|
171
|
+
else body = fmtG(abs, hasPrec ? prec : -1, upper, f32);
|
|
172
|
+
const sign = neg ? "-" : fl.plus ? "+" : fl.space ? " " : "";
|
|
173
|
+
if (fl.zero && !fl.minus && hasWid && wid > sign.length + body.length) {
|
|
174
|
+
return sign + body.padStart(wid - sign.length, "0");
|
|
175
|
+
}
|
|
176
|
+
return pad(sign + body, fl, wid);
|
|
177
|
+
};
|
|
178
|
+
const utf8 = (s) => Array.from(new TextEncoder().encode(s));
|
|
179
|
+
const fmtHex = (bytes, upper, fl, prec, hasPrec, wid) => {
|
|
180
|
+
let n = bytes.length;
|
|
181
|
+
if (hasPrec && prec < n) n = prec;
|
|
182
|
+
const hs = bytes.slice(0, n).map((b) => {
|
|
183
|
+
const h = (Number(b) & 255).toString(16).padStart(2, "0");
|
|
184
|
+
return upper ? h.toUpperCase() : h;
|
|
185
|
+
});
|
|
186
|
+
const px = fl.sharp ? (upper ? "0X" : "0x") : "";
|
|
187
|
+
return pad(hs.length === 0 ? "" : fl.space ? hs.map((h) => px + h).join(" ") : px + hs.join(""), fl, wid);
|
|
188
|
+
};
|
|
189
|
+
const baseOf = (t) => {
|
|
190
|
+
while (t && t.k === "named") t = t.u;
|
|
191
|
+
return t;
|
|
192
|
+
};
|
|
193
|
+
const isFloatN = (n) => n === "float32" || n === "float64";
|
|
194
|
+
const isComplexN = (n) => n === "complex64" || n === "complex128";
|
|
195
|
+
const IFACE = { k: "i", n: "interface {}" };
|
|
196
|
+
const typeName = (t) => {
|
|
197
|
+
if (t == null) return "<nil>";
|
|
198
|
+
switch (t.k) {
|
|
199
|
+
case "b": return t.n === "any" ? "interface {}" : t.n;
|
|
200
|
+
case "named": case "i": return t.n;
|
|
201
|
+
case "struct":
|
|
202
|
+
if (t.n) return t.n;
|
|
203
|
+
return !t.f || t.f.length === 0 ? "struct {}" : "struct { " + t.f.map(([k, ft]) => k + " " + typeName(ft ?? IFACE)).join("; ") + " }";
|
|
204
|
+
case "ptr": return "*" + typeName(t.e ?? IFACE);
|
|
205
|
+
case "slice": return "[]" + typeName(t.e ?? IFACE);
|
|
206
|
+
case "array": return "[" + t.len + "]" + typeName(t.e ?? IFACE);
|
|
207
|
+
case "map": return "map[" + typeName(t.key ?? IFACE) + "]" + typeName(t.val ?? IFACE);
|
|
208
|
+
case "chan": return "chan " + typeName(t.e ?? IFACE);
|
|
209
|
+
case "func": {
|
|
210
|
+
const ps = (t.p ?? []).map((p) => typeName(p ?? IFACE));
|
|
211
|
+
if (t.v && ps.length > 0) ps[ps.length - 1] = "..." + ps[ps.length - 1].slice(2);
|
|
212
|
+
const rs = (t.r ?? []).map((r) => typeName(r ?? IFACE));
|
|
213
|
+
return "func(" + ps.join(", ") + ")" + (rs.length === 0 ? "" : rs.length === 1 ? " " + rs[0] : " (" + rs.join(", ") + ")");
|
|
214
|
+
}
|
|
215
|
+
default: return "<nil>";
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
const TYPED = [[Int8Array, "int8"], [Uint8Array, "uint8"], [Uint8ClampedArray, "uint8"], [Int16Array, "int16"], [Uint16Array, "uint16"], [Int32Array, "int32"], [Uint32Array, "uint32"], [Float32Array, "float32"], [Float64Array, "float64"], [BigInt64Array, "int64"], [BigUint64Array, "uint64"]];
|
|
219
|
+
const isNumKey = (kd) => {
|
|
220
|
+
kd = baseOf(kd);
|
|
221
|
+
return kd?.k === "b" && /^(u?int|float|uintptr)/.test(kd.n);
|
|
222
|
+
};
|
|
223
|
+
// Best-effort type of a value that carries none (an any/interface operand).
|
|
224
|
+
const descOf = (v) => {
|
|
225
|
+
if (v === null || v === undefined) return null;
|
|
226
|
+
if (typeof v === "boolean") return { k: "b", n: "bool" };
|
|
227
|
+
if (typeof v === "string") return { k: "b", n: "string" };
|
|
228
|
+
if (typeof v === "bigint") return { k: "b", n: "int64" };
|
|
229
|
+
if (typeof v === "number") return { k: "b", n: Number.isInteger(v) ? "int" : "float64" };
|
|
230
|
+
if (typeof v !== "object") return null;
|
|
231
|
+
const ta = TYPED.find(([c]) => v instanceof c);
|
|
232
|
+
if (ta) return { k: "slice", e: { k: "b", n: ta[1] } };
|
|
233
|
+
if (Array.isArray(v)) return { k: "slice", e: v.length > 0 && v[0] != null ? descOf(v[0]) : IFACE };
|
|
234
|
+
if (v instanceof Map || v.__map === true) {
|
|
235
|
+
const ks = v instanceof Map ? Array.from(v.keys()) : Object.keys(v);
|
|
236
|
+
const k0 = ks[0];
|
|
237
|
+
const v0 = v instanceof Map ? v.get(k0) : v[k0];
|
|
238
|
+
const kd = k0 === undefined ? IFACE : v instanceof Map ? descOf(k0) : k0.charCodeAt(0) === 1 && typeof __kd === "function" ? descOf(__kd(k0)) : /^-?\d+$/.test(k0) ? { k: "b", n: "int" } : { k: "b", n: "string" };
|
|
239
|
+
return { k: "map", key: kd, val: k0 === undefined || v0 == null ? IFACE : descOf(v0) };
|
|
240
|
+
}
|
|
241
|
+
if (v._d instanceof Date) return { k: "struct", n: "time.Time", f: [] };
|
|
242
|
+
if (v.re !== undefined && v.im !== undefined) return { k: "b", n: "complex128" };
|
|
243
|
+
if (typeof v.__gfUnbox === "function") {
|
|
244
|
+
const nm = v.constructor?.name ?? "";
|
|
245
|
+
if (nm === "FmtStr" || nm === "FmtErr") return descOf(v.__gfUnbox());
|
|
246
|
+
return { k: "named", n: "main." + nm.replace(/\$Ptr$/, ""), u: descOf(v.__gfUnbox()) };
|
|
247
|
+
}
|
|
248
|
+
const proto = Object.getPrototypeOf(v);
|
|
249
|
+
if ((proto === null || Object.getPrototypeOf(proto) === null) && typeof v.Error === "function") {
|
|
250
|
+
return { k: "ptr", e: { k: "struct", n: "errors.errorString", f: [] } };
|
|
251
|
+
}
|
|
252
|
+
if (v.constructor && v.constructor !== Object) {
|
|
253
|
+
const st = { k: "struct", n: "main." + v.constructor.name.replace(/\$Ptr$/, ""), f: keys(v).map((k) => [k, descOf(v[k]) ?? IFACE]) };
|
|
254
|
+
return v.__p === true ? { k: "ptr", e: st } : st;
|
|
255
|
+
}
|
|
256
|
+
const host = { k: "struct", n: v.__tn ?? "", f: Object.keys(v).map((k) => [k, descOf(v[k]) ?? IFACE]) };
|
|
257
|
+
return v.__tn !== undefined && v.__p === true ? { k: "ptr", e: host } : host;
|
|
258
|
+
};
|
|
259
|
+
// The fields a struct value declares: a class that also keeps a copy of the
|
|
260
|
+
// fields promoted from an embedded struct lists its own in __fk.
|
|
261
|
+
const keys = (v) => v.__fk ?? Object.keys(v);
|
|
262
|
+
const sortedEntries = (m, kd) => {
|
|
263
|
+
const es = m instanceof Map
|
|
264
|
+
? Array.from(m.entries())
|
|
265
|
+
: Object.keys(m).map((k) => [k.charCodeAt(0) === 1 && typeof __kd === "function" ? __kd(k) : isNumKey(kd) || (!kd && /^-?\d+$/.test(k)) ? Number(k) : k, m[k]]);
|
|
266
|
+
const raw = (k) => (k !== null && typeof k === "object" && typeof k.__gfUnbox === "function" ? k.__gfUnbox() : k);
|
|
267
|
+
return es.sort(([a], [b]) => {
|
|
268
|
+
if (a !== null && b !== null && typeof a === "object" && typeof b === "object" && typeof __kcmp === "function" && !a.__gfUnbox) return __kcmp(a, b);
|
|
269
|
+
const x = raw(a), y = raw(b);
|
|
270
|
+
if (typeof x === "number" && typeof y === "number") return x - y;
|
|
271
|
+
const p = String(x), q = String(y);
|
|
272
|
+
return p < q ? -1 : p > q ? 1 : 0;
|
|
273
|
+
});
|
|
274
|
+
};
|
|
275
|
+
const gsBasic = (v, n) => {
|
|
276
|
+
if (v === null || v === undefined) return "<nil>";
|
|
277
|
+
if (typeof v === "string") return quote(v, false, '"');
|
|
278
|
+
if (typeof v === "boolean") return String(v);
|
|
279
|
+
if (typeof v === "object") return "(" + String(v.re) + "+" + String(v.im) + "i)";
|
|
280
|
+
if (isFloatN(n)) return fmtFloat(v, "g", {}, 0, false, -1, false, n === "float32");
|
|
281
|
+
if (/^u/.test(n)) return "0x" + toBig(v).toString(16);
|
|
282
|
+
return String(v);
|
|
283
|
+
};
|
|
284
|
+
const gsComp = (v, t, nm, top, gs) => {
|
|
285
|
+
if (t.k === "map") {
|
|
286
|
+
const tn = nm ?? typeName(t);
|
|
287
|
+
if (v == null) return tn + "(nil)";
|
|
288
|
+
return tn + "{" + sortedEntries(v, t.key).map(([k, x]) => gs(k, t.key, false) + ":" + gs(x, t.val, false)).join(", ") + "}";
|
|
289
|
+
}
|
|
290
|
+
if (v == null) return (nm ?? typeName(t)) + "(nil)";
|
|
291
|
+
const bytes = top && t.k === "slice" && t.e?.k === "b" && t.e.n === "uint8";
|
|
292
|
+
const tn = nm ?? (bytes ? "[]byte" : typeName(t));
|
|
293
|
+
return tn + "{" + Array.from(v).map((x) => gs(x, t.e, false)).join(", ") + "}";
|
|
294
|
+
};
|
|
295
|
+
// %#v: Go-syntax representation of v, whose static type is t (or unknown).
|
|
296
|
+
const gs = (v, t, top) => {
|
|
297
|
+
if (v !== null && typeof v === "object" && typeof v.__gfUnbox === "function") v = v.__gfUnbox();
|
|
298
|
+
if (t == null) {
|
|
299
|
+
if (v == null) return "<nil>";
|
|
300
|
+
t = descOf(v);
|
|
301
|
+
}
|
|
302
|
+
switch (t.k) {
|
|
303
|
+
case "i": return v == null ? typeName(t) + "(nil)" : gs(v, descOf(v), top);
|
|
304
|
+
case "b": return gsBasic(v, t.n);
|
|
305
|
+
case "named": {
|
|
306
|
+
const u = t.u ?? descOf(v);
|
|
307
|
+
return u && (u.k === "slice" || u.k === "array" || u.k === "map") ? gsComp(v, u, t.n, top, gs) : gs(v, u, top);
|
|
308
|
+
}
|
|
309
|
+
case "struct": {
|
|
310
|
+
const f = t.f ?? keys(v ?? {}).map((k) => [k, null]);
|
|
311
|
+
if (v == null) return typeName(t) + "{}";
|
|
312
|
+
return typeName({ k: "struct", n: t.n, f }) + "{" + f.map(([k, ft]) => k + ":" + gs(v[k], ft, false)).join(", ") + "}";
|
|
313
|
+
}
|
|
314
|
+
case "ptr": {
|
|
315
|
+
if (v == null) return "(" + typeName(t) + ")(nil)";
|
|
316
|
+
const e = t.e;
|
|
317
|
+
if (top && e && (e.k === "struct" || e.k === "slice" || e.k === "array" || e.k === "map")) return "&" + gs(v, e, false);
|
|
318
|
+
return "(" + typeName(t) + ")(0xc000010000)";
|
|
319
|
+
}
|
|
320
|
+
case "slice": case "array": case "map": return gsComp(v, t, null, top, gs);
|
|
321
|
+
default: return String(v);
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
// both(t, s): the descriptor of a value with a static type descriptor t and a
|
|
325
|
+
// Stringer descriptor s; split() undoes it. A Stringer descriptor never has a
|
|
326
|
+
// string "k", a type descriptor always does.
|
|
327
|
+
const both = (t, s) => (t && s ? { $both: 1, t, s } : (t ?? s));
|
|
328
|
+
const split = (fd) => (fd?.$both ? [fd.t, fd.s] : typeof fd?.k === "string" ? [fd, null] : [null, fd]);
|
|
329
|
+
return { both, split, runes, pad, quote, quoteRune, runeStr, validRune, fmtInt, fmtFloat, utf8, fmtHex, baseOf, isFloatN, isComplexN, typeName, descOf, sortedEntries, gs, PRINTABLE, hex, keys, isNumKey };
|
|
330
|
+
})();`;
|
|
331
|
+
|
|
332
|
+
// The format-string scanner and per-verb dispatch, spliced into `__sprintf`
|
|
333
|
+
// after its value formatter (`formatV`) so it can use it.
|
|
334
|
+
export const HELPER_FMT_LOOP = String.raw`
|
|
335
|
+
const U = __fmtu;
|
|
336
|
+
const unbox = (v, verb) => {
|
|
337
|
+
if (v && typeof v.__gfUnbox === "function" && !(typeof v.Error === "function" && "vsqxXw".includes(verb)) && !("vsqxX".includes(verb) && stringMethod(v))) return v.__gfUnbox();
|
|
338
|
+
return v;
|
|
339
|
+
};
|
|
340
|
+
const bad = (verb, v, t) => "%!" + verb + "(" + (v === null || v === undefined ? "<nil>" : U.typeName(t ?? U.descOf(v)) + "=" + formatV(v, false, true)) + ")";
|
|
341
|
+
const elemOf = (t) => {
|
|
342
|
+
t = U.baseOf(t);
|
|
343
|
+
return t && (t.k === "slice" || t.k === "array") ? t.e : null;
|
|
344
|
+
};
|
|
345
|
+
const fieldOf = (t, k) => {
|
|
346
|
+
t = U.baseOf(t);
|
|
347
|
+
if (t?.k === "ptr") t = U.baseOf(t.e);
|
|
348
|
+
return t?.k === "struct" ? t.f?.find((x) => x[0] === k)?.[1] : null;
|
|
349
|
+
};
|
|
350
|
+
const fmtStr = (verb, s, fl, wid, prec, hasPrec) => {
|
|
351
|
+
if (verb === "x" || verb === "X") return U.fmtHex(U.utf8(s), verb === "X", fl, prec, hasPrec, wid);
|
|
352
|
+
if (hasPrec && (verb === "s" || verb === "q")) s = Array.from(s).slice(0, prec).join("");
|
|
353
|
+
if (verb === "s") return U.pad(s, fl, wid);
|
|
354
|
+
if (verb === "q") return U.pad(fl.sharp && !/[\x60\x00-\x08\x0a-\x1f\x7f]/.test(s) ? "\x60" + s + "\x60" : U.quote(s, fl.plus, '"'), fl, wid);
|
|
355
|
+
return null;
|
|
356
|
+
};
|
|
357
|
+
const fmtNum = (verb, v, t, fl, wid, hasWid, prec, hasPrec) => {
|
|
358
|
+
const bt = U.baseOf(t);
|
|
359
|
+
const bn = bt?.k === "b" ? bt.n : "";
|
|
360
|
+
const isFloatT = U.isFloatN(bn);
|
|
361
|
+
const isIntT = bn !== "" && !isFloatT && !U.isComplexN(bn);
|
|
362
|
+
// A number that is not an integer (or is typed as a float) is a float.
|
|
363
|
+
const isFloatV = isFloatT || (!isIntT && typeof v === "number" && !Number.isInteger(v));
|
|
364
|
+
if (isFloatV && (verb === "x" || verb === "X" || verb === "b")) return U.fmtFloat(v, verb, fl, wid, hasWid, prec, hasPrec, bn === "float32");
|
|
365
|
+
if (isFloatV && "cqUdoO".includes(verb)) return null;
|
|
366
|
+
switch (verb) {
|
|
367
|
+
case "d": case "b": case "o": case "O": case "x": case "X": {
|
|
368
|
+
const base = verb === "d" ? 10 : verb === "b" ? 2 : verb === "o" || verb === "O" ? 8 : 16;
|
|
369
|
+
return U.fmtInt(v, base, verb === "X", verb === "O", fl, wid, hasWid, prec, hasPrec);
|
|
370
|
+
}
|
|
371
|
+
case "v": return isFloatV ? U.fmtFloat(v, "g", fl, wid, hasWid, prec, hasPrec, bn === "float32") : U.fmtInt(v, 10, false, false, fl, wid, hasWid, prec, hasPrec);
|
|
372
|
+
case "c": return U.pad(U.runeStr(Number(v)), fl, wid);
|
|
373
|
+
case "q": return U.pad(U.quoteRune(Number(v), fl.plus), fl, wid);
|
|
374
|
+
case "U": {
|
|
375
|
+
const c = Number(v);
|
|
376
|
+
// A negative value prints as its 64-bit two's complement, as Go's uint64 conversion.
|
|
377
|
+
const hx = c < 0 ? BigInt.asUintN(64, BigInt(c)).toString(16) : U.hex(c, 1);
|
|
378
|
+
let s = "U+" + hx.toUpperCase().padStart(Math.max(4, hasPrec ? prec : 0), "0");
|
|
379
|
+
if (fl.sharp && U.validRune(c) && U.PRINTABLE.test(String.fromCodePoint(c))) s += " '" + String.fromCodePoint(c) + "'";
|
|
380
|
+
return U.pad(s, fl, wid);
|
|
381
|
+
}
|
|
382
|
+
case "e": case "E": case "f": case "F": case "g": case "G":
|
|
383
|
+
if (isIntT) return null;
|
|
384
|
+
return U.fmtFloat(v, verb, fl, wid, hasWid, prec, hasPrec, bn === "float32");
|
|
385
|
+
default: return null;
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
// A nil *T element whose Error/String has a pointer receiver is still asked
|
|
389
|
+
// for its text under %s, %q, %x and %X: the descriptor carries its stand-in.
|
|
390
|
+
const nilStand = (e, d, verb) => (e == null && d?.np !== undefined && "sqxX".includes(verb) ? d.np : e);
|
|
391
|
+
// Applies a non-%v verb to v; composites apply it to each element, as Go does.
|
|
392
|
+
// sd: Stringer descriptor of v when it is not carried by v itself (see formatV).
|
|
393
|
+
const fmtv = (verb, v, t, fl, wid, hasWid, prec, hasPrec, top, sd) => {
|
|
394
|
+
sd = sd ?? v?.__fd;
|
|
395
|
+
if (sd?.b && v != null && !(v instanceof sd.b)) v = new sd.b(v);
|
|
396
|
+
v = unbox(v, verb);
|
|
397
|
+
const bt = U.baseOf(t);
|
|
398
|
+
if (v === null || v === undefined) {
|
|
399
|
+
if (bt?.k === "slice") v = [];
|
|
400
|
+
else if (bt?.k === "map") v = {};
|
|
401
|
+
// A nil *T with a String/Error method prints <nil> under %s (Go recovers
|
|
402
|
+
// the nil-dereference panic); a bare null cannot tell it from a nil interface.
|
|
403
|
+
else return verb === "s" || verb === "v" ? U.pad("<nil>", fl, wid) : bad(verb, v, t);
|
|
404
|
+
}
|
|
405
|
+
if (t?.n === "time.Duration" && "vs".includes(verb)) {
|
|
406
|
+
return typeof __durationString === "function" ? __durationString(v) : String(v);
|
|
407
|
+
}
|
|
408
|
+
switch (typeof v) {
|
|
409
|
+
case "boolean": return verb === "t" || verb === "v" ? U.pad(String(v), fl, wid) : bad(verb, v, t);
|
|
410
|
+
case "string": {
|
|
411
|
+
// Integer-keyed object maps hand their keys over as numeric strings.
|
|
412
|
+
if (verb === "d" && (bt == null || bt.k !== "b") && /^-?\d+$/.test(v)) return fmtNum(verb, BigInt(v), null, fl, wid, hasWid, prec, hasPrec);
|
|
413
|
+
return fmtStr(verb === "v" ? "s" : verb, v, fl, wid, prec, hasPrec) ?? bad(verb, v, t);
|
|
414
|
+
}
|
|
415
|
+
case "number": case "bigint": return fmtNum(verb, v, t, fl, wid, hasWid, prec, hasPrec) ?? bad(verb, v, t);
|
|
416
|
+
default: break;
|
|
417
|
+
}
|
|
418
|
+
if ("vsqxX".includes(verb)) {
|
|
419
|
+
const sm = stringMethod(v);
|
|
420
|
+
if (sm) return fmtStr(verb === "v" ? "s" : verb, String(callMethod(v, sm)), fl, wid, prec, hasPrec);
|
|
421
|
+
}
|
|
422
|
+
if ("re" in v && "im" in v) {
|
|
423
|
+
if (verb === "v") verb = "g";
|
|
424
|
+
if (!"eEfFgG".includes(verb)) return bad(verb, v, t);
|
|
425
|
+
const one = (n, pl) => U.fmtFloat(n, verb, pl ? { ...fl, plus: true } : fl, wid, hasWid, prec, hasPrec, false);
|
|
426
|
+
return "(" + one(v.re, false) + one(v.im, true) + "i)";
|
|
427
|
+
}
|
|
428
|
+
if (v._d instanceof Date) return formatV(v, false, true);
|
|
429
|
+
if (Array.isArray(v) || ArrayBuffer.isView(v)) {
|
|
430
|
+
const items = Array.from(v);
|
|
431
|
+
// The WASM host hands []byte over as a plain array, so an array of byte-sized
|
|
432
|
+
// numbers of unknown element type is taken for bytes under %s, %x and %X.
|
|
433
|
+
const et0 = elemOf(t);
|
|
434
|
+
const bn0 = U.baseOf(et0);
|
|
435
|
+
const isBytes = v instanceof Uint8Array || (et0 == null && "sqxX".includes(verb) && items.every((e) => Number.isInteger(e) && e >= 0 && e < 256)) || (bn0?.k === "b" && bn0.n === "uint8" && "sqxX".includes(verb));
|
|
436
|
+
if (isBytes && "sqxX".includes(verb)) {
|
|
437
|
+
if (verb === "x" || verb === "X") return U.fmtHex(items, verb === "X", fl, prec, hasPrec, wid);
|
|
438
|
+
return fmtStr(verb, new TextDecoder().decode(Uint8Array.from(items)), fl, wid, prec, hasPrec);
|
|
439
|
+
}
|
|
440
|
+
const et = elemOf(t);
|
|
441
|
+
if (v.__ptr_slice === true) items.forEach(markPtr);
|
|
442
|
+
return "[" + items.map((e) => fmtv(verb, nilStand(e, sd?.e, verb), et, fl, wid, hasWid, prec, hasPrec, false, sd?.e)).join(" ") + "]";
|
|
443
|
+
}
|
|
444
|
+
if (v instanceof Map || v.__map === true || U.baseOf(t)?.k === "map") {
|
|
445
|
+
const bm = U.baseOf(t);
|
|
446
|
+
const kt = bm?.k === "map" ? bm.key : null;
|
|
447
|
+
const vt = bm?.k === "map" ? bm.val : null;
|
|
448
|
+
const entries = U.sortedEntries(v, kt);
|
|
449
|
+
if (v.__ptr_map === true) entries.forEach(([, x]) => markPtr(x));
|
|
450
|
+
return "map[" + entries.map(([k, x]) => fmtv(verb, k, kt, fl, wid, hasWid, prec, hasPrec, false, sd?.k) + ":" + fmtv(verb, nilStand(x, sd?.v, verb), vt, fl, wid, hasWid, prec, hasPrec, false, sd?.v)).join(" ") + "]";
|
|
451
|
+
}
|
|
452
|
+
if (isPointer(v) && !top) return getPtr(v);
|
|
453
|
+
const ff = typeof v.__ff === "function" ? v.__ff() : (sd?.ff ?? null);
|
|
454
|
+
const body = U.keys(v).map((k) => fmtv(verb, nilStand(v[k], ff?.[k], verb), fieldOf(t, k), fl, wid, hasWid, prec, hasPrec, false, ff?.[k])).join(" ");
|
|
455
|
+
return (isPointer(v) ? "&{" : "{") + body + "}";
|
|
456
|
+
};
|
|
457
|
+
const typedArg = (x) => (x instanceof __FT ? { v: x.v, t: x.t } : { v: x, t: null });
|
|
458
|
+
let out = "";
|
|
459
|
+
let argNum = 0;
|
|
460
|
+
let reordered = false;
|
|
461
|
+
let good = true;
|
|
462
|
+
const argIndex = (p, afterIdx) => {
|
|
463
|
+
if (f[p] !== "[") return [p, false];
|
|
464
|
+
reordered = true;
|
|
465
|
+
const m = /^\[(\d+)\]/.exec(f.slice(p));
|
|
466
|
+
if (!m) {
|
|
467
|
+
const close = f.indexOf("]", p);
|
|
468
|
+
good = false;
|
|
469
|
+
return [close < 0 ? p + 1 : close + 1, true];
|
|
470
|
+
}
|
|
471
|
+
const n = Number(m[1]);
|
|
472
|
+
if (n < 1 || n > a.length) good = false;
|
|
473
|
+
else argNum = n - 1;
|
|
474
|
+
return [p + m[0].length, true];
|
|
475
|
+
};
|
|
476
|
+
const intArg = () => {
|
|
477
|
+
if (argNum >= a.length) return null;
|
|
478
|
+
const x = typedArg(a[argNum++]).v;
|
|
479
|
+
return typeof x === "number" && Number.isInteger(x) && Math.abs(x) <= 1e6 ? x : null;
|
|
480
|
+
};
|
|
481
|
+
for (let p = 0; p < f.length;) {
|
|
482
|
+
const pct = f.indexOf("%", p);
|
|
483
|
+
if (pct < 0) { out += f.slice(p); break; }
|
|
484
|
+
out += f.slice(p, pct);
|
|
485
|
+
p = pct + 1;
|
|
486
|
+
const fl = { plus: false, minus: false, sharp: false, space: false, zero: false };
|
|
487
|
+
for (; p < f.length; p++) {
|
|
488
|
+
const c = f[p];
|
|
489
|
+
if (c === "#") fl.sharp = true;
|
|
490
|
+
else if (c === "0") fl.zero = true;
|
|
491
|
+
else if (c === "+") fl.plus = true;
|
|
492
|
+
else if (c === "-") fl.minus = true;
|
|
493
|
+
else if (c === " ") fl.space = true;
|
|
494
|
+
else break;
|
|
495
|
+
}
|
|
496
|
+
good = true;
|
|
497
|
+
let after;
|
|
498
|
+
[p, after] = argIndex(p, false);
|
|
499
|
+
let wid = 0, hasWid = false, prec = 0, hasPrec = false;
|
|
500
|
+
if (f[p] === "*") {
|
|
501
|
+
p++;
|
|
502
|
+
const w = intArg();
|
|
503
|
+
if (w === null) out += "%!(BADWIDTH)";
|
|
504
|
+
else { wid = w; hasWid = true; }
|
|
505
|
+
if (wid < 0) { wid = -wid; fl.minus = true; }
|
|
506
|
+
after = false;
|
|
507
|
+
} else {
|
|
508
|
+
const m = /^\d+/.exec(f.slice(p));
|
|
509
|
+
if (m) { wid = Number(m[0]); hasWid = true; p += m[0].length; if (after) good = false; }
|
|
510
|
+
}
|
|
511
|
+
if (f[p] === ".") {
|
|
512
|
+
p++;
|
|
513
|
+
if (after) good = false;
|
|
514
|
+
[p, after] = argIndex(p, false);
|
|
515
|
+
if (f[p] === "*") {
|
|
516
|
+
p++;
|
|
517
|
+
const q = intArg();
|
|
518
|
+
if (q === null) out += "%!(BADPREC)";
|
|
519
|
+
else if (q >= 0) { prec = q; hasPrec = true; }
|
|
520
|
+
after = false;
|
|
521
|
+
} else {
|
|
522
|
+
const m = /^\d+/.exec(f.slice(p));
|
|
523
|
+
if (m) { prec = Number(m[0]); p += m[0].length; }
|
|
524
|
+
hasPrec = true;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
if (!after) [p, after] = argIndex(p, false);
|
|
528
|
+
if (p >= f.length) { out += "%!(NOVERB)"; break; }
|
|
529
|
+
const cp = f.codePointAt(p);
|
|
530
|
+
const verb = String.fromCodePoint(cp);
|
|
531
|
+
p += verb.length;
|
|
532
|
+
if (verb === "%") { out += "%"; continue; }
|
|
533
|
+
if (!good) { out += "%!" + verb + "(BADINDEX)"; continue; }
|
|
534
|
+
if (argNum >= a.length) { out += "%!" + verb + "(MISSING)"; continue; }
|
|
535
|
+
let { v, t } = typedArg(a[argNum++]);
|
|
536
|
+
if (v === null || v === undefined) {
|
|
537
|
+
const bt0 = U.baseOf(t);
|
|
538
|
+
if (bt0?.k === "slice" && verb === "v" && fl.sharp) { out += U.typeName(t) + "(nil)"; continue; }
|
|
539
|
+
}
|
|
540
|
+
sharp = verb === "v" && fl.sharp;
|
|
541
|
+
// The stand-in for a nil pointer with a pointer-receiver String/Error only serves %v and %s.
|
|
542
|
+
if (v && v.__nilp === true && !(verb === "s" || verb === "q" || (verb === "v" && !sharp))) v = null;
|
|
543
|
+
if (verb === "T") { out += U.pad(U.typeName(t ?? U.descOf(unbox(v, "T"))), fl, wid); continue; }
|
|
544
|
+
if (verb === "v" && hasPrec && !sharp) {
|
|
545
|
+
// A precision applies to each scalar (%.3v of 3.14159 is 3.14, of "abc" is abc cut to 3 runes).
|
|
546
|
+
out += fmtv("v", v, t, fl, wid, hasWid, prec, hasPrec, true);
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
if (verb === "v") {
|
|
550
|
+
if (v === null || v === undefined) {
|
|
551
|
+
const bt0 = U.baseOf(t);
|
|
552
|
+
v = bt0?.k === "slice" ? [] : v;
|
|
553
|
+
}
|
|
554
|
+
const vStr = t?.n === "time.Duration" && typeof __durationString === "function" ? __durationString(v) : formatV(unbox(v, "v"), fl.plus, true, false, U.both(t, v?.__fd));
|
|
555
|
+
out += U.pad(sharp ? U.gs(v, t, true) : vStr, fl, wid);
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
if (verb === "w") {
|
|
559
|
+
out += U.pad(String(v == null ? "<nil>" : typeof v === "object" && v.Error ? v.Error() : v), fl, wid);
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
if (verb === "p") { out += bad("p", v, t); continue; }
|
|
563
|
+
if (!"bcdoOqxXUeEfFgGstp".includes(verb)) { out += bad(verb, v, t); continue; }
|
|
564
|
+
out += fmtv(verb, v, t, fl, wid, hasWid, prec, hasPrec, true);
|
|
565
|
+
}
|
|
566
|
+
if (!reordered && argNum < a.length) {
|
|
567
|
+
out += "%!(EXTRA " + a.slice(argNum).map((x) => {
|
|
568
|
+
const y = typedArg(x);
|
|
569
|
+
return y.v === null || y.v === undefined ? "<nil>" : U.typeName(y.t ?? U.descOf(y.v)) + "=" + formatV(y.v, false, true);
|
|
570
|
+
}).join(", ") + ")";
|
|
571
|
+
}
|
|
572
|
+
return out;
|
|
573
|
+
};`;
|