gofront 1.8.0 → 1.9.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 (177) hide show
  1. package/README.md +3 -3
  2. package/package.json +5 -4
  3. package/src/backend/js/expressions.js +849 -371
  4. package/src/backend/js/index.js +241 -147
  5. package/src/backend/js/natives.js +383 -0
  6. package/src/backend/js/runtime.js +512 -2547
  7. package/src/backend/js/statements.js +506 -103
  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 +177 -13
  11. package/src/backend/shared/fixed-float.js +20 -0
  12. package/src/backend/shared/fmt-types.js +63 -171
  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 +643 -256
  16. package/src/backend/wasm/emit-exprs.js +124 -57
  17. package/src/backend/wasm/emit-maps.js +17 -367
  18. package/src/backend/wasm/emit-stmts.js +325 -75
  19. package/src/backend/wasm/emit.js +104 -13
  20. package/src/backend/wasm/globals.js +47 -8
  21. package/src/backend/wasm/glue.js +2 -4
  22. package/src/backend/wasm/index.js +36 -530
  23. package/src/backend/wasm/method-expr.js +12 -1
  24. package/src/backend/wasm/module-emitter.js +92 -717
  25. package/src/backend/wasm/monomorph.js +103 -6
  26. package/src/backend/wasm/natives.js +596 -0
  27. package/src/backend/wasm/prescan.js +5 -153
  28. package/src/backend/wasm/prune-funcs.js +89 -0
  29. package/src/backend/wasm/stdlib/index.js +2 -32
  30. package/src/backend/wasm/types.js +68 -20
  31. package/src/backend/wasm/variadic.js +3 -3
  32. package/src/cli/cli-core.js +5 -1
  33. package/src/cli/test-runner.js +115 -342
  34. package/src/compiler.js +108 -130
  35. package/src/lexer/lexer.js +105 -11
  36. package/src/lexer/templ-lexer.js +61 -18
  37. package/src/lexer/tokens.js +1 -0
  38. package/src/link/stdlib.js +354 -132
  39. package/src/link/type-names.js +148 -0
  40. package/src/link/wasm.js +30 -6
  41. package/src/lower/bounds.js +153 -0
  42. package/src/lower/captures.js +92 -33
  43. package/src/lower/embedding.js +32 -3
  44. package/src/lower/errors-as.js +196 -0
  45. package/src/lower/fmt-formatters.js +905 -0
  46. package/src/lower/functions.js +2 -0
  47. package/src/lower/gen-types.js +274 -0
  48. package/src/lower/index.js +7 -1
  49. package/src/lower/json-codecs.js +228 -247
  50. package/src/lower/ownership.js +25 -7
  51. package/src/lower/reachability.js +69 -51
  52. package/src/lower/walk.js +12 -0
  53. package/src/parser/declarations.js +28 -5
  54. package/src/parser/expressions.js +86 -16
  55. package/src/parser/statements.js +1 -0
  56. package/src/parser/templ.js +44 -5
  57. package/src/parser/types.js +1 -0
  58. package/src/resolver.js +1 -2
  59. package/src/typechecker/assignability.js +124 -11
  60. package/src/typechecker/const-fold.js +70 -27
  61. package/src/typechecker/constants.js +32 -6
  62. package/src/typechecker/expressions.js +326 -98
  63. package/src/typechecker/index.js +208 -33
  64. package/src/typechecker/init-order.js +136 -40
  65. package/src/typechecker/operand-text.js +40 -0
  66. package/src/typechecker/resolve.js +192 -36
  67. package/src/typechecker/statements.js +122 -11
  68. package/src/typechecker/stdlib/excluded.js +9 -5
  69. package/src/typechecker/stdlib/index.js +25 -9
  70. package/src/typechecker/termination.js +10 -1
  71. package/src/typechecker/types.js +203 -573
  72. package/stdlib/bytes/buffer.go +479 -0
  73. package/stdlib/bytes/bytes.go +1010 -0
  74. package/stdlib/bytes/reader.go +161 -0
  75. package/stdlib/context/context.go +115 -0
  76. package/stdlib/crypto/rand/rand.go +34 -0
  77. package/stdlib/crypto/sha256/sha256.go +249 -0
  78. package/stdlib/encoding/base64/base64.go +331 -0
  79. package/stdlib/encoding/binary/binary.go +332 -0
  80. package/stdlib/encoding/hex/hex.go +140 -0
  81. package/stdlib/encoding/json/json.go +62 -0
  82. package/stdlib/errors/errors.go +174 -0
  83. package/stdlib/fmt/errors.go +110 -0
  84. package/stdlib/fmt/format.go +732 -0
  85. package/stdlib/fmt/print.go +1232 -0
  86. package/stdlib/gom/gom.go +293 -0
  87. package/stdlib/html/html.go +251 -0
  88. package/stdlib/internal/fmtrt/fmtrt.go +163 -0
  89. package/stdlib/internal/jsonrt/dec.go +171 -38
  90. package/stdlib/internal/jsonrt/enc.go +186 -36
  91. package/stdlib/internal/jsonrt/scanner.go +17 -8
  92. package/stdlib/io/io.go +157 -1
  93. package/stdlib/maps/maps.go +131 -0
  94. package/stdlib/math/bits/bits.go +507 -0
  95. package/stdlib/math/extra.go +16 -14
  96. package/stdlib/math/math.go +439 -0
  97. package/stdlib/math/rand/rand.go +297 -0
  98. package/stdlib/os/os.go +93 -0
  99. package/stdlib/path/filepath/filepath.go +47 -0
  100. package/stdlib/path/path.go +394 -0
  101. package/stdlib/regexp/regexp.go +231 -0
  102. package/stdlib/slices/slices.go +526 -0
  103. package/stdlib/slices/sort.go +209 -0
  104. package/stdlib/slices/zsort_cmp.go +480 -0
  105. package/stdlib/slices/zsort_ordered.go +482 -0
  106. package/stdlib/sort/sort.go +391 -452
  107. package/stdlib/sort/zsort_func.go +480 -0
  108. package/stdlib/sort/zsort_iface.go +480 -0
  109. package/stdlib/strconv/float.go +1699 -0
  110. package/stdlib/strconv/isprint.go +752 -0
  111. package/stdlib/strconv/quote.go +235 -50
  112. package/stdlib/strconv/strconv.go +616 -0
  113. package/stdlib/strings/builder.go +95 -0
  114. package/stdlib/strings/reader.go +163 -0
  115. package/stdlib/strings/replacer.go +102 -0
  116. package/stdlib/strings/strings.go +807 -0
  117. package/stdlib/sync/sync.go +268 -0
  118. package/stdlib/testing/async_js.go +61 -0
  119. package/stdlib/testing/benchmark.go +297 -0
  120. package/stdlib/testing/testing.go +523 -0
  121. package/stdlib/time/duration.go +233 -0
  122. package/stdlib/time/format.go +745 -0
  123. package/stdlib/time/parse.go +790 -0
  124. package/stdlib/time/sleep_js.go +63 -0
  125. package/stdlib/time/time.go +834 -0
  126. package/stdlib/unicode/unicode.go +141 -3
  127. package/stdlib/unicode/utf8/utf8.go +464 -0
  128. package/src/backend/js/fmt-runtime.js +0 -573
  129. package/src/backend/js/stdlib/base64.js +0 -12
  130. package/src/backend/js/stdlib/binary.js +0 -102
  131. package/src/backend/js/stdlib/bits.js +0 -119
  132. package/src/backend/js/stdlib/builder.js +0 -98
  133. package/src/backend/js/stdlib/bytes.js +0 -368
  134. package/src/backend/js/stdlib/errors.js +0 -45
  135. package/src/backend/js/stdlib/fmt.js +0 -517
  136. package/src/backend/js/stdlib/gom.js +0 -155
  137. package/src/backend/js/stdlib/hex.js +0 -17
  138. package/src/backend/js/stdlib/html.js +0 -20
  139. package/src/backend/js/stdlib/io.js +0 -137
  140. package/src/backend/js/stdlib/json.js +0 -1167
  141. package/src/backend/js/stdlib/maps.js +0 -37
  142. package/src/backend/js/stdlib/math.js +0 -85
  143. package/src/backend/js/stdlib/os.js +0 -13
  144. package/src/backend/js/stdlib/path.js +0 -48
  145. package/src/backend/js/stdlib/rand.js +0 -32
  146. package/src/backend/js/stdlib/regexp.js +0 -54
  147. package/src/backend/js/stdlib/sha256.js +0 -12
  148. package/src/backend/js/stdlib/shared.js +0 -17
  149. package/src/backend/js/stdlib/simd.js +0 -34
  150. package/src/backend/js/stdlib/slices.js +0 -107
  151. package/src/backend/js/stdlib/sort.js +0 -30
  152. package/src/backend/js/stdlib/strconv.js +0 -79
  153. package/src/backend/js/stdlib/strings.js +0 -301
  154. package/src/backend/js/stdlib/sync.js +0 -13
  155. package/src/backend/js/stdlib/testing.js +0 -41
  156. package/src/backend/js/stdlib/time.js +0 -152
  157. package/src/backend/js/stdlib/unicode.js +0 -25
  158. package/src/backend/js/stdlib/utf8.js +0 -26
  159. package/src/backend/wasm/stdlib/bytes.js +0 -6716
  160. package/src/backend/wasm/stdlib/core.js +0 -10278
  161. package/src/backend/wasm/stdlib/io.js +0 -3578
  162. package/src/backend/wasm/stdlib/packages.js +0 -2402
  163. package/src/backend/wasm/stdlib/pure.js +0 -720
  164. package/src/backend/wasm/stdlib/time.js +0 -2229
  165. package/src/typechecker/stdlib/core.js +0 -1079
  166. package/src/typechecker/stdlib/extended.js +0 -1210
  167. package/stdlib/bytes/iter.go +0 -192
  168. package/stdlib/bytes/search.go +0 -240
  169. package/stdlib/bytes/split.go +0 -218
  170. package/stdlib/errors/overlay.go +0 -12
  171. package/stdlib/maps/iter.go +0 -65
  172. package/stdlib/slices/extra.go +0 -73
  173. package/stdlib/slices/iter.go +0 -113
  174. package/stdlib/strings/extra.go +0 -35
  175. package/stdlib/strings/iter.go +0 -122
  176. package/stdlib/sync/extra.go +0 -105
  177. package/stdlib/unicode/utf8/bytes.go +0 -239
@@ -1,188 +1,80 @@
1
- // Static type descriptors for `fmt` (Task 3.1c), shared by the JS and WASM
2
- // backends. `%T` and `%#v` need the Go type of an operand, which the runtime
3
- // values do not carry (an `int` and a `float64` holding 3 are both the number
4
- // 3, a `Color` is a raw number inside a slice). Where a format string is a
5
- // literal that needs them (`fmtWantsTypes`), codegen passes the operand's
6
- // static type next to its value as a plain JSON-compatible tree, which
7
- // `__sprintf` reads (`__ft` on JS, `fmt_arg_type` on WASM).
8
- //
9
- // Descriptor shapes (`k`): `b` basic `{ n }`, `named` `{ n, u }` (a named
10
- // non-struct type, `u` its underlying type), `struct` `{ n, f: [[name, T]] }`
11
- // (`n` is "" for an anonymous struct), `ptr` `{ e }`, `slice` `{ e }`,
12
- // `array` `{ e, len }`, `map` `{ key, val }`, `i` an interface `{ n }`,
13
- // `func` `{ p, r }`, `chan` `{ e }`. A type that is too deep or unknown is
14
- // `null`; the runtime then derives a best-effort type from the value.
1
+ // Go's `reflect` spelling of a type used as a type argument (the monomorphiser
2
+ // records it for `%T` of a type-parameter operand), shared by the JS and WASM
3
+ // backends.
15
4
 
16
- const MAX_DEPTH = 4;
17
- const FLAGS = "#+\\- 0";
18
- const VERBS = "vTtcdoObxXUeEfFgGsqp";
5
+ const qualify = (name) =>
6
+ name.split("[")[0].includes(".") ? name : `main.${name}`;
19
7
 
20
- const qualify = (name) => (name.includes(".") ? name : `main.${name}`);
8
+ const PREDECLARED = new Set([
9
+ "bool",
10
+ "string",
11
+ "int",
12
+ "int8",
13
+ "int16",
14
+ "int32",
15
+ "int64",
16
+ "uint",
17
+ "uint8",
18
+ "uint16",
19
+ "uint32",
20
+ "uint64",
21
+ "uintptr",
22
+ "float32",
23
+ "float64",
24
+ "complex64",
25
+ "complex128",
26
+ "byte",
27
+ "rune",
28
+ "error",
29
+ ]);
21
30
 
22
31
  /**
23
- * @param {any} t checker type
24
- * @param {(t: any) => any} [resolve] resolves a type reference
25
- * @param {number} [depth]
26
- * @returns {object | null}
32
+ * Go's `reflect` spelling of a type used as a type argument: `int`,
33
+ * `main.Foo`, `[]main.Foo`. Takes checker types and parsed type nodes;
34
+ * `specialized` maps the names of monomorphised instances to their spelling.
35
+ * @param {any} t
36
+ * @param {Map<string, string>} [specialized]
37
+ * @returns {string}
27
38
  */
28
- export function fmtTypeDesc(t, resolve = (x) => x, depth = 0) {
29
- t = resolve(t) ?? t;
30
- if (!t) return null;
31
- const sub = (x) => fmtTypeDesc(x, resolve, depth + 1);
32
- switch (t.kind) {
39
+ export function goTypeName(t, specialized = null) {
40
+ const go = (x) => goTypeName(x, specialized);
41
+ switch (t?.kind) {
33
42
  case "basic":
34
- if (t.name === "any") return { k: "i", n: "interface {}" };
35
- if (t.name === "nil" || t.name === "void") return null;
36
- return { k: "b", n: t.name };
43
+ return t.name === "any" ? "interface {}" : t.name;
37
44
  case "untyped":
38
- return { k: "b", n: t.base };
39
- case "interface":
40
- return { k: "i", n: t.name ? qualify(t.name) : "interface {}" };
45
+ return t.base;
46
+ case "TypeName":
47
+ case "Ident":
48
+ if (specialized?.has(t.name)) return qualify(specialized.get(t.name));
49
+ if (t.name === "any") return "interface {}";
50
+ return PREDECLARED.has(t.name) ? t.name : qualify(t.name);
51
+ case "GenericTypeName":
52
+ return qualify(`${t.name}[${t.typeArgs.map(go).join(",")}]`);
41
53
  case "named":
42
- return namedDesc(t, resolve, depth, sub);
43
- case "struct":
44
- return depth > MAX_DEPTH ? null : structDesc("", t, sub);
54
+ return qualify(instanceName(t, specialized));
55
+ case "interface":
56
+ return t.name ? qualify(t.name) : "interface {}";
45
57
  case "pointer":
46
- return depth > MAX_DEPTH ? null : { k: "ptr", e: sub(t.base) };
47
- case "slice":
48
- return depth > MAX_DEPTH ? null : { k: "slice", e: sub(t.elem) };
49
- case "array":
50
- return depth > MAX_DEPTH
51
- ? null
52
- : { k: "array", e: sub(t.elem), len: t.size ?? 0 };
53
- case "map":
54
- return depth > MAX_DEPTH
55
- ? null
56
- : { k: "map", key: sub(t.key), val: sub(t.value) };
57
- case "func":
58
- return {
59
- k: "func",
60
- p: (t.params ?? []).map(sub),
61
- r: (t.returns ?? []).map(sub),
62
- v: Boolean(t.variadic),
63
- };
64
- case "chan":
65
- return { k: "chan", e: sub(t.elem) };
66
- default:
67
- return null;
68
- }
69
- }
70
-
71
- /**
72
- * The fields a struct declares itself, in declaration order: named fields and
73
- * one entry per embedded type. Fields promoted from an embedded struct are
74
- * not listed (`fields` also holds them for selector lookup).
75
- * @param {any} st checker struct type
76
- * @returns {[string, any][]}
77
- */
78
- export function structOwnFields(st) {
79
- if (!st._structFields) return [...(st.fields ?? [])];
80
- const own = [];
81
- for (const sf of st._structFields) {
82
- if (!sf.embedded) {
83
- for (const n of sf.names) own.push([n, st.fields.get(n)]);
84
- continue;
85
- }
86
- const inner = sf.type?.kind === "pointer" ? sf.type.base : sf.type;
87
- const name = (
88
- sf.embeddedName ??
89
- sf.astType?.name ??
90
- sf.type?.name ??
91
- sf.type?.base?.name ??
92
- (inner?.kind === "named" ? inner.name : "")
93
- )
94
- .split(".")
95
- .pop();
96
- if (name) own.push([name, st.fields.get(name) ?? sf.type]);
97
- }
98
- return own;
99
- }
100
-
101
- function structDesc(n, st, sub) {
102
- const f = [];
103
- for (const [name, ft] of structOwnFields(st)) f.push([name, sub(ft)]);
104
- return { k: "struct", n, f };
105
- }
106
-
107
- function namedDesc(t, resolve, depth, sub) {
108
- const n = qualify(t.name ?? "");
109
- const u = resolve(t.underlying) ?? t.underlying;
110
- if (!u) return { k: "named", n, u: null };
111
- if (u.kind === "struct")
112
- return depth > MAX_DEPTH
113
- ? { k: "struct", n, f: null }
114
- : structDesc(n, u, sub);
115
- if (u.kind === "interface") return { k: "i", n };
116
- return { k: "named", n, u: depth > MAX_DEPTH ? null : sub(u) };
117
- }
118
-
119
- /**
120
- * Whether a type descriptor mentions a float32 or float64. Such operands
121
- * travel with their static type: a number alone cannot tell `float64(1e6)`
122
- * (Go prints 1e+06) from an `int`, or a float32 from the float64 holding the
123
- * same bits.
124
- * @param {any} desc result of fmtTypeDesc
125
- * @returns {boolean}
126
- */
127
- export function fmtDescHasFloat(desc) {
128
- if (!desc || typeof desc !== "object") return false;
129
- switch (desc.k) {
130
- case "b":
131
- return desc.n === "float32" || desc.n === "float64";
132
- case "named":
133
- return fmtDescHasFloat(desc.u);
134
- case "struct":
135
- return (desc.f ?? []).some(([, ft]) => fmtDescHasFloat(ft));
136
- case "ptr":
58
+ case "PointerType":
59
+ return `*${go(t.base)}`;
137
60
  case "slice":
61
+ case "SliceType":
62
+ return `[]${go(t.elem)}`;
138
63
  case "array":
139
- return fmtDescHasFloat(desc.e);
64
+ case "ArrayType":
65
+ return `[${t.size ?? 0}]${go(t.elem)}`;
140
66
  case "map":
141
- return fmtDescHasFloat(desc.key) || fmtDescHasFloat(desc.val);
67
+ case "MapType":
68
+ return `map[${go(t.key)}]${go(t.value)}`;
142
69
  default:
143
- return false;
70
+ return "interface {}";
144
71
  }
145
72
  }
146
73
 
147
- /**
148
- * Whether a type descriptor is a slice or array (possibly named). `%s`, `%q`
149
- * and `%x` read a byte slice as text, which a plain list of numbers cannot
150
- * tell from any other slice of small numbers.
151
- * @param {any} desc result of fmtTypeDesc
152
- * @returns {boolean}
153
- */
154
- export function fmtDescIsSeq(desc) {
155
- let d = desc;
156
- while (d?.k === "named") d = d.u;
157
- return d?.k === "slice" || d?.k === "array";
158
- }
159
-
160
- /**
161
- * Whether a call with this literal format string needs operand types: `%T`,
162
- * `%#v`, an unknown verb (`%!z(int=5)`), or more operands than verbs
163
- * (`%!(EXTRA int=1)`).
164
- * @param {unknown} format
165
- * @param {number} nargs operand count, -1 when not known statically
166
- * @param {boolean} [seqArgs] some operand is a slice or array, whose element
167
- * type decides how `%s`, `%q`, `%x` and `%X` read it
168
- */
169
- export function fmtWantsTypes(format, nargs, seqArgs = false) {
170
- if (typeof format !== "string") return false;
171
- const re = new RegExp(
172
- `%([${FLAGS}]*)((?:\\[\\d+\\])?(?:\\*|\\d+)?(?:\\.(?:\\[\\d+\\])?(?:\\*|\\d*))?(?:\\[\\d+\\])?)([^]?)`,
173
- "g",
174
- );
175
- let count = 0;
176
- let indexed = false;
177
- for (const m of format.matchAll(re)) {
178
- const verb = m[3];
179
- if (verb === "%") continue;
180
- if (verb === "T" || verb === "p") return true;
181
- if (verb === "v" && m[1].includes("#")) return true;
182
- if (seqArgs && "sqxX".includes(verb)) return true;
183
- if (verb !== "" && !VERBS.includes(verb) && verb !== "w") return true;
184
- if (/[[*]/.test(m[2])) indexed = true;
185
- count++;
186
- }
187
- return nargs >= 0 && !indexed && nargs > count;
74
+ // `Box[int]` for a generic instance: the checker's type arguments on JS, the
75
+ // spelling the monomorphiser recorded on WASM.
76
+ function instanceName(t, specialized = null) {
77
+ if (t._goName) return t._goName;
78
+ if (!t.typeArgs?.length) return t.name ?? "";
79
+ return `${t.name}[${t.typeArgs.map((a) => goTypeName(a, specialized)).join(",")}]`;
188
80
  }
@@ -0,0 +1,36 @@
1
+ // JS bodies of the host side of the unicode intrinsics (unicode_is,
2
+ // unicode_to_upper, unicode_to_lower). The JS backend inlines them as the
3
+ // intrinsic bodies and the WASM boundary ships them as `env` imports, so
4
+ // both targets answer from the same tables. Each takes the names of the
5
+ // parameters it reads and returns statements ending in a `return`.
6
+
7
+ // Classes, in the order of the constants in stdlib/unicode/unicode.go: the
8
+ // test of the one-code-point string `c`.
9
+ const CLASS_TESTS = [
10
+ "/\\p{L}/u.test(c)", // Letter
11
+ "/\\p{Nd}/u.test(c)", // Digit
12
+ "/[ \\t\\n\\v\\f\\r\\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]/.test(c)", // Space
13
+ "/\\p{Lu}/u.test(c)", // Upper
14
+ "/\\p{Ll}/u.test(c)", // Lower
15
+ "/\\p{P}/u.test(c)", // Punct
16
+ "/\\p{Cc}/u.test(c)", // Control
17
+ "!/\\p{Cc}/u.test(c)", // Print
18
+ "!/\\p{Cc}/u.test(c)", // Graphic
19
+ ];
20
+
21
+ export function unicodeIsJs(r, cls) {
22
+ const cases = CLASS_TESTS.map((test, i) => `case ${i}: return ${test};`).join(
23
+ " ",
24
+ );
25
+ return `const c = String.fromCodePoint(${r}); switch (${cls}) { ${cases} } return false;`;
26
+ }
27
+
28
+ // A letter whose upper case spans several code points (the German sharp s)
29
+ // stays as it is.
30
+ export function unicodeToUpperJs(r) {
31
+ return `const m = String.fromCodePoint(${r}).toUpperCase(); const u = m.codePointAt(0); return m.length > (u > 0xffff ? 2 : 1) ? ${r} : u;`;
32
+ }
33
+
34
+ export function unicodeToLowerJs(r) {
35
+ return `return String.fromCodePoint(${r}).toLowerCase().codePointAt(0);`;
36
+ }