@fraczak/k 6.3.3 → 6.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/DOCS/CODECS.md +258 -0
  3. package/DOCS/DICTIONARY.md +1172 -0
  4. package/DOCS/KIR_SPECIALIZATION_DESIGN.md +51 -46
  5. package/DOCS/KIR_V1.md +221 -0
  6. package/DOCS/KVM_EXECUTION_MODEL.md +56 -19
  7. package/DOCS/OBJECT_FILE_AND_PATTERN.md +2 -1
  8. package/DOCS/PROFILING_AND_TRACING.md +196 -0
  9. package/DOCS/REPL.md +61 -4
  10. package/DOCS/WEB_REPL_REQUIREMENTS.md +135 -0
  11. package/DOCS/dependency-graph.md +144 -0
  12. package/Examples/arithmetics.k +108 -82
  13. package/Examples/bnat.k +1 -1
  14. package/Examples/buda.k +44 -0
  15. package/Examples/ieee.k +300 -8671
  16. package/Examples/poly.k +67 -0
  17. package/README.md +68 -19
  18. package/Value.mjs +8 -2
  19. package/augmentation.mjs +9 -7
  20. package/backend-api.mjs +11 -2
  21. package/backends/arm64/README.md +104 -0
  22. package/backends/arm64/bin/k-arm64-compile.mjs +101 -0
  23. package/backends/arm64/bin/k-arm64-run.mjs +58 -0
  24. package/backends/arm64/bin/k-arm64.mjs +88 -0
  25. package/backends/arm64/scripts/run-tests.mjs +41 -0
  26. package/backends/arm64/src/arm64.mjs +229 -0
  27. package/backends/arm64/src/cli.mjs +155 -0
  28. package/backends/arm64/src/kvm2arm64.mjs +906 -0
  29. package/backends/arm64/src/runtime.c +728 -0
  30. package/backends/arm64/tests/integration.sh +112 -0
  31. package/backends/arm64/tests/test-arm64.mjs +240 -0
  32. package/backends/llvm/README.md +135 -0
  33. package/backends/llvm/bin/k-llvm-build.mjs +71 -0
  34. package/backends/llvm/bin/k-llvm-compile.mjs +68 -0
  35. package/backends/llvm/bin/k-llvm-jit.mjs +160 -0
  36. package/backends/llvm/bin/k-llvm-run.mjs +90 -0
  37. package/backends/llvm/runtime/krt.c +1508 -0
  38. package/backends/llvm/runtime/krt.h +109 -0
  39. package/backends/llvm/scripts/conformance.mjs +76 -0
  40. package/backends/llvm/scripts/run-tests.mjs +28 -0
  41. package/backends/llvm/src/executable.mjs +562 -0
  42. package/backends/llvm/src/kvm2llvm.mjs +998 -0
  43. package/backends/llvm/src/llvm.mjs +1092 -0
  44. package/backends/llvm/tests/composition-driver.c +22 -0
  45. package/backends/llvm/tests/identity-driver.c +27 -0
  46. package/backends/llvm/tests/integration.sh +153 -0
  47. package/backends/llvm/tests/perf-support.mjs +735 -0
  48. package/backends/llvm/tests/product-driver.c +23 -0
  49. package/backends/llvm/tests/projection-driver.c +19 -0
  50. package/backends/llvm/tests/relation-driver.c +29 -0
  51. package/backends/llvm/tests/test-llvm.mjs +240 -0
  52. package/backends/llvm/tests/union-driver.c +31 -0
  53. package/backends/llvm/tests/variant-driver.c +19 -0
  54. package/backends/llvm/tests/variant-projection-driver.c +21 -0
  55. package/backends/wasm/DOCS/USE-WEB-ASSEMBLY.md +233 -0
  56. package/backends/wasm/README.md +97 -0
  57. package/backends/wasm/TECHNICAL-DEBT.md +58 -0
  58. package/backends/wasm/bin/k-wasm-compile.mjs +50 -0
  59. package/backends/wasm/bin/k-wasm-run.mjs +140 -0
  60. package/backends/wasm/bin/k-wasm.mjs +49 -0
  61. package/backends/wasm/demo_ieee.mjs +319 -0
  62. package/backends/wasm/runtime.wat +475 -0
  63. package/backends/wasm/scripts/run-tests.mjs +41 -0
  64. package/backends/wasm/src/cli.mjs +133 -0
  65. package/backends/wasm/src/kvm2wasm.mjs +697 -0
  66. package/backends/wasm/src/wasm.mjs +1054 -0
  67. package/backends/wasm/tests/integration.sh +182 -0
  68. package/backends/wasm/tests/perf-support.mjs +336 -0
  69. package/backends/wasm/tests/test-wasm.mjs +625 -0
  70. package/browser/repl-browser.mjs +1584 -0
  71. package/browser/shims/assert.mjs +19 -0
  72. package/browser/shims/buffer.mjs +224 -0
  73. package/browser/shims/crypto.mjs +103 -0
  74. package/browser/shims/fs.mjs +159 -0
  75. package/browser/shims/os.mjs +17 -0
  76. package/browser/shims/path.mjs +54 -0
  77. package/browser/shims/process.mjs +44 -0
  78. package/browser/shims/readline.mjs +11 -0
  79. package/browser/shims/url.mjs +12 -0
  80. package/browser/vfs-data.mjs +19 -0
  81. package/codecs/README.md +3 -0
  82. package/codecs/runtime/show-value.mjs +12 -3
  83. package/conformance/helper-reuse/case.json +8 -0
  84. package/conformance/helper-reuse/expected.kv +1 -0
  85. package/conformance/helper-reuse/input.kv +1 -0
  86. package/conformance/helper-reuse/program.k +2 -0
  87. package/conformance/identity/case.json +8 -0
  88. package/conformance/identity/expected.kv +1 -0
  89. package/conformance/identity/input.kv +1 -0
  90. package/conformance/identity/program.k +1 -0
  91. package/conformance/product-projection/case.json +8 -0
  92. package/conformance/product-projection/expected.kv +1 -0
  93. package/conformance/product-projection/input.kv +1 -0
  94. package/conformance/product-projection/program.k +1 -0
  95. package/conformance/run.mjs +149 -0
  96. package/conformance/variant-construction/case.json +8 -0
  97. package/conformance/variant-construction/expected.kv +1 -0
  98. package/conformance/variant-construction/input.kv +1 -0
  99. package/conformance/variant-construction/program.k +1 -0
  100. package/harness/adapters/arm64.mjs +105 -0
  101. package/harness/adapters/kvm.mjs +144 -0
  102. package/harness/adapters/llvm.mjs +118 -0
  103. package/harness/adapters/native.mjs +77 -0
  104. package/harness/adapters/wasm.mjs +169 -0
  105. package/harness/backend.mjs +95 -0
  106. package/harness/cli.mjs +130 -0
  107. package/harness/format.mjs +95 -0
  108. package/harness/index.mjs +25 -0
  109. package/harness/persistent.mjs +121 -0
  110. package/harness/registry.mjs +44 -0
  111. package/harness/suite.mjs +257 -0
  112. package/harness/suites/poly.mjs +156 -0
  113. package/harness/trace.mjs +50 -0
  114. package/harness/util.mjs +92 -0
  115. package/intrinsics.mjs +41 -0
  116. package/kir.mjs +399 -0
  117. package/kvm.mjs +585 -81
  118. package/objects/README.md +37 -3
  119. package/objects/compile.mjs +15 -22
  120. package/objects/inspect.mjs +96 -0
  121. package/objects/validate.mjs +415 -0
  122. package/package.json +51 -19
  123. package/repl-codecs.mjs +105 -6
  124. package/repl.mjs +335 -49
  125. package/run.mjs +2 -7
  126. package/scripts/benchmark.mjs +406 -22
  127. package/scripts/build-repl-html.mjs +1784 -0
  128. package/scripts/perf-ieee.mjs +586 -0
  129. package/scripts/perf-int.mjs +531 -0
  130. package/scripts/perf-poly.mjs +945 -0
  131. package/scripts/render-benchmark.mjs +12 -8
  132. package/scripts/run-tests.mjs +6 -0
  133. package/tests/integration.sh +19 -2
  134. package/tests/test-arithmetics.mjs +54 -0
  135. package/tests/test-ieee-arithmetic.mjs +4 -0
  136. package/tests/test-kir.mjs +85 -0
  137. package/tests/test-kvm-polymorphic.mjs +278 -0
  138. package/tests/test-kvm.mjs +25 -6
  139. package/tests/test-poly.mjs +129 -0
  140. package/tests/test-repl-html.mjs +303 -0
  141. package/tests/test-repl.mjs +144 -1
  142. package/tests/test-validate-object.mjs +40 -0
  143. package/a.klib +0 -1
  144. package/a.kvm +0 -142676
  145. package/a.wasm +0 -0
  146. package/benchmark-results.html +0 -532
  147. package/benchmark-results.json +0 -480
  148. package/k-vscode/.vscode/launch.json +0 -14
  149. package/k-vscode/README.md +0 -75
  150. package/k-vscode/extension.js +0 -273
  151. package/k-vscode/language-configuration.json +0 -42
  152. package/k-vscode/package.json +0 -79
  153. package/k-vscode/snippets/k.json +0 -92
  154. package/k-vscode/syntaxes/k.tmLanguage.json +0 -599
  155. package/k-vscode/test/background-ranges.test.js +0 -50
  156. package/k-vscode/themes/k-contrast-color-theme.json +0 -104
  157. package/scripts/git-hooks/pre-commit +0 -10
@@ -0,0 +1,97 @@
1
+ # k WebAssembly Backend
2
+
3
+ `@fraczak/k-wasm` is the experimental WebAssembly backend for
4
+ [`@fraczak/k`](https://github.com/fraczak/k). It lowers typed k programs through
5
+ the kVM representation, emits standard `.wasm` modules with WABT, and provides
6
+ a Node.js runner for the binary `pattern + value` streams used by the k codec
7
+ toolchain.
8
+
9
+ ## Install
10
+
11
+ Install dependencies from the monorepo root:
12
+
13
+ ```bash
14
+ npm install
15
+ ```
16
+
17
+ Optionally expose the three backend commands on your path:
18
+
19
+ ```bash
20
+ npm link
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ Compile an expression into a standalone WebAssembly artifact:
26
+
27
+ ```bash
28
+ node ./bin/k-wasm-compile.mjs '|ok' /tmp/ok.wasm
29
+ ```
30
+
31
+ Run it over the unit value and print the decoded result:
32
+
33
+ ```bash
34
+ node ../../codecs/unit.mjs --parse |
35
+ node ./bin/k-wasm-run.mjs /tmp/ok.wasm |
36
+ node ../../codecs/k-print.mjs
37
+ ```
38
+
39
+ Expected output:
40
+
41
+ ```json
42
+ "ok"
43
+ ```
44
+
45
+ With the backend and k codec commands on your path, the equivalent shorter
46
+ form is:
47
+
48
+ ```bash
49
+ k-wasm-compile '|ok' /tmp/ok.wasm
50
+ k-unit --parse | k-wasm-run /tmp/ok.wasm | k-print
51
+ ```
52
+
53
+ ## Commands
54
+
55
+ | Command | Purpose |
56
+ | --- | --- |
57
+ | `k-wasm` | Compile k source, `.ko`, or `.kvm` input in memory and run it immediately |
58
+ | `k-wasm-compile` | Compile k source, `.ko`, or `.kvm` input into a `.wasm` artifact |
59
+ | `k-wasm-run` | Run an existing `.wasm` artifact over a binary input stream |
60
+
61
+ All commands accept `--help`. The compile commands follow the `k-compile`
62
+ input convention: pass inline source, an existing source path, a `.ko` object,
63
+ or a `.kvm` program. They also accept one `--lib` option for a `.klib`
64
+ dependency and repeated `--export` options to bring library aliases into the
65
+ source scope. Existing paths are treated as files; non-existing names with
66
+ `.k`, `.ko`, `.kvm`, `.klib`, or `.wasm` extensions are treated as missing
67
+ files; other arguments are treated as inline source. The runners read a binary
68
+ input stream from standard input unless an input file is given.
69
+
70
+ ## Artifacts
71
+
72
+ The compiler produces a standard WebAssembly binary module containing the
73
+ reachable relations, the arena runtime, and a `k.metadata` custom section. The
74
+ metadata stores the entry point and the pattern information needed to encode
75
+ and decode values. A compiled artifact can be run later without its original k
76
+ source, object, kVM, or `.klib` files.
77
+
78
+ The current host runner targets Node.js. It is still needed to bridge between
79
+ WebAssembly linear memory and k binary streams.
80
+
81
+ ## Development
82
+
83
+ Run the test suite:
84
+
85
+ ```bash
86
+ npm test
87
+ ```
88
+
89
+ Run the comparative IEEE benchmark:
90
+
91
+ ```bash
92
+ npm run perf:ieee
93
+ ```
94
+
95
+ See [DOCS/USE-WEB-ASSEMBLY.md](DOCS/USE-WEB-ASSEMBLY.md) for the artifact
96
+ format, source-file and library examples, profiling options, and current
97
+ limitations.
@@ -0,0 +1,58 @@
1
+ # Technical Debt
2
+
3
+ ## Polymorphic Input Retyping for Precompiled Wasm
4
+
5
+ `k-wasm` can retype a polymorphic program when it compiles and runs in one step:
6
+ the CLI decodes the input stream first, intersects the program input pattern with
7
+ the input value envelope, and compiles a specialized WebAssembly module for that
8
+ run.
9
+
10
+ `k-wasm-run` cannot currently do the same for an already compiled `.wasm`
11
+ artifact. By the time the runner sees the input envelope, the k program has
12
+ already been lowered to WebAssembly and the artifact only carries metadata such
13
+ as the generic input/output patterns. The original source/object relation graph
14
+ needed to re-run type derivation is not available.
15
+
16
+ This means precompiled artifacts can execute polymorphic programs, but their
17
+ output envelopes are limited to the generic artifact metadata rather than being
18
+ retyped against each input envelope.
19
+
20
+ One possible fix is to delay compilation for programs with polymorphic input
21
+ until the input envelope is available. That could mean storing enough source,
22
+ object, or typed relation data in the artifact to specialize on first run, or
23
+ using a separate artifact form for deferred compilation.
24
+
25
+ ## Wasm Arena Memory Management
26
+
27
+ The WebAssembly backend currently uses a bump arena for all product and variant
28
+ values created during execution. This keeps allocation cheap and simple, and
29
+ failed union branches can roll the arena back to a checkpoint, but successful
30
+ paths do not reclaim temporary values until the whole run ends.
31
+
32
+ Tail-call lowering now avoids allocating replacement input products for some
33
+ self-tail-recursive loops by keeping top-level product fields in Wasm locals.
34
+ Furthermore, self-tail-recursive loops now incorporate threshold-based arena
35
+ compaction: when arena growth within a tail loop exceeds 1 MB, live accumulator
36
+ and argument graphs are compacted down to the loop entry mark using an iterative
37
+ staging-and-copy mechanism in `runtime.wat`, freeing dead scratch data while
38
+ preserving performance for hot short-lived loops.
39
+
40
+ Additionally, linear memory exhaustion and 32-bit unsigned offset overflow are
41
+ now tracked explicitly via exported flags (`oom_flag`, `oom_size`) in `runtime.wat`,
42
+ which the JS runtime intercepts to throw a descriptive `OutOfMemoryError` instead
43
+ of an untyped `unreachable` trap.
44
+
45
+ Remaining memory-management targets:
46
+
47
+ - Add allocation profiling that attributes arena growth to generated relations
48
+ and static allocation sites. Large regressions should be visible without
49
+ manually instrumenting `factorial:o` or similar workloads.
50
+ - Extend local-loop lowering beyond top-level product fields. Hot tail loops
51
+ should keep common accumulator state in locals where possible and materialize
52
+ arena values only at function boundaries or observable return points.
53
+ - Introduce safe lifetime boundaries for successful non-tail calls. The runtime
54
+ needs a way to reclaim scratch values after a callee result has been consumed
55
+ without copying large live values on every call.
56
+ - Keep unsigned pointer handling explicit. Wasm arena addresses are `i32`
57
+ offsets, and JavaScript sees exported `i32` values as signed numbers, so all
58
+ JS-side arena offsets must be normalized before `DataView` access.
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import { argv, exit, stdin, stdout } from "node:process";
5
+
6
+ import {
7
+ compileProgramInput,
8
+ parseCompileOptions,
9
+ resolveProgramInput
10
+ } from "../src/cli.mjs";
11
+
12
+ function usage(stream = console.error) {
13
+ const prog = argv[1] || "k-wasm-compile.mjs";
14
+ stream(`Usage: node ${prog} [options] [source-snippet | input-file [wasm-file]]`);
15
+ stream("Compile k source, .ko, or .kvm input into a standalone WebAssembly artifact.");
16
+ stream("");
17
+ stream("Arguments:");
18
+ stream(" source-snippet Inline k source, in the same style as k.mjs.");
19
+ stream(" input-file Source .k, .ko, or .kvm file. Reads UTF-8 source from stdin when omitted.");
20
+ stream(" wasm-file Output .wasm path. Writes the binary artifact to stdout when omitted.");
21
+ stream("");
22
+ stream("Options:");
23
+ stream(" --lib file Load one .klib dependency before compiling.");
24
+ stream(" --export spec Export a library alias into source scope. May be repeated.");
25
+ stream(" spec is 'name' or 'libname:localname'.");
26
+ stream(" -h, --help Show this help.");
27
+ }
28
+
29
+ try {
30
+ const args = argv.slice(2);
31
+ if (args.includes("-h") || args.includes("--help")) {
32
+ usage(console.log);
33
+ exit(0);
34
+ }
35
+
36
+ const { libraries, exportSpecs } = parseCompileOptions(args);
37
+ const input = resolveProgramInput(args, { allowStdinSource: true });
38
+ const outputPath = args.shift();
39
+ if (args.length > 0) throw new Error("Too many arguments");
40
+ const artifact = await compileProgramInput(input, { libraries, exportSpecs, stdin });
41
+ if (outputPath == null) {
42
+ stdout.write(artifact);
43
+ } else {
44
+ fs.writeFileSync(outputPath, artifact);
45
+ }
46
+ } catch (error) {
47
+ console.error(error.stack || error.message || String(error));
48
+ usage();
49
+ exit(1);
50
+ }
@@ -0,0 +1,140 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import { argv, exit, stdin, stdout, stderr } from "node:process";
5
+
6
+ import { instantiateWasmArtifact } from "../src/wasm.mjs";
7
+
8
+ function usage(stream = console.error) {
9
+ const prog = argv[1] || "k-wasm-run.mjs";
10
+ stream(`Usage: node ${prog} [ --server ] wasm-file [ input-file ]`);
11
+ stream("Run a standalone k WebAssembly artifact over a binary pattern+value stream.");
12
+ stream("");
13
+ stream("Arguments:");
14
+ stream(" wasm-file Input .wasm artifact produced by k-wasm-compile.");
15
+ stream(" input-file Optional binary input stream. Reads stdin when omitted.");
16
+ stream("");
17
+ stream("Options:");
18
+ stream(" --server Run as a persistent server reading framed requests from stdin.");
19
+ stream(" -h, --help Show this help.");
20
+ }
21
+
22
+ function readAll(stream) {
23
+ return new Promise((resolve, reject) => {
24
+ const chunks = [];
25
+ stream.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
26
+ stream.on("end", () => resolve(Buffer.concat(chunks)));
27
+ stream.on("error", reject);
28
+ });
29
+ }
30
+
31
+ async function runServer(runner) {
32
+ const tracing = process.env.K_TRACE === "1" || process.env.TRACE === "1";
33
+ let inBuffer = Buffer.alloc(0);
34
+ let readStartNs = 0n;
35
+
36
+ stdin.on("data", (chunk) => {
37
+ if (inBuffer.length === 0) {
38
+ readStartNs = process.hrtime.bigint();
39
+ }
40
+ inBuffer = Buffer.concat([inBuffer, chunk]);
41
+ processBuffer();
42
+ });
43
+
44
+ stdin.on("end", () => {
45
+ exit(0);
46
+ });
47
+
48
+ function processBuffer() {
49
+ while (inBuffer.length >= 4) {
50
+ const len = inBuffer.readUInt32BE(0);
51
+ if (inBuffer.length < 4 + len) {
52
+ break;
53
+ }
54
+ const t1 = process.hrtime.bigint();
55
+ const payload = inBuffer.subarray(4, 4 + len);
56
+ inBuffer = inBuffer.subarray(4 + len);
57
+
58
+ try {
59
+ let outWire;
60
+ let trace = null;
61
+ if (tracing) {
62
+ const res = runner.execute(payload, { trace: true });
63
+ outWire = res.outputWire;
64
+ trace = res.trace;
65
+ } else {
66
+ outWire = runner.execute(payload);
67
+ }
68
+
69
+ const writeStart = process.hrtime.bigint();
70
+ const outHdr = Buffer.allocUnsafe(4);
71
+ outHdr.writeUInt32BE(outWire.length, 0);
72
+ stdout.write(outHdr);
73
+ stdout.write(outWire);
74
+ const tEnd = process.hrtime.bigint();
75
+
76
+ if (tracing && trace) {
77
+ const ipcReadNs = readStartNs > 0n ? Number(t1 - readStartNs) : 0;
78
+ const decodeNs = trace.decodeNs;
79
+ const flatInNs = trace.flatInNs;
80
+ const evalNs = trace.evalNs;
81
+ const flatOutNs = trace.flatOutNs;
82
+ const encodeNs = trace.encodeNs;
83
+ const ipcWriteNs = Number(tEnd - writeStart);
84
+ const totalNs = Number(tEnd - (readStartNs > 0n ? readStartNs : t1));
85
+ stderr.write(`K_TRACE_PHASES backend=wasm ipc_read_ns=${ipcReadNs} decode_ns=${decodeNs} flat_in_ns=${flatInNs} eval_ns=${evalNs} flat_out_ns=${flatOutNs} encode_ns=${encodeNs} ipc_write_ns=${ipcWriteNs} total_ns=${totalNs}\n`);
86
+ }
87
+ } catch (err) {
88
+ stderr.write(`Wasm server error: ${err.stack || err.message || String(err)}\n`);
89
+ exit(1);
90
+ }
91
+
92
+ readStartNs = process.hrtime.bigint();
93
+ }
94
+ }
95
+ }
96
+
97
+ async function main() {
98
+ const rawArgs = argv.slice(2);
99
+ if (rawArgs.includes("-h") || rawArgs.includes("--help")) {
100
+ usage(console.log);
101
+ return;
102
+ }
103
+
104
+ const isServer = rawArgs.includes("--server");
105
+ const args = rawArgs.filter(a => a !== "--server");
106
+
107
+ const wasmPath = args.shift();
108
+ if (!wasmPath) throw new Error("Missing .wasm artifact path");
109
+
110
+ const artifact = fs.readFileSync(wasmPath);
111
+ const runner = await instantiateWasmArtifact(artifact);
112
+
113
+ if (isServer) {
114
+ if (args.length > 0) throw new Error("Too many arguments for --server mode");
115
+ await runServer(runner);
116
+ return;
117
+ }
118
+
119
+ const inputPath = args.shift();
120
+ if (args.length > 0) throw new Error("Too many arguments");
121
+
122
+ const input = await readAll(inputPath == null ? stdin : fs.createReadStream(inputPath));
123
+ const tracing = process.env.K_TRACE === "1" || process.env.TRACE === "1";
124
+ if (tracing) {
125
+ const res = runner.execute(input, { trace: true });
126
+ stdout.write(res.outputWire);
127
+ if (res.trace) {
128
+ const trace = res.trace;
129
+ stderr.write(`K_TRACE_PHASES backend=wasm ipc_read_ns=0 decode_ns=${trace.decodeNs} flat_in_ns=${trace.flatInNs} eval_ns=${trace.evalNs} flat_out_ns=${trace.flatOutNs} encode_ns=${trace.encodeNs} ipc_write_ns=0 total_ns=${trace.evalNs}\n`);
130
+ }
131
+ } else {
132
+ stdout.write(runner.execute(input));
133
+ }
134
+ }
135
+
136
+ main().catch((error) => {
137
+ console.error(error.stack || error.message || String(error));
138
+ usage();
139
+ exit(1);
140
+ });
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import { argv, exit, stdin, stdout } from "node:process";
5
+ import { decodeWire } from "@fraczak/k/backend-api.mjs";
6
+
7
+ import {
8
+ compileProgramInput,
9
+ parseCompileOptions,
10
+ readAll,
11
+ resolveProgramInput
12
+ } from "../src/cli.mjs";
13
+ import { runWasmArtifact } from "../src/wasm.mjs";
14
+
15
+ function usage(stream = console.error) {
16
+ const prog = argv[1] || "k-wasm.mjs";
17
+ stream(`Usage: node ${prog} [options] ( source-snippet | input-file ) [ input-file ]`);
18
+ stream("Compile k source, .ko, or .kvm input to WebAssembly in memory and run it over a binary pattern+value stream.");
19
+ stream("");
20
+ stream("Options:");
21
+ stream(" --lib file Load one .klib dependency before compiling.");
22
+ stream(" --export spec Export a library alias into source scope. May be repeated.");
23
+ stream(" spec is 'name' or 'libname:localname'.");
24
+ stream(" -h, --help Show this help.");
25
+ }
26
+
27
+ async function main() {
28
+ const args = argv.slice(2);
29
+ if (args.includes("-h") || args.includes("--help")) {
30
+ usage(console.log);
31
+ return;
32
+ }
33
+
34
+ const { libraries, exportSpecs } = parseCompileOptions(args);
35
+ const programInput = resolveProgramInput(args);
36
+ const inputPath = args.shift();
37
+ if (args.length > 0) throw new Error("Too many arguments");
38
+
39
+ const inputBuffer = await readAll(inputPath == null ? stdin : fs.createReadStream(inputPath));
40
+ const { pattern: inputEnvelopePattern } = decodeWire(inputBuffer);
41
+ const artifact = await compileProgramInput(programInput, { libraries, exportSpecs, inputEnvelopePattern });
42
+ stdout.write(await runWasmArtifact(artifact, inputBuffer));
43
+ }
44
+
45
+ main().catch((error) => {
46
+ console.error(error.stack || error.message || String(error));
47
+ usage();
48
+ exit(1);
49
+ });