gofront 1.4.0 → 1.6.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 (77) hide show
  1. package/README.md +174 -403
  2. package/package.json +16 -19
  3. package/src/{codegen → backend/js}/expressions.js +265 -77
  4. package/src/{codegen → backend/js}/index.js +120 -89
  5. package/src/{codegen → backend/js}/runtime.js +102 -0
  6. package/src/{codegen → backend/js}/source-map.js +32 -0
  7. package/src/{codegen → backend/js}/statements.js +139 -64
  8. package/src/backend/js/stdlib/bits.js +32 -0
  9. package/src/{codegen → backend/js}/stdlib/errors.js +2 -2
  10. package/src/{codegen → backend/js}/stdlib/fmt.js +26 -8
  11. package/src/{codegen → backend/js}/stdlib/index.js +6 -0
  12. package/src/{codegen → backend/js}/stdlib/maps.js +1 -1
  13. package/src/{codegen → backend/js}/stdlib/path.js +2 -2
  14. package/src/backend/js/stdlib/shared.js +17 -0
  15. package/src/{codegen → backend/js}/stdlib/slices.js +1 -1
  16. package/src/{codegen → backend/js}/stdlib/sort.js +1 -1
  17. package/src/backend/js/stdlib/strconv.js +58 -0
  18. package/src/{codegen → backend/js}/stdlib/strings.js +4 -1
  19. package/src/{codegen → backend/js}/stdlib/testing.js +2 -2
  20. package/src/{codegen → backend/js}/stdlib/time.js +3 -3
  21. package/src/{codegen → backend/js}/templ.js +3 -3
  22. package/src/backend/wasm/boundary.js +1798 -0
  23. package/src/backend/wasm/emit-builtins.js +1103 -0
  24. package/src/backend/wasm/emit-exprs.js +1908 -0
  25. package/src/backend/wasm/emit-maps.js +1863 -0
  26. package/src/backend/wasm/emit-shared.js +519 -0
  27. package/src/backend/wasm/emit-stdlib.js +3006 -0
  28. package/src/backend/wasm/emit-stmts.js +2472 -0
  29. package/src/backend/wasm/emit.js +1376 -0
  30. package/src/backend/wasm/encode.js +937 -0
  31. package/src/backend/wasm/glue.js +144 -0
  32. package/src/backend/wasm/index.js +2790 -0
  33. package/src/backend/wasm/monomorph.js +711 -0
  34. package/src/backend/wasm/optimize.js +227 -0
  35. package/src/backend/wasm/types.js +544 -0
  36. package/src/backend/wasm/wat.js +302 -0
  37. package/src/cli-core.js +323 -75
  38. package/src/compiler.js +447 -14
  39. package/src/dev-server.js +56 -15
  40. package/src/index.js +99 -120
  41. package/src/lexer.js +18 -0
  42. package/src/lower/boxing.js +35 -0
  43. package/src/lower/captures.js +172 -0
  44. package/src/lower/embedding.js +30 -0
  45. package/src/lower/escape.js +164 -0
  46. package/src/lower/functions.js +302 -0
  47. package/src/lower/globals.js +316 -0
  48. package/src/lower/index.js +118 -0
  49. package/src/lower/ownership.js +137 -0
  50. package/src/lower/range.js +67 -0
  51. package/src/lower/walk.js +25 -0
  52. package/src/minifier.js +2 -0
  53. package/src/parser/index.js +8 -3
  54. package/src/resolver.js +3 -1
  55. package/src/test-runner.js +94 -20
  56. package/src/typechecker/assignability.js +42 -1
  57. package/src/typechecker/expressions.js +182 -3
  58. package/src/typechecker/index.js +261 -5
  59. package/src/typechecker/resolve.js +35 -6
  60. package/src/typechecker/stdlib/core.js +34 -19
  61. package/src/typechecker/stdlib/extended.js +18 -3
  62. package/src/typechecker/stdlib/shared.js +53 -0
  63. package/src/typechecker/stdlib.js +2 -0
  64. package/src/typechecker/types.js +259 -6
  65. package/src/vendor.js +2 -2
  66. package/src/codegen/stdlib/strconv.js +0 -33
  67. /package/src/{codegen → backend/js}/stdlib/builder.js +0 -0
  68. /package/src/{codegen → backend/js}/stdlib/bytes.js +0 -0
  69. /package/src/{codegen → backend/js}/stdlib/gom.js +0 -0
  70. /package/src/{codegen → backend/js}/stdlib/html.js +0 -0
  71. /package/src/{codegen → backend/js}/stdlib/io.js +0 -0
  72. /package/src/{codegen → backend/js}/stdlib/math.js +0 -0
  73. /package/src/{codegen → backend/js}/stdlib/os.js +0 -0
  74. /package/src/{codegen → backend/js}/stdlib/rand.js +0 -0
  75. /package/src/{codegen → backend/js}/stdlib/regexp.js +0 -0
  76. /package/src/{codegen → backend/js}/stdlib/unicode.js +0 -0
  77. /package/src/{codegen → backend/js}/stdlib/utf8.js +0 -0
@@ -0,0 +1,302 @@
1
+ // src/backend/wasm/wat.js
2
+ // Emits WebAssembly Text (WAT) format from Module IR.
3
+
4
+ function formatValType(t) {
5
+ if (typeof t === "string") return t;
6
+ if (typeof t === "number") return `(type ${t})`;
7
+ if (typeof t === "object" && t !== null) {
8
+ if (t.kind === "ref") {
9
+ const nullStr = t.nullable ? "null " : "";
10
+ const target =
11
+ t.typeIndex !== undefined ? `$t${t.typeIndex}` : (t.heapType ?? "any");
12
+ return `(ref ${nullStr}${target})`;
13
+ }
14
+ }
15
+ return String(t);
16
+ }
17
+
18
+ function formatTypeEntry(t, id) {
19
+ const typeId = id !== undefined ? ` $t${id}` : "";
20
+ if (t.form === "rec") {
21
+ const inners = t.types
22
+ .map(
23
+ (sub, i) =>
24
+ ` ${formatTypeEntry(sub, typeof id === "number" ? id + i : `${id}_${i}`)}`,
25
+ )
26
+ .join("\n");
27
+ return `(rec\n${inners}\n )`;
28
+ }
29
+ if (t.form === "struct") {
30
+ const fields = (t.fields ?? [])
31
+ .map((f) => {
32
+ const inner = formatValType(f.type);
33
+ return f.mutable ? `(field (mut ${inner}))` : `(field ${inner})`;
34
+ })
35
+ .join(" ");
36
+ return `(type${typeId} (struct ${fields}))`;
37
+ }
38
+ if (t.form === "array") {
39
+ const inner = formatValType(t.elemType ?? t.type);
40
+ const field = t.mutable ? `(mut ${inner})` : inner;
41
+ return `(type${typeId} (array ${field}))`;
42
+ }
43
+ // func
44
+ const params = (t.params ?? []).map(formatValType).join(" ");
45
+ const results = (t.results ?? []).map(formatValType).join(" ");
46
+ const paramStr = params ? ` (param ${params})` : "";
47
+ const resultStr = results ? ` (result ${results})` : "";
48
+ return `(type${typeId} (func${paramStr}${resultStr}))`;
49
+ }
50
+
51
+ function formatInstruction(inst) {
52
+ if (typeof inst === "string") return inst;
53
+ const { op } = inst;
54
+ switch (op) {
55
+ case "block":
56
+ case "loop":
57
+ case "if": {
58
+ const bt = inst.blockType ?? inst.resultType;
59
+ const res = bt && bt !== "void" ? ` (result ${formatValType(bt)})` : "";
60
+ return `${op}${res}`;
61
+ }
62
+ case "br":
63
+ case "br_if":
64
+ return `${op} ${inst.depth ?? inst.index ?? 0}`;
65
+ case "br_table": {
66
+ const targets = (inst.targets ?? []).join(" ");
67
+ return `${op} ${targets} ${inst.defaultTarget ?? 0}`;
68
+ }
69
+ case "call":
70
+ case "return_call":
71
+ return `${op} ${inst.funcIndex ?? inst.index ?? 0}`;
72
+ case "call_indirect":
73
+ return `${op} (type $t${inst.typeIndex ?? 0})`;
74
+ case "call_ref":
75
+ case "return_call_ref":
76
+ return `${op} (type $t${inst.typeIndex ?? 0})`;
77
+ case "ref.func":
78
+ return `ref.func ${inst.funcIndex ?? inst.index ?? 0}`;
79
+ case "local.get":
80
+ case "local.set":
81
+ case "local.tee":
82
+ return `${op} ${inst.localIndex ?? inst.index ?? 0}`;
83
+ case "global.get":
84
+ case "global.set":
85
+ return `${op} ${inst.globalIndex ?? inst.index ?? 0}`;
86
+ case "i32.load":
87
+ case "i64.load":
88
+ case "f32.load":
89
+ case "f64.load":
90
+ case "i32.load8_s":
91
+ case "i32.load8_u":
92
+ case "i32.load16_s":
93
+ case "i32.load16_u":
94
+ case "i32.store":
95
+ case "i64.store":
96
+ case "f32.store":
97
+ case "f64.store":
98
+ case "i32.store8":
99
+ case "i32.store16":
100
+ return inst.offset ? `${op} offset=${inst.offset}` : op;
101
+ case "i32.const":
102
+ case "i64.const":
103
+ return `${op} ${inst.value ?? 0}`;
104
+ case "f32.const":
105
+ case "f64.const": {
106
+ const v = inst.value ?? 0;
107
+ if (Number.isNaN(v)) return `${op} nan`;
108
+ if (v === Infinity) return `${op} inf`;
109
+ if (v === -Infinity) return `${op} -inf`;
110
+ return `${op} ${v}`;
111
+ }
112
+ case "throw":
113
+ return `${op} ${inst.tagIndex ?? inst.index ?? 0}`;
114
+ case "throw_ref":
115
+ return "throw_ref";
116
+ case "try_table": {
117
+ const bt = inst.blockType ?? inst.resultType;
118
+ const res = bt && bt !== "void" ? ` (result ${formatValType(bt)})` : "";
119
+ const catches = (inst.catches ?? [])
120
+ .map((c) => {
121
+ const k = c.kind ?? c.op;
122
+ if (k === "catch")
123
+ return `(catch ${c.tagIndex ?? 0} ${c.label ?? 0})`;
124
+ if (k === "catch_ref")
125
+ return `(catch_ref ${c.tagIndex ?? 0} ${c.label ?? 0})`;
126
+ if (k === "catch_all") return `(catch_all ${c.label ?? 0})`;
127
+ if (k === "catch_all_ref") return `(catch_all_ref ${c.label ?? 0})`;
128
+ return "";
129
+ })
130
+ .filter(Boolean)
131
+ .join(" ");
132
+ return `${op}${res}${catches ? ` ${catches}` : ""}`;
133
+ }
134
+ case "struct.new":
135
+ return `struct.new ${inst.typeIndex !== undefined ? `$t${inst.typeIndex}` : 0}`;
136
+ case "struct.get":
137
+ case "struct.get_s":
138
+ case "struct.get_u":
139
+ case "struct.set":
140
+ return `${op} ${inst.typeIndex !== undefined ? `$t${inst.typeIndex}` : 0} ${inst.fieldIndex ?? 0}`;
141
+ case "array.new":
142
+ case "array.new_default":
143
+ case "array.get":
144
+ case "array.get_s":
145
+ case "array.get_u":
146
+ case "array.set":
147
+ return `${op} ${inst.typeIndex !== undefined ? `$t${inst.typeIndex}` : 0}`;
148
+ case "array.new_fixed":
149
+ return `${op} ${inst.typeIndex !== undefined ? `$t${inst.typeIndex}` : 0} ${inst.size ?? inst.count ?? 0}`;
150
+ case "array.copy":
151
+ return `${op} ${inst.typeIndexDst !== undefined ? `$t${inst.typeIndexDst}` : `$t${inst.typeIndex ?? 0}`} ${inst.typeIndexSrc !== undefined ? `$t${inst.typeIndexSrc}` : `$t${inst.typeIndex ?? 0}`}`;
152
+ case "array.len":
153
+ return "array.len";
154
+ case "ref.test":
155
+ case "ref.test_null":
156
+ case "ref.cast":
157
+ case "ref.cast_null": {
158
+ const ht =
159
+ inst.typeIndex !== undefined
160
+ ? `$t${inst.typeIndex}`
161
+ : inst.heapType !== undefined
162
+ ? String(inst.heapType)
163
+ : 0;
164
+ return `${op} ${ht}`;
165
+ }
166
+ case "any.convert_extern":
167
+ case "extern.convert_any":
168
+ return op;
169
+ default:
170
+ return op;
171
+ }
172
+ }
173
+
174
+ export function emitWat(mod) {
175
+ const lines = ["(module"];
176
+
177
+ // 1. Types
178
+ if (mod.types && mod.types.length > 0) {
179
+ let typeIdx = 0;
180
+ for (let i = 0; i < mod.types.length; i++) {
181
+ const entry = mod.types[i];
182
+ lines.push(` ${formatTypeEntry(entry, typeIdx)}`);
183
+ if (entry.form === "rec") {
184
+ typeIdx += entry.types.length;
185
+ } else {
186
+ typeIdx += 1;
187
+ }
188
+ }
189
+ }
190
+
191
+ // 2. Imports
192
+ if (mod.imports && mod.imports.length > 0) {
193
+ for (const imp of mod.imports) {
194
+ const desc =
195
+ imp.kind === "func"
196
+ ? `(func (type $t${imp.typeIndex ?? 0}))`
197
+ : imp.kind === "tag"
198
+ ? `(tag (type $t${imp.typeIndex ?? 0}))`
199
+ : `(${imp.kind})`;
200
+ lines.push(` (import "${imp.module}" "${imp.name}" ${desc})`);
201
+ }
202
+ }
203
+
204
+ // 3. Tags
205
+ if (mod.tags && mod.tags.length > 0) {
206
+ for (let i = 0; i < mod.tags.length; i++) {
207
+ lines.push(` (tag $tag${i} (type $t${mod.tags[i].typeIndex ?? 0}))`);
208
+ }
209
+ }
210
+
211
+ if (mod.memory) {
212
+ const max = mod.memory.max != null ? ` ${mod.memory.max}` : "";
213
+ lines.push(` (memory $mem ${mod.memory.min}${max})`);
214
+ }
215
+
216
+ // 4. Globals
217
+ if (mod.globals && mod.globals.length > 0) {
218
+ for (let i = 0; i < mod.globals.length; i++) {
219
+ const g = mod.globals[i];
220
+ const t = formatValType(g.type);
221
+ const typeStr = g.mutable ? `(mut ${t})` : t;
222
+ const initStr = (g.init ?? [{ op: "i32.const", value: 0 }])
223
+ .map(formatInstruction)
224
+ .join(" ");
225
+ lines.push(` (global $g${i} ${typeStr} ${initStr})`);
226
+ }
227
+ }
228
+
229
+ // 5. Elements (declarative for ref.func)
230
+ if (mod.elements && mod.elements.length > 0) {
231
+ lines.push(
232
+ ` (elem declare func ${mod.elements.map((idx) => `$f${idx}`).join(" ")})`,
233
+ );
234
+ }
235
+
236
+ // Map exports by kind & index
237
+ const exportsByFunc = new Map();
238
+ for (const exp of mod.exports ?? []) {
239
+ if (exp.kind === "func") {
240
+ if (!exportsByFunc.has(exp.index)) exportsByFunc.set(exp.index, []);
241
+ exportsByFunc.get(exp.index).push(exp.name);
242
+ }
243
+ }
244
+
245
+ // 5. Functions
246
+ if (mod.funcs && mod.funcs.length > 0) {
247
+ const importFuncCount = (mod.imports ?? []).filter(
248
+ (i) => i.kind === "func",
249
+ ).length;
250
+ // Type indices count every member of a rec group, not the group entry.
251
+ const flatTypes = (mod.types ?? []).flatMap((t) =>
252
+ t.form === "rec" ? t.types : [t],
253
+ );
254
+
255
+ for (let i = 0; i < mod.funcs.length; i++) {
256
+ const fn = mod.funcs[i];
257
+ const globalFuncIdx = importFuncCount + i;
258
+ const expNames = exportsByFunc.get(globalFuncIdx) ?? [];
259
+ const expStr = expNames.map((n) => ` (export "${n}")`).join("");
260
+
261
+ const typeEntry = flatTypes[fn.typeIndex] ?? null;
262
+ let sigStr = ` (type $t${fn.typeIndex ?? 0})`;
263
+ if (typeEntry && typeEntry.form === "func") {
264
+ const params = (typeEntry.params ?? []).map(formatValType).join(" ");
265
+ const results = (typeEntry.results ?? []).map(formatValType).join(" ");
266
+ if (params) sigStr += ` (param ${params})`;
267
+ if (results) sigStr += ` (result ${results})`;
268
+ }
269
+
270
+ lines.push(` (func $f${globalFuncIdx}${expStr}${sigStr}`);
271
+
272
+ // Locals
273
+ if (fn.locals && fn.locals.length > 0) {
274
+ const locTypes = fn.locals.map((l) =>
275
+ l && typeof l === "object" && "type" in l && !l.kind ? l.type : l,
276
+ );
277
+ lines.push(` (local ${locTypes.map(formatValType).join(" ")})`);
278
+ }
279
+
280
+ // Body instructions
281
+ for (const inst of fn.body ?? []) {
282
+ lines.push(` ${formatInstruction(inst)}`);
283
+ }
284
+ lines.push(" )");
285
+ }
286
+ }
287
+
288
+ // 6. Remaining exports (e.g. tags, globals, memories)
289
+ for (const exp of mod.exports ?? []) {
290
+ if (exp.kind !== "func") {
291
+ lines.push(` (export "${exp.name}" (${exp.kind} ${exp.index}))`);
292
+ }
293
+ }
294
+
295
+ // 7. Start function
296
+ if (typeof mod.start === "number") {
297
+ lines.push(` (start $f${mod.start})`);
298
+ }
299
+
300
+ lines.push(")");
301
+ return `${lines.join("\n")}\n`;
302
+ }