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
@@ -7,6 +7,7 @@
7
7
  // (e.g. Identity$int, Box$int, Stack$int.Push) and re-typechecks the monomorphised AST.
8
8
 
9
9
  import { TypeChecker } from "../../typechecker/index.js";
10
+ import { goTypeName } from "../shared/fmt-types.js";
10
11
 
11
12
  /**
12
13
  * Returns true if the AST contains any generic declarations.
@@ -72,9 +73,20 @@ function rawTypeKey(t) {
72
73
  if (t.kind === "map" || t.kind === "MapType") {
73
74
  return `map_${typeKey(t.key)}_${typeKey(t.value)}`;
74
75
  }
75
- if (t.kind === "func" || t.kind === "FuncType") {
76
+ if (t.kind === "func") {
76
77
  const params = (t.params ?? []).map(typeKey).join("_");
77
- const rets = (t.returns ?? []).map(typeKey).join("_");
78
+ const rets = (t.returns ?? [])
79
+ .filter((r) => !(r?.kind === "basic" && r.name === "void"))
80
+ .map(typeKey)
81
+ .join("_");
82
+ return `fn_${params}_ret_${rets}`;
83
+ }
84
+ if (t.kind === "FuncType") {
85
+ const params = (t.params ?? []).map((p) => typeKey(p.type)).join("_");
86
+ const rt = t.returnType;
87
+ const rets = rt
88
+ ? (rt.kind === "TupleType" ? rt.types : [rt]).map(typeKey).join("_")
89
+ : "";
78
90
  return `fn_${params}_ret_${rets}`;
79
91
  }
80
92
  if (t.name) return t.name;
@@ -118,7 +130,11 @@ export function typeToTypeNode(t) {
118
130
  if (t.kind === "array") {
119
131
  return {
120
132
  kind: "ArrayType",
121
- len: t.len ?? t.size ?? 0,
133
+ size: {
134
+ kind: "BasicLit",
135
+ litKind: "INT",
136
+ value: String(t.len ?? t.size ?? 0),
137
+ },
122
138
  elem: typeToTypeNode(t.elem),
123
139
  };
124
140
  }
@@ -130,16 +146,77 @@ export function typeToTypeNode(t) {
130
146
  };
131
147
  }
132
148
  if (t.kind === "typeParam") return { kind: "TypeName", name: t.name };
149
+ // Without this a func type argument fell through to `any`, so a
150
+ // `map[string]V` built in `mk[func()]` was a `map[string]any`.
151
+ if (t.kind === "func") return funcTypeNode(t);
133
152
  return { kind: "TypeName", name: t.name ?? "any" };
134
153
  }
135
154
 
155
+ // A checker func type as a `FuncType` node (several results as a `TupleType`).
156
+ function funcTypeNode(t) {
157
+ // A variadic func lists its last parameter by element type.
158
+ const params = (t.params ?? []).map((p, i, all) => ({
159
+ name: "_",
160
+ type: typeToTypeNode(p),
161
+ variadic: !!t.variadic && i === all.length - 1,
162
+ }));
163
+ const rets = (t.returns ?? []).filter(
164
+ (r) => !(r?.kind === "basic" && r.name === "void"),
165
+ );
166
+ // Several results come as one tuple type or as a list.
167
+ const results = rets.length === 1 && rets[0]?.types ? rets[0].types : rets;
168
+ let returnType = null;
169
+ if (results.length === 1) returnType = typeToTypeNode(results[0]);
170
+ else if (results.length > 1)
171
+ returnType = { kind: "TupleType", types: results.map(typeToTypeNode) };
172
+ return { kind: "FuncType", params, returnType };
173
+ }
174
+
175
+ // Replaces the type parameters inside a checker type (`[]E`, `map[K]V`,
176
+ // `Box[E]`) by their type arguments; the result mixes checker types and the
177
+ // AST type nodes of the substitution, which `typeKey` and `typeToTypeNode`
178
+ // both accept.
179
+ function substituteInType(t, map) {
180
+ if (!t || typeof t !== "object") return t;
181
+ const sub = (x) => substituteInType(x, map);
182
+ switch (t.kind) {
183
+ case "typeParam":
184
+ return map.has(t.name) ? map.get(t.name) : t;
185
+ case "slice":
186
+ case "array":
187
+ return { ...t, elem: sub(t.elem) };
188
+ case "pointer":
189
+ return { ...t, base: sub(t.base) };
190
+ case "map":
191
+ return { ...t, key: sub(t.key), value: sub(t.value) };
192
+ case "func":
193
+ return {
194
+ ...t,
195
+ params: (t.params ?? []).map(sub),
196
+ returns: (t.returns ?? []).map(sub),
197
+ };
198
+ case "named":
199
+ return t.typeArgs?.length ? { ...t, typeArgs: t.typeArgs.map(sub) } : t;
200
+ default:
201
+ return t;
202
+ }
203
+ }
204
+
205
+ // A partial instantiation (`Grow[S](nil, n)`) lists only the explicit type
206
+ // arguments; the checker recorded the complete list, which replaces it.
207
+ function completeTypeArgs(node, typeSubstMap) {
208
+ if (node._typeArgs?.length > (node.typeArgs?.length ?? 0))
209
+ return node._typeArgs.map((t) => substituteInType(t, typeSubstMap));
210
+ return node.typeArgs;
211
+ }
212
+
136
213
  function getSpecializedName(baseName, typeArgs) {
137
214
  if (!typeArgs || typeArgs.length === 0) return baseName;
138
215
  const keys = typeArgs.map(typeKey).join("$");
139
216
  return `${baseName}$${keys}`;
140
217
  }
141
218
 
142
- const KEPT_CLONE_KEYS = new Set(["_typeArgs", "_line", "_col"]);
219
+ const KEPT_CLONE_KEYS = new Set(["_typeArgs", "_line", "_col", "_spread"]);
143
220
 
144
221
  function cloneAst(node) {
145
222
  if (!node || typeof node !== "object") return node;
@@ -252,6 +329,7 @@ function substituteTypesInAst(
252
329
  }
253
330
  const baseName = node.expr?.name;
254
331
  if (baseName) {
332
+ node.typeArgs = completeTypeArgs(node, typeSubstMap);
255
333
  const sName = getSpecializedName(baseName, node.typeArgs);
256
334
  const isType = genericTypes ? genericTypes.has(baseName) : false;
257
335
  if (onGenericUsage) {
@@ -271,6 +349,13 @@ function substituteTypesInAst(
271
349
  // 3b. CompositeLit
272
350
  if (node.kind === "CompositeLit") {
273
351
  const targetProp = node.typeExpr ? "typeExpr" : node.type ? "type" : null;
352
+ // `S{a, b}` with S a type parameter: the type is a bare identifier.
353
+ if (
354
+ targetProp &&
355
+ node[targetProp]?.kind === "Ident" &&
356
+ typeSubstMap.has(node[targetProp].name)
357
+ )
358
+ node[targetProp] = cloneAst(typeSubstMap.get(node[targetProp].name));
274
359
  if (targetProp && node[targetProp]) {
275
360
  node[targetProp] = substituteTypesInAst(
276
361
  node[targetProp],
@@ -301,6 +386,18 @@ function substituteTypesInAst(
301
386
  _line: node._line,
302
387
  };
303
388
  }
389
+ // `make(S, n)` / `new(S)`: the type argument is a bare identifier.
390
+ if (
391
+ node.func?.kind === "Ident" &&
392
+ (node.func.name === "make" || node.func.name === "new") &&
393
+ node.args?.[0]?.kind === "Ident" &&
394
+ typeSubstMap.has(node.args[0].name)
395
+ ) {
396
+ node.args[0] = {
397
+ kind: "TypeExpr",
398
+ type: cloneAst(typeSubstMap.get(node.args[0].name)),
399
+ };
400
+ }
304
401
  if (node.func?.kind === "Ident") {
305
402
  let typeArgs = node._typeArgs ?? node.func._typeArgs;
306
403
  if (typeArgs) {
@@ -309,7 +406,7 @@ function substituteTypesInAst(
309
406
  if (name && typeSubstMap.has(name)) {
310
407
  return typeSubstMap.get(name);
311
408
  }
312
- return t;
409
+ return substituteInType(t, typeSubstMap);
313
410
  });
314
411
  const baseName = node.func.name;
315
412
  const sName = getSpecializedName(baseName, typeArgs);
@@ -559,9 +656,14 @@ export function monomorphise(programs, checker) {
559
656
  const genericFuncs = new Map();
560
657
  const genericTypes = new Map();
561
658
  const genericMethods = new Map(); // recvBaseName -> Array<MethodDecl>
659
+ // Template declaration -> its program; a specialization joins the program
660
+ // of its template, so a wasm package's instances stay wasm-package
661
+ // declarations even when a Go-source stdlib package is linked first.
662
+ const homeOf = new Map();
562
663
 
563
664
  for (const p of progs) {
564
665
  for (const d of p?.decls ?? []) {
666
+ homeOf.set(d, p);
565
667
  if (d.kind === "FuncDecl" && d.typeParams && d.typeParams.length > 0) {
566
668
  genericFuncs.set(d.name, d);
567
669
  } else if (
@@ -611,6 +713,7 @@ export function monomorphise(programs, checker) {
611
713
  }
612
714
  }
613
715
 
716
+ const typeInstances = new Map();
614
717
  const specializedFuncs = new Map();
615
718
  const specializedTypes = new Map();
616
719
  const specializedMethods = new Map();
@@ -638,6 +741,7 @@ export function monomorphise(programs, checker) {
638
741
  typeSubstMap.set(tp.name, typeToTypeNode(concrete));
639
742
  }
640
743
 
744
+ typeInstances.set(item.specializedName, item);
641
745
  const monoTypeDecl = cloneAst(genDecl);
642
746
  monoTypeDecl.name = item.specializedName;
643
747
  monoTypeDecl.typeParams = null;
@@ -650,6 +754,7 @@ export function monomorphise(programs, checker) {
650
754
  );
651
755
  rebindNamedResults(monoTypeDecl);
652
756
  specializedTypes.set(item.specializedName, monoTypeDecl);
757
+ homeOf.set(monoTypeDecl, homeOf.get(genDecl));
653
758
 
654
759
  // Specialize all methods declared on this generic type
655
760
  const methods = genericMethods.get(item.genericName) ?? [];
@@ -669,6 +774,7 @@ export function monomorphise(programs, checker) {
669
774
  rebindNamedResults(monoMethod);
670
775
  const mKey = `${item.specializedName}.${monoMethod.name}`;
671
776
  specializedMethods.set(mKey, monoMethod);
777
+ homeOf.set(monoMethod, homeOf.get(m));
672
778
  }
673
779
  } else if (item.kind === "func") {
674
780
  const genDecl = genericFuncs.get(item.genericName);
@@ -693,6 +799,7 @@ export function monomorphise(programs, checker) {
693
799
  );
694
800
  rebindNamedResults(monoFuncDecl);
695
801
  specializedFuncs.set(item.specializedName, monoFuncDecl);
802
+ homeOf.set(monoFuncDecl, homeOf.get(genDecl));
696
803
  }
697
804
  }
698
805
 
@@ -744,15 +851,22 @@ export function monomorphise(programs, checker) {
744
851
 
745
852
  const targetProg = progs[0];
746
853
  if (targetProg) {
747
- targetProg.decls.push(...specializedTypes.values());
748
- targetProg.decls.push(...specializedMethods.values());
749
- targetProg.decls.push(...specializedFuncs.values());
854
+ for (const group of [
855
+ specializedTypes,
856
+ specializedMethods,
857
+ specializedFuncs,
858
+ ])
859
+ for (const d of group.values())
860
+ (homeOf.get(d) ?? targetProg).decls.push(d);
750
861
  }
751
862
 
752
863
  // 6. Typecheck the monomorphised program to annotate all concrete types
753
864
  const monoChecker = new TypeChecker();
754
865
  monoChecker.target = "wasm";
755
866
  monoChecker.pkgName = targetProg?.pkg?.name ?? "main";
867
+ // The programs were checked once already, where `//gofront:native` is
868
+ // limited to the standard library; this pass only re-annotates them.
869
+ monoChecker.nativesChecked = true;
756
870
  if (checker?.types) {
757
871
  for (const [name, type] of checker.types.entries()) {
758
872
  if (!monoChecker.types.has(name)) {
@@ -764,6 +878,23 @@ export function monomorphise(programs, checker) {
764
878
  // One pass over all programs: declarations of every linked package are
765
879
  // visible to the others (cross-package references are dequalified).
766
880
  monoChecker.checkAll(progs);
881
+ nameInstances(monoChecker, typeInstances);
767
882
 
768
883
  return { programs: progs, checker: monoChecker };
769
884
  }
885
+
886
+ // Records Go's spelling of each generic instance (`Box[int]`) on its
887
+ // monomorphised type, which is named `Box$int`; `%T` prints the spelling.
888
+ function nameInstances(checker, instances) {
889
+ const spelling = {
890
+ has: (name) => instances.has(name),
891
+ get: (name) => {
892
+ const { genericName, typeArgs } = instances.get(name);
893
+ return `${genericName}[${typeArgs.map((a) => goTypeName(a, spelling)).join(",")}]`;
894
+ },
895
+ };
896
+ for (const name of instances.keys()) {
897
+ const type = checker.types.get(name);
898
+ if (type) type._goName = spelling.get(name);
899
+ }
900
+ }