@fraczak/k 7.0.1 → 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 +78 -0
- package/DOCS/BIG_PICTURE.md +5 -5
- package/DOCS/FILE_FORMATS.md +241 -18
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +9 -9
- package/DOCS/PATTERNS.md +3 -3
- package/DOCS/POLYMORPHIC_IR.md +104 -0
- package/DOCS/PROFILING_AND_TRACING.md +60 -72
- package/DOCS/REPL.md +3 -3
- package/DOCS/book/03-types-as-finite-automata.md +4 -4
- package/DOCS/book/06-values-in-memory.md +9 -9
- package/DOCS/book/08-operational-semantics-and-execution.md +1 -1
- package/DOCS/book/09-compiler-architecture.md +2 -2
- package/DOCS/book/10-from-ast-to-intermediate-representation.md +2 -2
- package/DOCS/book/14-canonical-serialization.md +1 -1
- package/Examples/arithmetics.k +2 -2
- package/Examples/bnat.k +1 -1
- package/Examples/karatsuba-mult.k +2 -2
- package/JOURNAL.md +288 -0
- package/README.md +13 -10
- 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 +41 -0
- package/backends/llvm/runtime/krt.h +2 -0
- package/backends/llvm/src/cli.mjs +95 -17
- package/backends/llvm/src/executable.mjs +132 -15
- package/backends/llvm/src/kvm2llvm.mjs +50 -23
- package/backends/llvm/src/llvm.mjs +133 -20
- 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 +25 -58
- package/backends/llvm/tests/test-llvm.mjs +25 -4
- 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 +132 -24
- package/backends/wasm/tests/test-wasm.mjs +5 -5
- package/browser/repl-browser.mjs +16 -5
- package/browser/vfs-data.mjs +5 -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/core.k +8 -8
- package/harness/format.mjs +2 -2
- package/harness/registry.mjs +0 -2
- package/k.mjs +56 -16
- package/kir.mjs +200 -75
- 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 -7
- package/pkir.mjs +772 -0
- package/repl.mjs +36 -18
- package/scripts/benchmark-idempotency.mjs +12 -8
- package/scripts/benchmark.mjs +5 -9
- package/scripts/build-repl-html.mjs +16 -4
- package/scripts/perf-ieee.mjs +253 -103
- package/scripts/perf-int.mjs +585 -297
- package/scripts/perf-multiplication.mjs +66 -25
- package/scripts/perf-poly.mjs +292 -164
- package/scripts/run-tests.mjs +3 -0
- package/tests/code-derivation/pattern-envelope.mjs +4 -4
- package/tests/test-access-table.mjs +213 -0
- package/tests/test-kvm-polymorphic.mjs +2 -2
- 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/arm64/README.md +0 -103
- package/backends/arm64/bin/k-arm64-compile.mjs +0 -93
- package/backends/arm64/bin/k-arm64-run.mjs +0 -58
- package/backends/arm64/bin/k-arm64.mjs +0 -88
- package/backends/arm64/scripts/run-tests.mjs +0 -57
- package/backends/arm64/src/arm64.mjs +0 -229
- package/backends/arm64/src/cli.mjs +0 -155
- package/backends/arm64/src/kvm2arm64.mjs +0 -906
- package/backends/arm64/src/runtime.c +0 -744
- package/backends/arm64/tests/integration.sh +0 -112
- package/backends/arm64/tests/test-arm64.mjs +0 -240
- package/backends/llvm/bin/k-llvm-jit.mjs +0 -160
- package/harness/adapters/arm64.mjs +0 -105
|
@@ -6,22 +6,35 @@ import { decodeObject } from "@fraczak/k/object.mjs";
|
|
|
6
6
|
import { parseValue } from "@fraczak/k/valueIO.mjs";
|
|
7
7
|
import { compileObjectAndRun } from "../src/executable.mjs";
|
|
8
8
|
|
|
9
|
-
function
|
|
9
|
+
function helpText() {
|
|
10
10
|
const prog = argv[1] || "k-llvm-run.mjs";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
11
|
+
return [
|
|
12
|
+
"Compile and execute a k .ko/.klib object through LLVM.",
|
|
13
|
+
"",
|
|
14
|
+
`Usage: ${prog} [options] object-file [input.kv]`,
|
|
15
|
+
"",
|
|
16
|
+
"Arguments:",
|
|
17
|
+
" object-file Input .ko or .klib file.",
|
|
18
|
+
" input.kv Input value. Reads text from stdin when omitted.",
|
|
19
|
+
"",
|
|
20
|
+
"Options:",
|
|
21
|
+
" --retype rel Relation to specialize (default: main).",
|
|
22
|
+
" --input-pattern value Input pattern property-list JSON or file.",
|
|
23
|
+
" --expect value Expected output value JSON/text or file.",
|
|
24
|
+
" --pkir Lower via Polymorphic K IR (PKIR).",
|
|
25
|
+
" -h, --help Show this help.",
|
|
26
|
+
"",
|
|
27
|
+
"Without --expect, the runner prints the result as compact JSON.",
|
|
28
|
+
"",
|
|
29
|
+
"Examples:",
|
|
30
|
+
` ${prog} program.ko input.kv`,
|
|
31
|
+
` ${prog} --expect expected.kv program.ko input.kv`,
|
|
32
|
+
` echo '{"x":"left"}' | ${prog} program.ko`
|
|
33
|
+
].join("\n");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function usage(stream = console.error) {
|
|
37
|
+
stream(helpText());
|
|
25
38
|
}
|
|
26
39
|
|
|
27
40
|
async function readStdinText() {
|
|
@@ -33,7 +46,9 @@ async function readStdinText() {
|
|
|
33
46
|
}
|
|
34
47
|
|
|
35
48
|
function readMaybeFile(textOrPath) {
|
|
36
|
-
return fs.existsSync(textOrPath)
|
|
49
|
+
return fs.existsSync(textOrPath)
|
|
50
|
+
? fs.readFileSync(textOrPath, "utf8")
|
|
51
|
+
: textOrPath;
|
|
37
52
|
}
|
|
38
53
|
|
|
39
54
|
function readPattern(inputPattern) {
|
|
@@ -51,6 +66,7 @@ try {
|
|
|
51
66
|
let relation = null;
|
|
52
67
|
let inputPattern = null;
|
|
53
68
|
let expectedText = null;
|
|
69
|
+
let usePKIR = false;
|
|
54
70
|
while (args.length > 0 && args[0].startsWith("--")) {
|
|
55
71
|
const option = args.shift();
|
|
56
72
|
if (option === "--retype") {
|
|
@@ -58,10 +74,16 @@ try {
|
|
|
58
74
|
if (!relation) throw new Error("--retype requires a relation name");
|
|
59
75
|
} else if (option === "--input-pattern") {
|
|
60
76
|
inputPattern = args.shift();
|
|
61
|
-
if (!inputPattern)
|
|
77
|
+
if (!inputPattern) {
|
|
78
|
+
throw new Error("--input-pattern requires JSON or a file path");
|
|
79
|
+
}
|
|
62
80
|
} else if (option === "--expect") {
|
|
63
81
|
expectedText = args.shift();
|
|
64
|
-
if (!expectedText)
|
|
82
|
+
if (!expectedText) {
|
|
83
|
+
throw new Error("--expect requires a value or file path");
|
|
84
|
+
}
|
|
85
|
+
} else if (option === "--pkir") {
|
|
86
|
+
usePKIR = true;
|
|
65
87
|
} else {
|
|
66
88
|
throw new Error(`Unknown option: ${option}`);
|
|
67
89
|
}
|
|
@@ -73,18 +95,22 @@ try {
|
|
|
73
95
|
if (args.length > 0) throw new Error(`Unexpected argument: ${args[0]}`);
|
|
74
96
|
|
|
75
97
|
const object = decodeObject(fs.readFileSync(objectPath));
|
|
76
|
-
const inputText = inputPath == null
|
|
98
|
+
const inputText = inputPath == null
|
|
99
|
+
? await readStdinText()
|
|
100
|
+
: fs.readFileSync(inputPath, "utf8");
|
|
77
101
|
const input = parseValue(inputText);
|
|
78
|
-
const expected = expectedText == null
|
|
102
|
+
const expected = expectedText == null
|
|
103
|
+
? null
|
|
104
|
+
: parseValue(readMaybeFile(expectedText));
|
|
79
105
|
const result = compileObjectAndRun(object, {
|
|
80
106
|
relation: relation || object.main,
|
|
81
107
|
input,
|
|
82
108
|
expected,
|
|
83
|
-
inputPattern: readPattern(inputPattern)
|
|
109
|
+
inputPattern: readPattern(inputPattern),
|
|
110
|
+
usePKIR
|
|
84
111
|
});
|
|
85
112
|
stdout.write(expected == null ? result.stdout : "OK\n");
|
|
86
113
|
} catch (error) {
|
|
87
114
|
console.error(error.stack || error.message || String(error));
|
|
88
|
-
usage();
|
|
89
115
|
exit(1);
|
|
90
116
|
}
|
|
@@ -148,7 +148,17 @@ export function wireInput(value, pattern = value.pattern) {
|
|
|
148
148
|
};
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
export function compileCaseExecutable({
|
|
151
|
+
export function compileCaseExecutable({
|
|
152
|
+
object,
|
|
153
|
+
relationName,
|
|
154
|
+
relHash,
|
|
155
|
+
inputPattern,
|
|
156
|
+
cacheDir,
|
|
157
|
+
sourceLabel,
|
|
158
|
+
runtimeMode = "fast",
|
|
159
|
+
clangOpt = "-O3",
|
|
160
|
+
usePKIR = false
|
|
161
|
+
}) {
|
|
152
162
|
const key = sha256([
|
|
153
163
|
"k-llvm-perf-v1",
|
|
154
164
|
backendFingerprint(),
|
|
@@ -157,12 +167,23 @@ export function compileCaseExecutable({ object, relationName, relHash, inputPatt
|
|
|
157
167
|
sourceLabel,
|
|
158
168
|
relationName,
|
|
159
169
|
relHash,
|
|
160
|
-
JSON.stringify(inputPattern)
|
|
170
|
+
JSON.stringify(inputPattern),
|
|
171
|
+
usePKIR ? "pkir" : "kir"
|
|
161
172
|
].join("\0"));
|
|
162
173
|
const exePath = path.join(cacheDir, `${key}.exe`);
|
|
163
174
|
if (!fs.existsSync(exePath)) {
|
|
164
175
|
const tmpPath = path.join(cacheDir, `${key}.${process.pid}.tmp`);
|
|
165
|
-
compileObjectToExecutable(
|
|
176
|
+
compileObjectToExecutable(
|
|
177
|
+
cloneObjectPayload(object),
|
|
178
|
+
tmpPath,
|
|
179
|
+
{
|
|
180
|
+
relation: relationName,
|
|
181
|
+
inputPattern,
|
|
182
|
+
runtimeMode,
|
|
183
|
+
clangOpt,
|
|
184
|
+
usePKIR
|
|
185
|
+
}
|
|
186
|
+
);
|
|
166
187
|
fs.renameSync(tmpPath, exePath);
|
|
167
188
|
}
|
|
168
189
|
return exePath;
|
|
@@ -216,7 +237,7 @@ export function runExecutableMainBench(exePath, inputWire, calls) {
|
|
|
216
237
|
reject(new Error(`${exePath} --bench-main failed with status ${status}\n${text}`.trim()));
|
|
217
238
|
return;
|
|
218
239
|
}
|
|
219
|
-
const match = text.match(/
|
|
240
|
+
const match = text.match(/K_LLVM_BENCH_MAIN calls=(\d+) total_ns=(\d+) per_call_ns=([0-9.]+)/);
|
|
220
241
|
if (!match) {
|
|
221
242
|
reject(new Error(`${exePath} --bench-main did not report timing\n${text}`.trim()));
|
|
222
243
|
return;
|
|
@@ -599,61 +620,7 @@ export function llvmLaneName() {
|
|
|
599
620
|
: "LLVM Executable (persistent)";
|
|
600
621
|
}
|
|
601
622
|
|
|
602
|
-
export function arm64LaneName(optLevel = "-O2") {
|
|
603
|
-
const mode = process.env.ARM64_SPAWN_PER_CALL === "1"
|
|
604
|
-
? "spawn/call"
|
|
605
|
-
: (process.env.ARM64_PIPELINE === "1" ? "persistent, pipelined" : "persistent");
|
|
606
|
-
return `Linux ARM64 ${optLevel} (${mode})`;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
export function createARM64Runner(testSuite) {
|
|
610
|
-
const arm64Cases = testSuite.filter(tc => tc.arm64?.status === "ok");
|
|
611
|
-
if (process.env.ARM64_SPAWN_PER_CALL === "1") {
|
|
612
|
-
return {
|
|
613
|
-
run(iterations) {
|
|
614
|
-
if (arm64Cases.length === 0) return null;
|
|
615
|
-
return runTimedIterationsAsync(iterations, async () => {
|
|
616
|
-
for (const tc of arm64Cases) {
|
|
617
|
-
await runExecutable(tc.arm64.exePath, tc.inputWire);
|
|
618
|
-
}
|
|
619
|
-
});
|
|
620
|
-
},
|
|
621
|
-
close() {}
|
|
622
|
-
};
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
const servers = new Map();
|
|
626
|
-
function serverFor(exePath) {
|
|
627
|
-
let server = servers.get(exePath);
|
|
628
|
-
if (server == null) {
|
|
629
|
-
server = new PersistentExecutable(exePath);
|
|
630
|
-
servers.set(exePath, server);
|
|
631
|
-
}
|
|
632
|
-
return server;
|
|
633
|
-
}
|
|
634
623
|
|
|
635
|
-
return {
|
|
636
|
-
async run(iterations) {
|
|
637
|
-
if (arm64Cases.length === 0) return null;
|
|
638
|
-
return runTimedIterationsAsync(iterations, async () => {
|
|
639
|
-
if (process.env.ARM64_PIPELINE === "1") {
|
|
640
|
-
const pending = [];
|
|
641
|
-
for (const tc of arm64Cases) {
|
|
642
|
-
pending.push(serverFor(tc.arm64.exePath).request(tc.inputWire));
|
|
643
|
-
}
|
|
644
|
-
await Promise.all(pending);
|
|
645
|
-
return;
|
|
646
|
-
}
|
|
647
|
-
for (const tc of arm64Cases) {
|
|
648
|
-
await serverFor(tc.arm64.exePath).request(tc.inputWire);
|
|
649
|
-
}
|
|
650
|
-
});
|
|
651
|
-
},
|
|
652
|
-
close() {
|
|
653
|
-
for (const server of servers.values()) server.close();
|
|
654
|
-
}
|
|
655
|
-
};
|
|
656
|
-
}
|
|
657
624
|
|
|
658
625
|
export function average(times) {
|
|
659
626
|
return times.reduce((sum, time) => sum + time, 0) / times.length;
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { compileObjectBuffer, decodeObject } from "@fraczak/k/object.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
compileObjectToLLVM,
|
|
5
|
+
compileLLVMArtifactFromKVM,
|
|
6
|
+
compileLLVMArtifactFromPKIR,
|
|
7
|
+
emitLLVMModule,
|
|
8
|
+
llvmIdentifier
|
|
9
|
+
} from "../src/llvm.mjs";
|
|
4
10
|
import { objectToKVMArtifact } from "@fraczak/k/kvm.mjs";
|
|
11
|
+
import { compileRelationToPKIR } from "@fraczak/k/backend-api.mjs";
|
|
5
12
|
|
|
6
13
|
function kirP(body, { patternGraph = null } = {}) {
|
|
7
14
|
return {
|
|
@@ -239,11 +246,11 @@ assert.doesNotMatch(nestedUnionLLVM, /call void @k_product_set_at\(ptr %product\
|
|
|
239
246
|
assert.doesNotMatch(nestedUnionLLVM, /ptr false/);
|
|
240
247
|
|
|
241
248
|
const productRecurseObject = decodeObject(compileObjectBuffer(`
|
|
242
|
-
list = ?< {} nil, { {} car, list cdr } cons >;
|
|
243
|
-
foo = list <
|
|
249
|
+
list? = ?< {} nil, { {} car, list? cdr } cons >;
|
|
250
|
+
foo = list? <
|
|
244
251
|
/nil |nil,
|
|
245
252
|
/cons { .car car, .cdr foo cdr } |cons
|
|
246
|
-
> list
|
|
253
|
+
> list?;
|
|
247
254
|
foo
|
|
248
255
|
`, { source: "llvm-product-recurse.k" }));
|
|
249
256
|
const { llvm: productRecurseLLVM } = compileObjectToLLVM(productRecurseObject, {
|
|
@@ -270,4 +277,18 @@ assert.match(kvmLLVM, /source_filename = "k-llvm:__main__"/);
|
|
|
270
277
|
assert.match(kvmLLVM, /define %k_result @k_main/);
|
|
271
278
|
assert.match(kvmLLVM, /store ptr %product_fields\d+, ptr %ptr_slot\d+/);
|
|
272
279
|
|
|
280
|
+
// Test PKIR lowering via compileObjectToLLVM with usePKIR: true
|
|
281
|
+
const pkirObjectLLVM = compileObjectToLLVM(productObject, {
|
|
282
|
+
usePKIR: true
|
|
283
|
+
});
|
|
284
|
+
assert.match(pkirObjectLLVM.llvm, /source_filename = "k-llvm:__main__"/);
|
|
285
|
+
assert.match(pkirObjectLLVM.llvm, /define %k_result @k_main/);
|
|
286
|
+
|
|
287
|
+
// Test compileLLVMArtifactFromPKIR directly
|
|
288
|
+
const mainRel = productObject.rels[productObject.main || "__main__"];
|
|
289
|
+
const pkirFromRel = compileRelationToPKIR(mainRel, "__main__");
|
|
290
|
+
const pkirLLVM = compileLLVMArtifactFromPKIR(pkirFromRel);
|
|
291
|
+
assert.match(pkirLLVM, /source_filename = "k-llvm:__main__"/);
|
|
292
|
+
assert.match(pkirLLVM, /define %k_result @k_main/);
|
|
293
|
+
|
|
273
294
|
console.log("OK");
|
|
@@ -9,22 +9,39 @@ import {
|
|
|
9
9
|
resolveProgramInput
|
|
10
10
|
} from "../src/cli.mjs";
|
|
11
11
|
|
|
12
|
-
function
|
|
12
|
+
function helpText() {
|
|
13
13
|
const prog = argv[1] || "k-wasm-compile.mjs";
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
14
|
+
return [
|
|
15
|
+
"Compile k source, .ko, .kvm, or .pkir into a WebAssembly (.wasm)",
|
|
16
|
+
"artifact.",
|
|
17
|
+
"",
|
|
18
|
+
`Usage: ${prog} [options]`,
|
|
19
|
+
" [source-snippet | input-file [output-wasm]]",
|
|
20
|
+
"",
|
|
21
|
+
"Arguments:",
|
|
22
|
+
" source-snippet Inline k source snippet (in the style of k.mjs).",
|
|
23
|
+
" input-file Source .k, .ko, .kvm, or .pkir file.",
|
|
24
|
+
" Reads UTF-8 source from stdin when omitted.",
|
|
25
|
+
" output-wasm Output .wasm path. Writes to stdout if omitted.",
|
|
26
|
+
"",
|
|
27
|
+
"Options:",
|
|
28
|
+
" -o, --output path Specify output file path explicitly.",
|
|
29
|
+
" --pkir Lower via Polymorphic K IR (PKIR).",
|
|
30
|
+
" --lib file Load one .klib or .k library before compiling.",
|
|
31
|
+
" --export spec Export library alias into scope. Repeatable.",
|
|
32
|
+
" spec is 'name' or 'libname:localname'.",
|
|
33
|
+
" -h, --help Show this help.",
|
|
34
|
+
"",
|
|
35
|
+
"Examples:",
|
|
36
|
+
` ${prog} 'x = |x; x x' program.wasm`,
|
|
37
|
+
` ${prog} program.k -o program.wasm`,
|
|
38
|
+
` ${prog} --pkir program.k -o program.wasm`,
|
|
39
|
+
` ${prog} --lib core.klib --export add program.k program.wasm`
|
|
40
|
+
].join("\n");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function usage(stream = console.error) {
|
|
44
|
+
stream(helpText());
|
|
28
45
|
}
|
|
29
46
|
|
|
30
47
|
try {
|
|
@@ -41,18 +58,28 @@ try {
|
|
|
41
58
|
if (arg === "-o" || arg === "--output") {
|
|
42
59
|
args.shift();
|
|
43
60
|
explicitOutput = args.shift();
|
|
44
|
-
if (!explicitOutput)
|
|
61
|
+
if (!explicitOutput) {
|
|
62
|
+
throw new Error("-o/--output requires a file argument");
|
|
63
|
+
}
|
|
45
64
|
} else {
|
|
46
65
|
remainingArgs.push(args.shift());
|
|
47
66
|
}
|
|
48
67
|
}
|
|
49
68
|
|
|
50
|
-
const { libraries, exportSpecs } =
|
|
51
|
-
|
|
69
|
+
const { libraries, exportSpecs, usePKIR } =
|
|
70
|
+
parseCompileOptions(remainingArgs);
|
|
71
|
+
const input = resolveProgramInput(remainingArgs, {
|
|
72
|
+
allowStdinSource: true
|
|
73
|
+
});
|
|
52
74
|
const positionalOutput = remainingArgs.shift();
|
|
53
75
|
if (remainingArgs.length > 0) throw new Error("Too many arguments");
|
|
54
76
|
const outputPath = explicitOutput || positionalOutput || null;
|
|
55
|
-
const artifact = await compileProgramInput(input, {
|
|
77
|
+
const artifact = await compileProgramInput(input, {
|
|
78
|
+
libraries,
|
|
79
|
+
exportSpecs,
|
|
80
|
+
stdin,
|
|
81
|
+
usePKIR
|
|
82
|
+
});
|
|
56
83
|
if (outputPath == null) {
|
|
57
84
|
stdout.write(artifact);
|
|
58
85
|
} else {
|
|
@@ -60,6 +87,5 @@ try {
|
|
|
60
87
|
}
|
|
61
88
|
} catch (error) {
|
|
62
89
|
console.error(error.stack || error.message || String(error));
|
|
63
|
-
usage();
|
|
64
90
|
exit(1);
|
|
65
91
|
}
|
|
@@ -5,31 +5,54 @@ import { argv, exit, stdin, stdout, stderr } from "node:process";
|
|
|
5
5
|
|
|
6
6
|
import { instantiateWasmArtifact } from "../src/wasm.mjs";
|
|
7
7
|
|
|
8
|
-
function
|
|
8
|
+
function helpText() {
|
|
9
9
|
const prog = argv[1] || "k-wasm-run.mjs";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
return [
|
|
11
|
+
"Run a standalone WebAssembly (.wasm) artifact over a binary",
|
|
12
|
+
"pattern+value wire stream.",
|
|
13
|
+
"",
|
|
14
|
+
`Usage: ${prog} [options] wasm-file [ input-wire-file ]`,
|
|
15
|
+
"",
|
|
16
|
+
"Arguments:",
|
|
17
|
+
" wasm-file Input .wasm artifact produced by k-wasm-compile.",
|
|
18
|
+
" input-wire-file Optional binary wire input (default: stdin).",
|
|
19
|
+
"",
|
|
20
|
+
"Options:",
|
|
21
|
+
" --server Run as persistent server reading framed requests from",
|
|
22
|
+
" stdin.",
|
|
23
|
+
" -h, --help Show this help.",
|
|
24
|
+
"",
|
|
25
|
+
"Environment Variables:",
|
|
26
|
+
" K_TRACE, TRACE When '1', output phase tracing metrics to stderr.",
|
|
27
|
+
"",
|
|
28
|
+
"Examples:",
|
|
29
|
+
` echo '"hello"' | k-json --parse | \\`,
|
|
30
|
+
` ${prog} prog.wasm | k-json --print`,
|
|
31
|
+
` ${prog} prog.wasm input.wire > output.wire`,
|
|
32
|
+
` ${prog} --server prog.wasm`
|
|
33
|
+
].join("\n");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function usage(stream = console.error) {
|
|
37
|
+
stream(helpText());
|
|
20
38
|
}
|
|
21
39
|
|
|
22
40
|
function readAll(stream) {
|
|
23
41
|
return new Promise((resolve, reject) => {
|
|
24
42
|
const chunks = [];
|
|
25
|
-
stream.on("data", (chunk) =>
|
|
43
|
+
stream.on("data", (chunk) => {
|
|
44
|
+
chunks.push(
|
|
45
|
+
Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)
|
|
46
|
+
);
|
|
47
|
+
});
|
|
26
48
|
stream.on("end", () => resolve(Buffer.concat(chunks)));
|
|
27
49
|
stream.on("error", reject);
|
|
28
50
|
});
|
|
29
51
|
}
|
|
30
52
|
|
|
31
53
|
async function runServer(runner) {
|
|
32
|
-
const tracing =
|
|
54
|
+
const tracing =
|
|
55
|
+
process.env.K_TRACE === "1" || process.env.TRACE === "1";
|
|
33
56
|
let inBuffer = Buffer.alloc(0);
|
|
34
57
|
let readStartNs = 0n;
|
|
35
58
|
|
|
@@ -82,10 +105,17 @@ async function runServer(runner) {
|
|
|
82
105
|
const encodeNs = trace.encodeNs;
|
|
83
106
|
const ipcWriteNs = Number(tEnd - writeStart);
|
|
84
107
|
const totalNs = Number(tEnd - (readStartNs > 0n ? readStartNs : t1));
|
|
85
|
-
stderr.write(
|
|
108
|
+
stderr.write(
|
|
109
|
+
`K_TRACE_PHASES backend=wasm ipc_read_ns=${ipcReadNs} ` +
|
|
110
|
+
`decode_ns=${decodeNs} flat_in_ns=${flatInNs} ` +
|
|
111
|
+
`eval_ns=${evalNs} flat_out_ns=${flatOutNs} ` +
|
|
112
|
+
`encode_ns=${encodeNs} ipc_write_ns=${ipcWriteNs} ` +
|
|
113
|
+
`total_ns=${totalNs}\n`
|
|
114
|
+
);
|
|
86
115
|
}
|
|
87
116
|
} catch (err) {
|
|
88
|
-
|
|
117
|
+
const msg = err.stack || err.message || String(err);
|
|
118
|
+
stderr.write(`Wasm server error: ${msg}\n`);
|
|
89
119
|
exit(1);
|
|
90
120
|
}
|
|
91
121
|
|
|
@@ -102,7 +132,7 @@ async function main() {
|
|
|
102
132
|
}
|
|
103
133
|
|
|
104
134
|
const isServer = rawArgs.includes("--server");
|
|
105
|
-
const args = rawArgs.filter(a => a !== "--server");
|
|
135
|
+
const args = rawArgs.filter((a) => a !== "--server");
|
|
106
136
|
|
|
107
137
|
const wasmPath = args.shift();
|
|
108
138
|
if (!wasmPath) throw new Error("Missing .wasm artifact path");
|
|
@@ -111,7 +141,9 @@ async function main() {
|
|
|
111
141
|
const runner = await instantiateWasmArtifact(artifact);
|
|
112
142
|
|
|
113
143
|
if (isServer) {
|
|
114
|
-
if (args.length > 0)
|
|
144
|
+
if (args.length > 0) {
|
|
145
|
+
throw new Error("Too many arguments for --server mode");
|
|
146
|
+
}
|
|
115
147
|
await runServer(runner);
|
|
116
148
|
return;
|
|
117
149
|
}
|
|
@@ -119,14 +151,23 @@ async function main() {
|
|
|
119
151
|
const inputPath = args.shift();
|
|
120
152
|
if (args.length > 0) throw new Error("Too many arguments");
|
|
121
153
|
|
|
122
|
-
const
|
|
123
|
-
|
|
154
|
+
const inputStream =
|
|
155
|
+
inputPath == null ? stdin : fs.createReadStream(inputPath);
|
|
156
|
+
const input = await readAll(inputStream);
|
|
157
|
+
const tracing =
|
|
158
|
+
process.env.K_TRACE === "1" || process.env.TRACE === "1";
|
|
124
159
|
if (tracing) {
|
|
125
160
|
const res = runner.execute(input, { trace: true });
|
|
126
161
|
stdout.write(res.outputWire);
|
|
127
162
|
if (res.trace) {
|
|
128
163
|
const trace = res.trace;
|
|
129
|
-
stderr.write(
|
|
164
|
+
stderr.write(
|
|
165
|
+
`K_TRACE_PHASES backend=wasm ipc_read_ns=0 ` +
|
|
166
|
+
`decode_ns=${trace.decodeNs} flat_in_ns=${trace.flatInNs} ` +
|
|
167
|
+
`eval_ns=${trace.evalNs} flat_out_ns=${trace.flatOutNs} ` +
|
|
168
|
+
`encode_ns=${trace.encodeNs} ipc_write_ns=0 ` +
|
|
169
|
+
`total_ns=${trace.evalNs}\n`
|
|
170
|
+
);
|
|
130
171
|
}
|
|
131
172
|
} else {
|
|
132
173
|
stdout.write(runner.execute(input));
|
|
@@ -12,16 +12,40 @@ import {
|
|
|
12
12
|
} from "../src/cli.mjs";
|
|
13
13
|
import { runWasmArtifact } from "../src/wasm.mjs";
|
|
14
14
|
|
|
15
|
-
function
|
|
15
|
+
function helpText() {
|
|
16
16
|
const prog = argv[1] || "k-wasm.mjs";
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
return [
|
|
18
|
+
"Compile k source, .ko, .kvm, or .pkir to WebAssembly in memory",
|
|
19
|
+
"and run it over a binary pattern+value wire stream.",
|
|
20
|
+
"",
|
|
21
|
+
`Usage: ${prog} [options]`,
|
|
22
|
+
" ( source-snippet | input-file ) [ input-wire-file ]",
|
|
23
|
+
"",
|
|
24
|
+
"Arguments:",
|
|
25
|
+
" source-snippet Inline k source snippet (in the style of k.mjs).",
|
|
26
|
+
" input-file Source .k, .ko, .kvm, or .pkir file.",
|
|
27
|
+
" input-wire-file Optional binary wire input (default: stdin).",
|
|
28
|
+
"",
|
|
29
|
+
"Options:",
|
|
30
|
+
" --lib file Load one .klib or .k library before compiling.",
|
|
31
|
+
" --export spec Export library alias into scope. Repeatable.",
|
|
32
|
+
" spec is 'name' or 'libname:localname'.",
|
|
33
|
+
" --pkir Lower via Polymorphic K IR (PKIR).",
|
|
34
|
+
" -h, --help Show this help.",
|
|
35
|
+
"",
|
|
36
|
+
"Environment Variables:",
|
|
37
|
+
" K_TRACE, TRACE When '1', output phase tracing to stderr.",
|
|
38
|
+
"",
|
|
39
|
+
"Examples:",
|
|
40
|
+
` echo '"abc"' | k-parse | ${prog} '{.1 0}' | k-print`,
|
|
41
|
+
` echo '{"x":1,"y":2}' | k-json --parse | \\`,
|
|
42
|
+
` ${prog} --lib Examples/poly.k --export concat \\`,
|
|
43
|
+
` 's={()xs,()ys}concat; s' | k-json --print`
|
|
44
|
+
].join("\n");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function usage(stream = console.error) {
|
|
48
|
+
stream(helpText());
|
|
25
49
|
}
|
|
26
50
|
|
|
27
51
|
async function main() {
|
|
@@ -31,19 +55,29 @@ async function main() {
|
|
|
31
55
|
return;
|
|
32
56
|
}
|
|
33
57
|
|
|
34
|
-
const { libraries, exportSpecs } = parseCompileOptions(args);
|
|
58
|
+
const { libraries, exportSpecs, usePKIR } = parseCompileOptions(args);
|
|
35
59
|
const programInput = resolveProgramInput(args);
|
|
36
60
|
const inputPath = args.shift();
|
|
37
61
|
if (args.length > 0) throw new Error("Too many arguments");
|
|
38
62
|
|
|
39
|
-
const inputBuffer = await readAll(
|
|
63
|
+
const inputBuffer = await readAll(
|
|
64
|
+
inputPath == null ? stdin : fs.createReadStream(inputPath)
|
|
65
|
+
);
|
|
66
|
+
if (inputBuffer.length === 0) {
|
|
67
|
+
throw new Error("No input wire data received on stdin");
|
|
68
|
+
}
|
|
69
|
+
|
|
40
70
|
const { pattern: inputEnvelopePattern } = decodeWire(inputBuffer);
|
|
41
|
-
const artifact = await compileProgramInput(programInput, {
|
|
71
|
+
const artifact = await compileProgramInput(programInput, {
|
|
72
|
+
libraries,
|
|
73
|
+
exportSpecs,
|
|
74
|
+
inputEnvelopePattern,
|
|
75
|
+
usePKIR
|
|
76
|
+
});
|
|
42
77
|
stdout.write(await runWasmArtifact(artifact, inputBuffer));
|
|
43
78
|
}
|
|
44
79
|
|
|
45
80
|
main().catch((error) => {
|
|
46
81
|
console.error(error.stack || error.message || String(error));
|
|
47
|
-
usage();
|
|
48
82
|
exit(1);
|
|
49
83
|
});
|