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
@@ -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.
@@ -118,7 +119,11 @@ export function typeToTypeNode(t) {
118
119
  if (t.kind === "array") {
119
120
  return {
120
121
  kind: "ArrayType",
121
- len: t.len ?? t.size ?? 0,
122
+ size: {
123
+ kind: "BasicLit",
124
+ litKind: "INT",
125
+ value: String(t.len ?? t.size ?? 0),
126
+ },
122
127
  elem: typeToTypeNode(t.elem),
123
128
  };
124
129
  }
@@ -133,13 +138,51 @@ export function typeToTypeNode(t) {
133
138
  return { kind: "TypeName", name: t.name ?? "any" };
134
139
  }
135
140
 
141
+ // Replaces the type parameters inside a checker type (`[]E`, `map[K]V`,
142
+ // `Box[E]`) by their type arguments; the result mixes checker types and the
143
+ // AST type nodes of the substitution, which `typeKey` and `typeToTypeNode`
144
+ // both accept.
145
+ function substituteInType(t, map) {
146
+ if (!t || typeof t !== "object") return t;
147
+ const sub = (x) => substituteInType(x, map);
148
+ switch (t.kind) {
149
+ case "typeParam":
150
+ return map.has(t.name) ? map.get(t.name) : t;
151
+ case "slice":
152
+ case "array":
153
+ return { ...t, elem: sub(t.elem) };
154
+ case "pointer":
155
+ return { ...t, base: sub(t.base) };
156
+ case "map":
157
+ return { ...t, key: sub(t.key), value: sub(t.value) };
158
+ case "func":
159
+ return {
160
+ ...t,
161
+ params: (t.params ?? []).map(sub),
162
+ returns: (t.returns ?? []).map(sub),
163
+ };
164
+ case "named":
165
+ return t.typeArgs?.length ? { ...t, typeArgs: t.typeArgs.map(sub) } : t;
166
+ default:
167
+ return t;
168
+ }
169
+ }
170
+
171
+ // A partial instantiation (`Grow[S](nil, n)`) lists only the explicit type
172
+ // arguments; the checker recorded the complete list, which replaces it.
173
+ function completeTypeArgs(node, typeSubstMap) {
174
+ if (node._typeArgs?.length > (node.typeArgs?.length ?? 0))
175
+ return node._typeArgs.map((t) => substituteInType(t, typeSubstMap));
176
+ return node.typeArgs;
177
+ }
178
+
136
179
  function getSpecializedName(baseName, typeArgs) {
137
180
  if (!typeArgs || typeArgs.length === 0) return baseName;
138
181
  const keys = typeArgs.map(typeKey).join("$");
139
182
  return `${baseName}$${keys}`;
140
183
  }
141
184
 
142
- const KEPT_CLONE_KEYS = new Set(["_typeArgs", "_line", "_col"]);
185
+ const KEPT_CLONE_KEYS = new Set(["_typeArgs", "_line", "_col", "_spread"]);
143
186
 
144
187
  function cloneAst(node) {
145
188
  if (!node || typeof node !== "object") return node;
@@ -252,6 +295,7 @@ function substituteTypesInAst(
252
295
  }
253
296
  const baseName = node.expr?.name;
254
297
  if (baseName) {
298
+ node.typeArgs = completeTypeArgs(node, typeSubstMap);
255
299
  const sName = getSpecializedName(baseName, node.typeArgs);
256
300
  const isType = genericTypes ? genericTypes.has(baseName) : false;
257
301
  if (onGenericUsage) {
@@ -271,6 +315,13 @@ function substituteTypesInAst(
271
315
  // 3b. CompositeLit
272
316
  if (node.kind === "CompositeLit") {
273
317
  const targetProp = node.typeExpr ? "typeExpr" : node.type ? "type" : null;
318
+ // `S{a, b}` with S a type parameter: the type is a bare identifier.
319
+ if (
320
+ targetProp &&
321
+ node[targetProp]?.kind === "Ident" &&
322
+ typeSubstMap.has(node[targetProp].name)
323
+ )
324
+ node[targetProp] = cloneAst(typeSubstMap.get(node[targetProp].name));
274
325
  if (targetProp && node[targetProp]) {
275
326
  node[targetProp] = substituteTypesInAst(
276
327
  node[targetProp],
@@ -301,6 +352,18 @@ function substituteTypesInAst(
301
352
  _line: node._line,
302
353
  };
303
354
  }
355
+ // `make(S, n)` / `new(S)`: the type argument is a bare identifier.
356
+ if (
357
+ node.func?.kind === "Ident" &&
358
+ (node.func.name === "make" || node.func.name === "new") &&
359
+ node.args?.[0]?.kind === "Ident" &&
360
+ typeSubstMap.has(node.args[0].name)
361
+ ) {
362
+ node.args[0] = {
363
+ kind: "TypeExpr",
364
+ type: cloneAst(typeSubstMap.get(node.args[0].name)),
365
+ };
366
+ }
304
367
  if (node.func?.kind === "Ident") {
305
368
  let typeArgs = node._typeArgs ?? node.func._typeArgs;
306
369
  if (typeArgs) {
@@ -309,7 +372,7 @@ function substituteTypesInAst(
309
372
  if (name && typeSubstMap.has(name)) {
310
373
  return typeSubstMap.get(name);
311
374
  }
312
- return t;
375
+ return substituteInType(t, typeSubstMap);
313
376
  });
314
377
  const baseName = node.func.name;
315
378
  const sName = getSpecializedName(baseName, typeArgs);
@@ -559,9 +622,14 @@ export function monomorphise(programs, checker) {
559
622
  const genericFuncs = new Map();
560
623
  const genericTypes = new Map();
561
624
  const genericMethods = new Map(); // recvBaseName -> Array<MethodDecl>
625
+ // Template declaration -> its program; a specialization joins the program
626
+ // of its template, so a wasm package's instances stay wasm-package
627
+ // declarations even when a Go-source stdlib package is linked first.
628
+ const homeOf = new Map();
562
629
 
563
630
  for (const p of progs) {
564
631
  for (const d of p?.decls ?? []) {
632
+ homeOf.set(d, p);
565
633
  if (d.kind === "FuncDecl" && d.typeParams && d.typeParams.length > 0) {
566
634
  genericFuncs.set(d.name, d);
567
635
  } else if (
@@ -611,6 +679,7 @@ export function monomorphise(programs, checker) {
611
679
  }
612
680
  }
613
681
 
682
+ const typeInstances = new Map();
614
683
  const specializedFuncs = new Map();
615
684
  const specializedTypes = new Map();
616
685
  const specializedMethods = new Map();
@@ -638,6 +707,7 @@ export function monomorphise(programs, checker) {
638
707
  typeSubstMap.set(tp.name, typeToTypeNode(concrete));
639
708
  }
640
709
 
710
+ typeInstances.set(item.specializedName, item);
641
711
  const monoTypeDecl = cloneAst(genDecl);
642
712
  monoTypeDecl.name = item.specializedName;
643
713
  monoTypeDecl.typeParams = null;
@@ -650,6 +720,7 @@ export function monomorphise(programs, checker) {
650
720
  );
651
721
  rebindNamedResults(monoTypeDecl);
652
722
  specializedTypes.set(item.specializedName, monoTypeDecl);
723
+ homeOf.set(monoTypeDecl, homeOf.get(genDecl));
653
724
 
654
725
  // Specialize all methods declared on this generic type
655
726
  const methods = genericMethods.get(item.genericName) ?? [];
@@ -669,6 +740,7 @@ export function monomorphise(programs, checker) {
669
740
  rebindNamedResults(monoMethod);
670
741
  const mKey = `${item.specializedName}.${monoMethod.name}`;
671
742
  specializedMethods.set(mKey, monoMethod);
743
+ homeOf.set(monoMethod, homeOf.get(m));
672
744
  }
673
745
  } else if (item.kind === "func") {
674
746
  const genDecl = genericFuncs.get(item.genericName);
@@ -693,6 +765,7 @@ export function monomorphise(programs, checker) {
693
765
  );
694
766
  rebindNamedResults(monoFuncDecl);
695
767
  specializedFuncs.set(item.specializedName, monoFuncDecl);
768
+ homeOf.set(monoFuncDecl, homeOf.get(genDecl));
696
769
  }
697
770
  }
698
771
 
@@ -744,15 +817,22 @@ export function monomorphise(programs, checker) {
744
817
 
745
818
  const targetProg = progs[0];
746
819
  if (targetProg) {
747
- targetProg.decls.push(...specializedTypes.values());
748
- targetProg.decls.push(...specializedMethods.values());
749
- targetProg.decls.push(...specializedFuncs.values());
820
+ for (const group of [
821
+ specializedTypes,
822
+ specializedMethods,
823
+ specializedFuncs,
824
+ ])
825
+ for (const d of group.values())
826
+ (homeOf.get(d) ?? targetProg).decls.push(d);
750
827
  }
751
828
 
752
829
  // 6. Typecheck the monomorphised program to annotate all concrete types
753
830
  const monoChecker = new TypeChecker();
754
831
  monoChecker.target = "wasm";
755
832
  monoChecker.pkgName = targetProg?.pkg?.name ?? "main";
833
+ // The programs were checked once already, where `//gofront:native` is
834
+ // limited to the standard library; this pass only re-annotates them.
835
+ monoChecker.nativesChecked = true;
756
836
  if (checker?.types) {
757
837
  for (const [name, type] of checker.types.entries()) {
758
838
  if (!monoChecker.types.has(name)) {
@@ -764,6 +844,23 @@ export function monomorphise(programs, checker) {
764
844
  // One pass over all programs: declarations of every linked package are
765
845
  // visible to the others (cross-package references are dequalified).
766
846
  monoChecker.checkAll(progs);
847
+ nameInstances(monoChecker, typeInstances);
767
848
 
768
849
  return { programs: progs, checker: monoChecker };
769
850
  }
851
+
852
+ // Records Go's spelling of each generic instance (`Box[int]`) on its
853
+ // monomorphised type, which is named `Box$int`; `%T` prints the spelling.
854
+ function nameInstances(checker, instances) {
855
+ const spelling = {
856
+ has: (name) => instances.has(name),
857
+ get: (name) => {
858
+ const { genericName, typeArgs } = instances.get(name);
859
+ return `${genericName}[${typeArgs.map((a) => goTypeName(a, spelling)).join(",")}]`;
860
+ },
861
+ };
862
+ for (const name of instances.keys()) {
863
+ const type = checker.types.get(name);
864
+ if (type) type._goName = spelling.get(name);
865
+ }
866
+ }