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.
- package/README.md +174 -403
- package/package.json +16 -19
- package/src/{codegen → backend/js}/expressions.js +265 -77
- package/src/{codegen → backend/js}/index.js +120 -89
- package/src/{codegen → backend/js}/runtime.js +102 -0
- package/src/{codegen → backend/js}/source-map.js +32 -0
- package/src/{codegen → backend/js}/statements.js +139 -64
- package/src/backend/js/stdlib/bits.js +32 -0
- package/src/{codegen → backend/js}/stdlib/errors.js +2 -2
- package/src/{codegen → backend/js}/stdlib/fmt.js +26 -8
- package/src/{codegen → backend/js}/stdlib/index.js +6 -0
- package/src/{codegen → backend/js}/stdlib/maps.js +1 -1
- package/src/{codegen → backend/js}/stdlib/path.js +2 -2
- package/src/backend/js/stdlib/shared.js +17 -0
- package/src/{codegen → backend/js}/stdlib/slices.js +1 -1
- package/src/{codegen → backend/js}/stdlib/sort.js +1 -1
- package/src/backend/js/stdlib/strconv.js +58 -0
- package/src/{codegen → backend/js}/stdlib/strings.js +4 -1
- package/src/{codegen → backend/js}/stdlib/testing.js +2 -2
- package/src/{codegen → backend/js}/stdlib/time.js +3 -3
- package/src/{codegen → backend/js}/templ.js +3 -3
- package/src/backend/wasm/boundary.js +1798 -0
- package/src/backend/wasm/emit-builtins.js +1103 -0
- package/src/backend/wasm/emit-exprs.js +1908 -0
- package/src/backend/wasm/emit-maps.js +1863 -0
- package/src/backend/wasm/emit-shared.js +519 -0
- package/src/backend/wasm/emit-stdlib.js +3006 -0
- package/src/backend/wasm/emit-stmts.js +2472 -0
- package/src/backend/wasm/emit.js +1376 -0
- package/src/backend/wasm/encode.js +937 -0
- package/src/backend/wasm/glue.js +144 -0
- package/src/backend/wasm/index.js +2790 -0
- package/src/backend/wasm/monomorph.js +711 -0
- package/src/backend/wasm/optimize.js +227 -0
- package/src/backend/wasm/types.js +544 -0
- package/src/backend/wasm/wat.js +302 -0
- package/src/cli-core.js +323 -75
- package/src/compiler.js +447 -14
- package/src/dev-server.js +56 -15
- package/src/index.js +99 -120
- package/src/lexer.js +18 -0
- package/src/lower/boxing.js +35 -0
- package/src/lower/captures.js +172 -0
- package/src/lower/embedding.js +30 -0
- package/src/lower/escape.js +164 -0
- package/src/lower/functions.js +302 -0
- package/src/lower/globals.js +316 -0
- package/src/lower/index.js +118 -0
- package/src/lower/ownership.js +137 -0
- package/src/lower/range.js +67 -0
- package/src/lower/walk.js +25 -0
- package/src/minifier.js +2 -0
- package/src/parser/index.js +8 -3
- package/src/resolver.js +3 -1
- package/src/test-runner.js +94 -20
- package/src/typechecker/assignability.js +42 -1
- package/src/typechecker/expressions.js +182 -3
- package/src/typechecker/index.js +261 -5
- package/src/typechecker/resolve.js +35 -6
- package/src/typechecker/stdlib/core.js +34 -19
- package/src/typechecker/stdlib/extended.js +18 -3
- package/src/typechecker/stdlib/shared.js +53 -0
- package/src/typechecker/stdlib.js +2 -0
- package/src/typechecker/types.js +259 -6
- package/src/vendor.js +2 -2
- package/src/codegen/stdlib/strconv.js +0 -33
- /package/src/{codegen → backend/js}/stdlib/builder.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/bytes.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/gom.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/html.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/io.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/math.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/os.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/rand.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/regexp.js +0 -0
- /package/src/{codegen → backend/js}/stdlib/unicode.js +0 -0
- /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
|
+
}
|