@fraczak/k 7.0.2 → 7.2.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 +75 -0
- package/DOCS/CODECS.md +37 -2
- package/DOCS/CODEC_ARCHITECTURE.md +12 -5
- package/DOCS/FILE_FORMATS.md +238 -15
- package/DOCS/POLYMORPHIC_IR.md +104 -0
- package/DOCS/REPL.md +11 -3
- package/DOCS/WEB_REPL_REQUIREMENTS.md +1 -1
- package/JOURNAL.md +288 -0
- package/README.md +12 -3
- package/Value.mjs +28 -3
- package/access-table.mjs +343 -0
- package/backend-api.mjs +23 -1
- 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/browser/tree-view.mjs +47 -8
- package/browser/vfs-data.mjs +6 -5
- package/codecs/README.md +1 -0
- package/codecs/djson.mjs +270 -0
- package/codecs/int.mjs +2 -1
- package/codecs/json.mjs +7 -2
- package/codecs/k-parse.mjs +36 -9
- package/codecs/k-print.mjs +26 -6
- package/codecs/runtime/codec-sdk.mjs +24 -6
- package/codecs/runtime/pattern-json.mjs +80 -1
- package/codecs/runtime/prefix-codec.mjs +629 -67
- package/codecs/runtime/show-value.mjs +93 -51
- package/codecs/runtime/unicode-string.mjs +29 -6
- package/codecs/show.mjs +24 -6
- package/codecs/utf16.mjs +2 -1
- 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 +11 -3
- package/pkir.mjs +772 -0
- package/repl.mjs +92 -23
- package/scripts/build-repl-html.mjs +22 -3
- 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-codecs.mjs +168 -0
- package/tests/test-pkir.mjs +530 -0
- package/tests/test-polymorphic-tdd.mjs +196 -0
- package/tests/test-repl-html.mjs +16 -2
- package/tests/test-repl.mjs +63 -1
- package/backends/llvm/bin/k-llvm-jit.mjs +0 -160
|
@@ -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 {
|
|
@@ -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
|
});
|
|
@@ -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}`);
|