@fraczak/k 7.0.2 → 7.1.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/CHANGELOG.md +42 -0
- package/DOCS/FILE_FORMATS.md +238 -15
- package/DOCS/POLYMORPHIC_IR.md +104 -0
- package/JOURNAL.md +288 -0
- package/README.md +10 -2
- package/access-table.mjs +343 -0
- package/backend-api.mjs +18 -0
- package/backends/llvm/README.md +20 -21
- package/backends/llvm/bin/k-llvm-build.mjs +105 -32
- package/backends/llvm/bin/k-llvm-compile.mjs +63 -24
- package/backends/llvm/bin/k-llvm.mjs +292 -0
- package/backends/llvm/runtime/krt.c +8 -0
- package/backends/llvm/runtime/krt.h +1 -0
- package/backends/llvm/src/cli.mjs +95 -17
- package/backends/llvm/src/executable.mjs +128 -11
- package/backends/llvm/src/kvm2llvm.mjs +10 -5
- package/backends/llvm/src/llvm.mjs +121 -9
- package/backends/llvm/tests/integration.sh +11 -11
- package/backends/llvm/{bin → tests}/k-llvm-run.mjs +48 -22
- package/backends/llvm/tests/perf-support.mjs +24 -3
- package/backends/llvm/tests/test-llvm.mjs +22 -1
- package/backends/wasm/bin/k-wasm-compile.mjs +46 -20
- package/backends/wasm/bin/k-wasm-run.mjs +61 -20
- package/backends/wasm/bin/k-wasm.mjs +47 -13
- package/backends/wasm/src/cli.mjs +141 -19
- package/backends/wasm/src/wasm.mjs +130 -23
- package/browser/repl-browser.mjs +16 -5
- package/codecs/k-parse.mjs +29 -8
- package/codecs/k-print.mjs +22 -6
- package/codecs/runtime/codec-sdk.mjs +8 -4
- package/codecs/show.mjs +20 -6
- package/k.mjs +56 -16
- package/kir.mjs +58 -19
- package/kvm.mjs +49 -12
- package/objects/compile.mjs +37 -23
- package/objects/decompile.mjs +40 -10
- package/objects/extract-aliases.mjs +44 -14
- package/objects/inspect.mjs +19 -14
- package/objects/validate.mjs +18 -11
- package/package.json +10 -3
- package/pkir.mjs +772 -0
- package/repl.mjs +36 -18
- package/scripts/build-repl-html.mjs +14 -2
- package/scripts/perf-ieee.mjs +264 -13
- package/scripts/perf-int.mjs +315 -22
- package/scripts/perf-multiplication.mjs +58 -7
- package/scripts/perf-poly.mjs +306 -24
- package/scripts/run-tests.mjs +3 -0
- package/tests/test-access-table.mjs +213 -0
- package/tests/test-pkir.mjs +530 -0
- package/tests/test-polymorphic-tdd.mjs +196 -0
- package/tests/test-repl-html.mjs +15 -2
- package/tests/test-repl.mjs +30 -1
- package/backends/llvm/bin/k-llvm-jit.mjs +0 -160
|
@@ -1,26 +1,112 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
compileLibrary,
|
|
6
|
+
decodeObject,
|
|
7
|
+
loadLibrary
|
|
8
|
+
} from "@fraczak/k/backend-api.mjs";
|
|
5
9
|
import {
|
|
6
10
|
compileWasmArtifact,
|
|
7
11
|
compileWasmArtifactFromKVM,
|
|
8
|
-
compileWasmArtifactFromObject
|
|
12
|
+
compileWasmArtifactFromObject,
|
|
13
|
+
compileWasmArtifactFromPKIR
|
|
9
14
|
} from "./wasm.mjs";
|
|
10
15
|
|
|
11
16
|
function readAll(stream) {
|
|
12
17
|
return new Promise((resolve, reject) => {
|
|
13
18
|
const chunks = [];
|
|
14
|
-
stream.on("data", (chunk) =>
|
|
19
|
+
stream.on("data", (chunk) => {
|
|
20
|
+
chunks.push(
|
|
21
|
+
Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)
|
|
22
|
+
);
|
|
23
|
+
});
|
|
15
24
|
stream.on("end", () => resolve(Buffer.concat(chunks)));
|
|
16
25
|
stream.on("error", reject);
|
|
17
26
|
});
|
|
18
27
|
}
|
|
19
28
|
|
|
29
|
+
export function buildExportPreamble(exports = [], libraries = []) {
|
|
30
|
+
if (exports.length === 0) return "";
|
|
31
|
+
const aliasMap = {};
|
|
32
|
+
for (const lib of libraries) {
|
|
33
|
+
for (const [name, hash] of Object.entries(lib.relAlias || {})) {
|
|
34
|
+
if (name !== "__main__") aliasMap[name] = hash;
|
|
35
|
+
}
|
|
36
|
+
for (const [hash, entry] of Object.entries(lib.meta || {})) {
|
|
37
|
+
if (entry?.type !== "rel") continue;
|
|
38
|
+
for (const origin of entry?.origins || []) {
|
|
39
|
+
if (origin?.name && origin.name !== "__main__") {
|
|
40
|
+
aliasMap[origin.name] = hash;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const lines = [];
|
|
46
|
+
for (const spec of exports) {
|
|
47
|
+
const [libName, localName] = spec.includes(":")
|
|
48
|
+
? spec.split(":", 2)
|
|
49
|
+
: [spec, spec];
|
|
50
|
+
const hash = aliasMap[libName];
|
|
51
|
+
if (!hash) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`--export: '${libName}' not found in loaded libraries`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
const body = hash.startsWith("@") ? hash.slice(1) : hash;
|
|
57
|
+
lines.push(`${localName} = @${body};`);
|
|
58
|
+
}
|
|
59
|
+
return lines.join("\n") + "\n";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function loadLibraryFromPath(libPath) {
|
|
63
|
+
const ext = path.extname(libPath).toLowerCase();
|
|
64
|
+
if (ext === ".klib" || ext === ".ko") {
|
|
65
|
+
return loadLibrary(decodeObject(fs.readFileSync(libPath)));
|
|
66
|
+
}
|
|
67
|
+
if (ext === ".k") {
|
|
68
|
+
let depLibs = [];
|
|
69
|
+
const baseName = path.basename(libPath);
|
|
70
|
+
if (baseName === "poly.k") {
|
|
71
|
+
const dir = path.dirname(libPath);
|
|
72
|
+
const arithPath = path.join(dir, "arithmetics.k");
|
|
73
|
+
if (fs.existsSync(arithPath)) {
|
|
74
|
+
const arithLib = loadLibrary(
|
|
75
|
+
compileLibrary(fs.readFileSync(arithPath, "utf8"), {
|
|
76
|
+
source: arithPath
|
|
77
|
+
})
|
|
78
|
+
);
|
|
79
|
+
depLibs.push(arithLib);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const rawSource = fs.readFileSync(libPath, "utf8");
|
|
83
|
+
if (depLibs.length > 0) {
|
|
84
|
+
const neededExports = [
|
|
85
|
+
"0", "int", "inc", "dec", "nat", "zero_int?", "neg?", "GT"
|
|
86
|
+
];
|
|
87
|
+
const preamble = buildExportPreamble(neededExports, depLibs);
|
|
88
|
+
const compiled = compileLibrary(preamble + rawSource, {
|
|
89
|
+
source: libPath,
|
|
90
|
+
libraries: depLibs
|
|
91
|
+
});
|
|
92
|
+
const mergedLib = loadLibrary(compiled);
|
|
93
|
+
for (const dep of depLibs) {
|
|
94
|
+
for (const [k, v] of Object.entries(dep.relAlias || {})) {
|
|
95
|
+
if (!mergedLib.relAlias[k]) mergedLib.relAlias[k] = v;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return mergedLib;
|
|
99
|
+
}
|
|
100
|
+
return loadLibrary(compileLibrary(rawSource, { source: libPath }));
|
|
101
|
+
}
|
|
102
|
+
throw new Error(`Unsupported library extension: ${ext}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
20
105
|
function parseCompileOptions(args) {
|
|
21
106
|
const libraries = [];
|
|
22
107
|
const exportSpecs = [];
|
|
23
108
|
let loadedLibrary = false;
|
|
109
|
+
let usePKIR = false;
|
|
24
110
|
|
|
25
111
|
while (args.length > 0) {
|
|
26
112
|
if (args[0] === "--") {
|
|
@@ -28,25 +114,34 @@ function parseCompileOptions(args) {
|
|
|
28
114
|
break;
|
|
29
115
|
}
|
|
30
116
|
if (args[0] === "--lib") {
|
|
31
|
-
if (loadedLibrary)
|
|
117
|
+
if (loadedLibrary) {
|
|
118
|
+
throw new Error("--lib may only be specified once");
|
|
119
|
+
}
|
|
32
120
|
args.shift();
|
|
33
121
|
const libPath = args.shift();
|
|
34
122
|
if (!libPath) throw new Error("--lib requires a file argument");
|
|
35
|
-
libraries.push(
|
|
123
|
+
libraries.push(loadLibraryFromPath(libPath));
|
|
36
124
|
loadedLibrary = true;
|
|
37
125
|
} else if (args[0] === "--export") {
|
|
38
126
|
args.shift();
|
|
39
127
|
const spec = args.shift();
|
|
40
|
-
if (!spec)
|
|
128
|
+
if (!spec) {
|
|
129
|
+
throw new Error(
|
|
130
|
+
"--export requires a spec argument (name or libname:localname)"
|
|
131
|
+
);
|
|
132
|
+
}
|
|
41
133
|
exportSpecs.push(spec);
|
|
134
|
+
} else if (args[0] === "--pkir") {
|
|
135
|
+
args.shift();
|
|
136
|
+
usePKIR = true;
|
|
42
137
|
} else if (args[0].startsWith("--")) {
|
|
43
|
-
|
|
138
|
+
break;
|
|
44
139
|
} else {
|
|
45
140
|
break;
|
|
46
141
|
}
|
|
47
142
|
}
|
|
48
143
|
|
|
49
|
-
return { libraries, exportSpecs };
|
|
144
|
+
return { libraries, exportSpecs, usePKIR };
|
|
50
145
|
}
|
|
51
146
|
|
|
52
147
|
function fileInputType(filePath) {
|
|
@@ -54,6 +149,7 @@ function fileInputType(filePath) {
|
|
|
54
149
|
if (ext === ".ko") return "ko";
|
|
55
150
|
if (ext === ".kvm") return "kvm";
|
|
56
151
|
if (ext === ".klib") return "klib";
|
|
152
|
+
if (ext === ".pkir") return "pkir";
|
|
57
153
|
return "source-file";
|
|
58
154
|
}
|
|
59
155
|
|
|
@@ -68,38 +164,55 @@ function resolveProgramInput(args, { allowStdinSource = false } = {}) {
|
|
|
68
164
|
if (fs.existsSync(inputArg)) {
|
|
69
165
|
const kind = fileInputType(inputArg);
|
|
70
166
|
if (kind === "klib") {
|
|
71
|
-
throw new Error(
|
|
167
|
+
throw new Error(
|
|
168
|
+
"Cannot compile a .klib library to WebAssembly without a main " +
|
|
169
|
+
"relation; load it with --lib."
|
|
170
|
+
);
|
|
72
171
|
}
|
|
73
172
|
return { kind, path: inputArg, sourceName: inputArg };
|
|
74
173
|
}
|
|
75
174
|
|
|
76
|
-
if ([".k", ".ko", ".kvm", ".klib", ".wasm"].includes(ext)) {
|
|
175
|
+
if ([".k", ".ko", ".kvm", ".klib", ".wasm", ".pkir"].includes(ext)) {
|
|
77
176
|
throw new Error(`Input file not found: ${inputArg}`);
|
|
78
177
|
}
|
|
79
178
|
|
|
80
|
-
return {
|
|
179
|
+
return {
|
|
180
|
+
kind: "inline-source",
|
|
181
|
+
source: inputArg,
|
|
182
|
+
sourceName: "<inline>"
|
|
183
|
+
};
|
|
81
184
|
}
|
|
82
185
|
|
|
83
186
|
async function compileProgramInput(
|
|
84
187
|
input,
|
|
85
|
-
{
|
|
188
|
+
{
|
|
189
|
+
libraries = [],
|
|
190
|
+
exportSpecs = [],
|
|
191
|
+
stdin = null,
|
|
192
|
+
inputEnvelopePattern = null,
|
|
193
|
+
usePKIR = false
|
|
194
|
+
} = {}
|
|
86
195
|
) {
|
|
87
196
|
if (input.kind === "inline-source") {
|
|
88
197
|
return compileWasmArtifact(input.source, {
|
|
89
198
|
libraries,
|
|
90
199
|
exports: exportSpecs,
|
|
91
200
|
source: input.sourceName,
|
|
92
|
-
inputEnvelopePattern
|
|
201
|
+
inputEnvelopePattern,
|
|
202
|
+
usePKIR
|
|
93
203
|
});
|
|
94
204
|
}
|
|
95
205
|
|
|
96
206
|
if (input.kind === "stdin-source") {
|
|
97
|
-
if (!stdin)
|
|
207
|
+
if (!stdin) {
|
|
208
|
+
throw new Error("stdin source requested without a stdin stream");
|
|
209
|
+
}
|
|
98
210
|
return compileWasmArtifact((await readAll(stdin)).toString("utf8"), {
|
|
99
211
|
libraries,
|
|
100
212
|
exports: exportSpecs,
|
|
101
213
|
source: input.sourceName,
|
|
102
|
-
inputEnvelopePattern
|
|
214
|
+
inputEnvelopePattern,
|
|
215
|
+
usePKIR
|
|
103
216
|
});
|
|
104
217
|
}
|
|
105
218
|
|
|
@@ -108,18 +221,27 @@ async function compileProgramInput(
|
|
|
108
221
|
libraries,
|
|
109
222
|
exports: exportSpecs,
|
|
110
223
|
source: input.sourceName,
|
|
111
|
-
inputEnvelopePattern
|
|
224
|
+
inputEnvelopePattern,
|
|
225
|
+
usePKIR
|
|
112
226
|
});
|
|
113
227
|
}
|
|
114
228
|
|
|
115
229
|
if (input.kind === "ko") {
|
|
116
|
-
|
|
117
|
-
|
|
230
|
+
const obj = decodeObject(fs.readFileSync(input.path));
|
|
231
|
+
return compileWasmArtifactFromObject(obj, {
|
|
232
|
+
inputEnvelopePattern,
|
|
233
|
+
usePKIR
|
|
118
234
|
});
|
|
119
235
|
}
|
|
120
236
|
|
|
237
|
+
if (input.kind === "pkir") {
|
|
238
|
+
const pkir = JSON.parse(fs.readFileSync(input.path, "utf8"));
|
|
239
|
+
return compileWasmArtifactFromPKIR(pkir);
|
|
240
|
+
}
|
|
241
|
+
|
|
121
242
|
if (input.kind === "kvm") {
|
|
122
|
-
|
|
243
|
+
const kvm = JSON.parse(fs.readFileSync(input.path, "utf8"));
|
|
244
|
+
return compileWasmArtifactFromKVM(kvm);
|
|
123
245
|
}
|
|
124
246
|
|
|
125
247
|
throw new Error(`Unsupported input kind: ${input.kind}`);
|
|
@@ -14,7 +14,9 @@ import {
|
|
|
14
14
|
propertyListToPattern,
|
|
15
15
|
Value,
|
|
16
16
|
specializeKVM,
|
|
17
|
-
specializeObjectRelations
|
|
17
|
+
specializeObjectRelations,
|
|
18
|
+
compileRelationToPKIR,
|
|
19
|
+
lowerPKIRToKVM
|
|
18
20
|
} from "@fraczak/k/backend-api.mjs";
|
|
19
21
|
import { intersectPropertyListPatterns } from "@fraczak/k/codecs/runtime/codec.mjs";
|
|
20
22
|
import { propertyListToFilter } from "@fraczak/k/codecs/runtime/show-value.mjs";
|
|
@@ -283,7 +285,7 @@ function cloneKVMFunction(kvmFunc) {
|
|
|
283
285
|
};
|
|
284
286
|
}
|
|
285
287
|
|
|
286
|
-
function compileModule(mainRelName, defs) {
|
|
288
|
+
function compileModule(mainRelName, defs, { usePKIR = false } = {}) {
|
|
287
289
|
const compiled = new Set();
|
|
288
290
|
const queue = [mainRelName];
|
|
289
291
|
const wats = [];
|
|
@@ -299,8 +301,14 @@ function compileModule(mainRelName, defs) {
|
|
|
299
301
|
throw new Error(`Relation ${name} not found`);
|
|
300
302
|
}
|
|
301
303
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
+
let kvmFunc;
|
|
305
|
+
if (usePKIR) {
|
|
306
|
+
const pkir = compileRelationToPKIR(relDef, name);
|
|
307
|
+
kvmFunc = lowerPKIRToKVM(pkir);
|
|
308
|
+
} else {
|
|
309
|
+
kvmFunc = lowerToKVM(relDef, name);
|
|
310
|
+
kvmFunc.typePatternGraph = relDef.typePatternGraph;
|
|
311
|
+
}
|
|
304
312
|
scanCalls(kvmFunc.body, compiled, queue);
|
|
305
313
|
|
|
306
314
|
kvmFunc.name = nameMap.get(name) || cleanName(name);
|
|
@@ -502,7 +510,7 @@ function buildExportPreamble(exportSpecs, libraries) {
|
|
|
502
510
|
async function compileWasmArtifactFromDefs(
|
|
503
511
|
defs,
|
|
504
512
|
mainRelName = "__main__",
|
|
505
|
-
{ typingMode = "generic" } = {}
|
|
513
|
+
{ typingMode = "generic", usePKIR = false } = {}
|
|
506
514
|
) {
|
|
507
515
|
resetTagIds();
|
|
508
516
|
const mainRel = defs.rels[mainRelName];
|
|
@@ -510,7 +518,11 @@ async function compileWasmArtifactFromDefs(
|
|
|
510
518
|
throw new Error(`No main relation (${mainRelName}) defined in script`);
|
|
511
519
|
}
|
|
512
520
|
|
|
513
|
-
const { wat: moduleWatBody, relationNames, entryName } = compileModule(
|
|
521
|
+
const { wat: moduleWatBody, relationNames, entryName } = compileModule(
|
|
522
|
+
mainRelName,
|
|
523
|
+
defs,
|
|
524
|
+
{ usePKIR }
|
|
525
|
+
);
|
|
514
526
|
assertRelationsConverged(defs, relationNames);
|
|
515
527
|
const fullWat = runtimeWat.trim().slice(0, -1) + "\n" + moduleWatBody + "\n)";
|
|
516
528
|
const graph = mainRel.typePatternGraph;
|
|
@@ -523,7 +535,12 @@ async function compileWasmArtifactFromDefs(
|
|
|
523
535
|
entry: entryName || cleanName(mainRelName),
|
|
524
536
|
inputPattern,
|
|
525
537
|
outputPattern,
|
|
526
|
-
typing: classifyTyping(
|
|
538
|
+
typing: classifyTyping(
|
|
539
|
+
inputPattern,
|
|
540
|
+
outputPattern,
|
|
541
|
+
relTypeStatus(defs, mainRelName),
|
|
542
|
+
typingMode
|
|
543
|
+
),
|
|
527
544
|
tags: getTagEntries()
|
|
528
545
|
};
|
|
529
546
|
return appendCustomSection(await compileWat(fullWat), METADATA_SECTION, JSON.stringify(metadata));
|
|
@@ -598,12 +615,17 @@ async function compileWasmArtifactFromKVM(kvmInput, options = {}) {
|
|
|
598
615
|
return appendCustomSection(await compileWat(fullWat), METADATA_SECTION, JSON.stringify(metadata));
|
|
599
616
|
}
|
|
600
617
|
|
|
601
|
-
async function compileWasmArtifactFromObject(
|
|
618
|
+
async function compileWasmArtifactFromObject(
|
|
619
|
+
object,
|
|
620
|
+
{ entry = null, inputEnvelopePattern = null, usePKIR = false } = {}
|
|
621
|
+
) {
|
|
602
622
|
if (!object?.rels) {
|
|
603
623
|
throw new Error("Expected .ko input to contain k object relations");
|
|
604
624
|
}
|
|
605
625
|
if (object.main == null) {
|
|
606
|
-
throw new Error(
|
|
626
|
+
throw new Error(
|
|
627
|
+
"Cannot compile a .klib library to WebAssembly without a main relation"
|
|
628
|
+
);
|
|
607
629
|
}
|
|
608
630
|
const mainRelName = entry || object.main || "__main__";
|
|
609
631
|
let defs = { rels: object.rels, compileStats: object.compileStats };
|
|
@@ -611,43 +633,126 @@ async function compileWasmArtifactFromObject(object, { entry = null, inputEnvelo
|
|
|
611
633
|
|
|
612
634
|
if (inputEnvelopePattern) {
|
|
613
635
|
const mainRel = object.rels[mainRelName];
|
|
614
|
-
if (!mainRel)
|
|
615
|
-
|
|
616
|
-
|
|
636
|
+
if (!mainRel) {
|
|
637
|
+
throw new Error(`No main relation (${mainRelName}) defined in object`);
|
|
638
|
+
}
|
|
639
|
+
const inputPattern = getPatternPropertyList(
|
|
640
|
+
mainRel.typePatternGraph,
|
|
641
|
+
mainRel.def.patterns[0]
|
|
642
|
+
);
|
|
643
|
+
const outputPattern = getPatternPropertyList(
|
|
644
|
+
mainRel.typePatternGraph,
|
|
645
|
+
mainRel.def.patterns[1]
|
|
646
|
+
);
|
|
617
647
|
const typing = classifyTyping(inputPattern, outputPattern);
|
|
618
648
|
if (typing.program === "polymorphic") {
|
|
619
|
-
const specialized = specializeObjectRelations(
|
|
620
|
-
|
|
649
|
+
const specialized = specializeObjectRelations(
|
|
650
|
+
object,
|
|
651
|
+
mainRelName,
|
|
652
|
+
inputEnvelopePattern
|
|
653
|
+
);
|
|
654
|
+
defs = {
|
|
655
|
+
rels: specialized.rels,
|
|
656
|
+
relAlias: specialized.relAlias,
|
|
657
|
+
compileStats: specialized.compileStats
|
|
658
|
+
};
|
|
621
659
|
typingMode = "specialized";
|
|
622
660
|
}
|
|
623
661
|
}
|
|
624
662
|
|
|
625
|
-
return compileWasmArtifactFromDefs(defs, mainRelName, {
|
|
663
|
+
return compileWasmArtifactFromDefs(defs, mainRelName, {
|
|
664
|
+
typingMode,
|
|
665
|
+
usePKIR
|
|
666
|
+
});
|
|
626
667
|
}
|
|
627
668
|
|
|
628
669
|
async function compileWasmArtifact(
|
|
629
670
|
source,
|
|
630
|
-
{
|
|
671
|
+
{
|
|
672
|
+
libraries = [],
|
|
673
|
+
exports = [],
|
|
674
|
+
source: sourceName = null,
|
|
675
|
+
inputEnvelopePattern = null,
|
|
676
|
+
usePKIR = false
|
|
677
|
+
} = {}
|
|
631
678
|
) {
|
|
632
679
|
const preamble = buildExportPreamble(exports, libraries);
|
|
633
680
|
const fullSource = preamble + source;
|
|
634
|
-
const options = {
|
|
681
|
+
const options = {
|
|
682
|
+
libraries,
|
|
683
|
+
...(sourceName ? { source: sourceName } : {})
|
|
684
|
+
};
|
|
635
685
|
let defs = annotate(fullSource, options);
|
|
636
686
|
|
|
637
687
|
let typingMode = "generic";
|
|
638
688
|
if (inputEnvelopePattern) {
|
|
639
689
|
const mainRel = defs.rels.__main__;
|
|
640
|
-
const inputPattern = getPatternPropertyList(
|
|
641
|
-
|
|
690
|
+
const inputPattern = getPatternPropertyList(
|
|
691
|
+
mainRel.typePatternGraph,
|
|
692
|
+
mainRel.def.patterns[0]
|
|
693
|
+
);
|
|
694
|
+
const outputPattern = getPatternPropertyList(
|
|
695
|
+
mainRel.typePatternGraph,
|
|
696
|
+
mainRel.def.patterns[1]
|
|
697
|
+
);
|
|
642
698
|
if (classifyTyping(inputPattern, outputPattern).program === "polymorphic") {
|
|
643
|
-
const obj = {
|
|
644
|
-
|
|
645
|
-
|
|
699
|
+
const obj = {
|
|
700
|
+
format: "k-object",
|
|
701
|
+
rels: defs.rels,
|
|
702
|
+
relAlias: defs.relAlias,
|
|
703
|
+
compileStats: defs.compileStats,
|
|
704
|
+
main: "__main__"
|
|
705
|
+
};
|
|
706
|
+
const specialized = specializeObjectRelations(
|
|
707
|
+
obj,
|
|
708
|
+
"__main__",
|
|
709
|
+
inputEnvelopePattern
|
|
710
|
+
);
|
|
711
|
+
defs = {
|
|
712
|
+
rels: specialized.rels,
|
|
713
|
+
relAlias: specialized.relAlias,
|
|
714
|
+
compileStats: specialized.compileStats
|
|
715
|
+
};
|
|
646
716
|
typingMode = "specialized";
|
|
647
717
|
}
|
|
648
718
|
}
|
|
649
719
|
|
|
650
|
-
return compileWasmArtifactFromDefs(defs, "__main__", {
|
|
720
|
+
return compileWasmArtifactFromDefs(defs, "__main__", {
|
|
721
|
+
typingMode,
|
|
722
|
+
usePKIR
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
async function compileWasmArtifactFromPKIR(pkirInput, options = {}) {
|
|
727
|
+
let kvmProgram;
|
|
728
|
+
let entry = options.entry || "__main__";
|
|
729
|
+
if (pkirInput && typeof pkirInput === "object") {
|
|
730
|
+
if (pkirInput.format === "pk-ir" && pkirInput.functions) {
|
|
731
|
+
entry = pkirInput.entry || entry;
|
|
732
|
+
kvmProgram = {};
|
|
733
|
+
for (const [name, f] of Object.entries(pkirInput.functions)) {
|
|
734
|
+
kvmProgram[name] = lowerPKIRToKVM(f);
|
|
735
|
+
}
|
|
736
|
+
} else if (pkirInput.instructions) {
|
|
737
|
+
const kvm = lowerPKIRToKVM(pkirInput);
|
|
738
|
+
entry = kvm.name || entry;
|
|
739
|
+
kvmProgram = { [entry]: kvm };
|
|
740
|
+
} else if (pkirInput.functions) {
|
|
741
|
+
entry = pkirInput.entry || entry;
|
|
742
|
+
kvmProgram = {};
|
|
743
|
+
for (const [name, f] of Object.entries(pkirInput.functions)) {
|
|
744
|
+
kvmProgram[name] = lowerPKIRToKVM(f);
|
|
745
|
+
}
|
|
746
|
+
} else {
|
|
747
|
+
throw new Error("Invalid PKIR input for WebAssembly compilation");
|
|
748
|
+
}
|
|
749
|
+
} else {
|
|
750
|
+
throw new Error("Expected PKIR input object");
|
|
751
|
+
}
|
|
752
|
+
return compileWasmArtifactFromKVM(
|
|
753
|
+
{ format: "k-vm", layer: "KVM", entry, functions: kvmProgram },
|
|
754
|
+
options
|
|
755
|
+
);
|
|
651
756
|
}
|
|
652
757
|
|
|
653
758
|
function createTagRegistry(entries) {
|
|
@@ -1050,6 +1155,7 @@ export {
|
|
|
1050
1155
|
appendCustomSection,
|
|
1051
1156
|
compileWasmArtifactFromKVM,
|
|
1052
1157
|
compileWasmArtifactFromObject,
|
|
1158
|
+
compileWasmArtifactFromPKIR,
|
|
1053
1159
|
compileWasmArtifact,
|
|
1054
1160
|
instantiateWasmArtifact,
|
|
1055
1161
|
metadataFromModule,
|
|
@@ -1067,6 +1173,7 @@ export default {
|
|
|
1067
1173
|
appendCustomSection,
|
|
1068
1174
|
compileWasmArtifactFromKVM,
|
|
1069
1175
|
compileWasmArtifactFromObject,
|
|
1176
|
+
compileWasmArtifactFromPKIR,
|
|
1070
1177
|
compileWasmArtifact,
|
|
1071
1178
|
metadataFromModule,
|
|
1072
1179
|
readArenaValue,
|
package/browser/repl-browser.mjs
CHANGED
|
@@ -311,13 +311,17 @@ export async function executeCommand(input) {
|
|
|
311
311
|
function updateEngineUI() {
|
|
312
312
|
const badge = document.getElementById("engine-badge");
|
|
313
313
|
if (!badge) return;
|
|
314
|
-
badge.
|
|
315
|
-
badge.title = `Engine: ${state.engine} (click to toggle wasm/js)`;
|
|
314
|
+
badge.classList.remove("js-mode", "pkir-mode");
|
|
316
315
|
if (state.engine === "js") {
|
|
316
|
+
badge.textContent = "js-in-process";
|
|
317
317
|
badge.classList.add("js-mode");
|
|
318
|
+
} else if (state.engine === "pkir") {
|
|
319
|
+
badge.textContent = "pkir-wasm";
|
|
320
|
+
badge.classList.add("pkir-mode");
|
|
318
321
|
} else {
|
|
319
|
-
badge.
|
|
322
|
+
badge.textContent = "wasm-in-process";
|
|
320
323
|
}
|
|
324
|
+
badge.title = `Engine: ${state.engine} (click to toggle wasm/pkir/js)`;
|
|
321
325
|
}
|
|
322
326
|
|
|
323
327
|
function adjustInputHeight() {
|
|
@@ -979,11 +983,18 @@ export function initRepl() {
|
|
|
979
983
|
}
|
|
980
984
|
});
|
|
981
985
|
|
|
982
|
-
// Engine Badge toggle (wasm
|
|
986
|
+
// Engine Badge toggle (wasm -> pkir -> js -> wasm)
|
|
983
987
|
const engineBadge = document.getElementById("engine-badge");
|
|
984
988
|
if (engineBadge) {
|
|
985
989
|
engineBadge.onclick = () => {
|
|
986
|
-
|
|
990
|
+
let nextEngine;
|
|
991
|
+
if (state.engine === "wasm") {
|
|
992
|
+
nextEngine = "pkir";
|
|
993
|
+
} else if (state.engine === "pkir") {
|
|
994
|
+
nextEngine = "js";
|
|
995
|
+
} else {
|
|
996
|
+
nextEngine = "wasm";
|
|
997
|
+
}
|
|
987
998
|
executeCommand(`:engine ${nextEngine}`);
|
|
988
999
|
};
|
|
989
1000
|
}
|
package/codecs/k-parse.mjs
CHANGED
|
@@ -7,10 +7,32 @@ import { isMainEntrypoint } from "./runtime/cli-entry.mjs";
|
|
|
7
7
|
import { patternFromFilter } from "./runtime/pattern-k.mjs";
|
|
8
8
|
import { encodeToWire } from "./runtime/prefix-codec.mjs";
|
|
9
9
|
|
|
10
|
-
function
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
function helpText() {
|
|
11
|
+
const prog = argv[1] || "k-parse.mjs";
|
|
12
|
+
return [
|
|
13
|
+
"Parse a textual k value and emit a binary pattern+value stream.",
|
|
14
|
+
"If no pattern or type is provided, derives a closed pattern from",
|
|
15
|
+
"the value.",
|
|
16
|
+
"",
|
|
17
|
+
`Usage: ${prog} [options] [value-file]`,
|
|
18
|
+
"",
|
|
19
|
+
"Arguments:",
|
|
20
|
+
" value-file Input textual k value file.",
|
|
21
|
+
" Reads from stdin when omitted.",
|
|
22
|
+
"",
|
|
23
|
+
"Options:",
|
|
24
|
+
" --input-type type Type filter script or file for pattern.",
|
|
25
|
+
" --input-pattern json Pattern JSON string or file.",
|
|
26
|
+
" -h, --help Show this help.",
|
|
27
|
+
"",
|
|
28
|
+
"Examples:",
|
|
29
|
+
` echo '{"x": 1}' | ${prog} | k-print`,
|
|
30
|
+
` ${prog} --input-type '<{} a, {} b>' value.kv`
|
|
31
|
+
].join("\n");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function usage(stream = console.error) {
|
|
35
|
+
stream(helpText());
|
|
14
36
|
}
|
|
15
37
|
|
|
16
38
|
function maybeReadFile(s) {
|
|
@@ -31,11 +53,10 @@ function readAll(stream) {
|
|
|
31
53
|
}
|
|
32
54
|
|
|
33
55
|
async function main() {
|
|
34
|
-
const prog = argv[1];
|
|
35
56
|
const args = argv.slice(2);
|
|
36
57
|
|
|
37
58
|
if (args.includes("-h") || args.includes("--help")) {
|
|
38
|
-
usage(
|
|
59
|
+
usage(console.log);
|
|
39
60
|
return exit(0);
|
|
40
61
|
}
|
|
41
62
|
|
|
@@ -51,13 +72,13 @@ async function main() {
|
|
|
51
72
|
} else if (valueFile == null) {
|
|
52
73
|
valueFile = args[i];
|
|
53
74
|
} else {
|
|
54
|
-
usage(
|
|
75
|
+
usage();
|
|
55
76
|
return exit(1);
|
|
56
77
|
}
|
|
57
78
|
}
|
|
58
79
|
|
|
59
80
|
if (inputTypeArg != null && inputPatternArg != null) {
|
|
60
|
-
usage(
|
|
81
|
+
usage();
|
|
61
82
|
return exit(1);
|
|
62
83
|
}
|
|
63
84
|
|
package/codecs/k-print.mjs
CHANGED
|
@@ -5,13 +5,29 @@ import { argv, stdin, stdout } from "node:process";
|
|
|
5
5
|
import { isMainEntrypoint } from "./runtime/cli-entry.mjs";
|
|
6
6
|
import { decodeWire } from "./runtime/prefix-codec.mjs";
|
|
7
7
|
|
|
8
|
+
function helpText() {
|
|
9
|
+
const prog = argv[1] || "k-print.mjs";
|
|
10
|
+
return [
|
|
11
|
+
"Read a binary pattern+value stream and print the decoded",
|
|
12
|
+
"textual value.",
|
|
13
|
+
"",
|
|
14
|
+
`Usage: ${prog} [options] [file]`,
|
|
15
|
+
"",
|
|
16
|
+
"Arguments:",
|
|
17
|
+
" file Input binary wire file (default: stdin).",
|
|
18
|
+
"",
|
|
19
|
+
"Options:",
|
|
20
|
+
" --debug Print decoded pattern and value as JSON.",
|
|
21
|
+
" -h, --help Show this help.",
|
|
22
|
+
"",
|
|
23
|
+
"Examples:",
|
|
24
|
+
` echo '"hello"' | k-parse | ${prog}`,
|
|
25
|
+
` ${prog} input.wire`
|
|
26
|
+
].join("\n");
|
|
27
|
+
}
|
|
28
|
+
|
|
8
29
|
function usage(stream = console.error) {
|
|
9
|
-
stream(
|
|
10
|
-
stream(" Read a binary pattern+value stream and print the decoded textual value.");
|
|
11
|
-
stream("");
|
|
12
|
-
stream("Options:");
|
|
13
|
-
stream(" --debug Print decoded pattern and value as JSON.");
|
|
14
|
-
stream(" -h, --help Show this help.");
|
|
30
|
+
stream(helpText());
|
|
15
31
|
}
|
|
16
32
|
|
|
17
33
|
function readAll(stream) {
|
|
@@ -22,10 +22,14 @@ function printUsage(fileName, doc) {
|
|
|
22
22
|
if (doc) {
|
|
23
23
|
stdout.write(`${doc.trim()}\n\n`);
|
|
24
24
|
}
|
|
25
|
-
stdout.write(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
stdout.write(
|
|
26
|
+
"Options:\n" +
|
|
27
|
+
" --parse Read external text from stdin, write binary\n" +
|
|
28
|
+
" pattern+value stream to stdout.\n" +
|
|
29
|
+
" --print Read binary pattern+value stream from stdin,\n" +
|
|
30
|
+
" write external text to stdout.\n" +
|
|
31
|
+
" -h, --help Show this help.\n"
|
|
32
|
+
);
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
function runCodecCLI(metaUrl, codec) {
|