@fraczak/k 6.3.3 → 6.4.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 (155) hide show
  1. package/DOCS/CODECS.md +258 -0
  2. package/DOCS/DICTIONARY.md +1172 -0
  3. package/DOCS/KIR_SPECIALIZATION_DESIGN.md +51 -46
  4. package/DOCS/KIR_V1.md +221 -0
  5. package/DOCS/KVM_EXECUTION_MODEL.md +56 -19
  6. package/DOCS/OBJECT_FILE_AND_PATTERN.md +2 -1
  7. package/DOCS/PROFILING_AND_TRACING.md +196 -0
  8. package/DOCS/REPL.md +61 -4
  9. package/DOCS/WEB_REPL_REQUIREMENTS.md +135 -0
  10. package/DOCS/dependency-graph.md +144 -0
  11. package/Examples/arithmetics.k +51 -48
  12. package/Examples/bnat.k +1 -1
  13. package/Examples/buda.k +44 -0
  14. package/Examples/ieee.k +300 -8671
  15. package/Examples/poly.k +67 -0
  16. package/README.md +68 -19
  17. package/augmentation.mjs +9 -7
  18. package/backend-api.mjs +11 -2
  19. package/backends/arm64/README.md +104 -0
  20. package/backends/arm64/bin/k-arm64-compile.mjs +101 -0
  21. package/backends/arm64/bin/k-arm64-run.mjs +58 -0
  22. package/backends/arm64/bin/k-arm64.mjs +88 -0
  23. package/backends/arm64/scripts/run-tests.mjs +41 -0
  24. package/backends/arm64/src/arm64.mjs +229 -0
  25. package/backends/arm64/src/cli.mjs +155 -0
  26. package/backends/arm64/src/kvm2arm64.mjs +906 -0
  27. package/backends/arm64/src/runtime.c +728 -0
  28. package/backends/arm64/tests/integration.sh +112 -0
  29. package/backends/arm64/tests/test-arm64.mjs +240 -0
  30. package/backends/llvm/README.md +135 -0
  31. package/backends/llvm/bin/k-llvm-build.mjs +71 -0
  32. package/backends/llvm/bin/k-llvm-compile.mjs +68 -0
  33. package/backends/llvm/bin/k-llvm-jit.mjs +160 -0
  34. package/backends/llvm/bin/k-llvm-run.mjs +90 -0
  35. package/backends/llvm/runtime/krt.c +1508 -0
  36. package/backends/llvm/runtime/krt.h +109 -0
  37. package/backends/llvm/scripts/conformance.mjs +76 -0
  38. package/backends/llvm/scripts/run-tests.mjs +28 -0
  39. package/backends/llvm/src/executable.mjs +562 -0
  40. package/backends/llvm/src/kvm2llvm.mjs +998 -0
  41. package/backends/llvm/src/llvm.mjs +1092 -0
  42. package/backends/llvm/tests/composition-driver.c +22 -0
  43. package/backends/llvm/tests/identity-driver.c +27 -0
  44. package/backends/llvm/tests/integration.sh +153 -0
  45. package/backends/llvm/tests/perf-support.mjs +735 -0
  46. package/backends/llvm/tests/product-driver.c +23 -0
  47. package/backends/llvm/tests/projection-driver.c +19 -0
  48. package/backends/llvm/tests/relation-driver.c +29 -0
  49. package/backends/llvm/tests/test-llvm.mjs +240 -0
  50. package/backends/llvm/tests/union-driver.c +31 -0
  51. package/backends/llvm/tests/variant-driver.c +19 -0
  52. package/backends/llvm/tests/variant-projection-driver.c +21 -0
  53. package/backends/wasm/DOCS/USE-WEB-ASSEMBLY.md +233 -0
  54. package/backends/wasm/README.md +97 -0
  55. package/backends/wasm/TECHNICAL-DEBT.md +60 -0
  56. package/backends/wasm/bin/k-wasm-compile.mjs +50 -0
  57. package/backends/wasm/bin/k-wasm-run.mjs +140 -0
  58. package/backends/wasm/bin/k-wasm.mjs +49 -0
  59. package/backends/wasm/demo_ieee.mjs +319 -0
  60. package/backends/wasm/runtime.wat +102 -0
  61. package/backends/wasm/scripts/run-tests.mjs +41 -0
  62. package/backends/wasm/src/cli.mjs +133 -0
  63. package/backends/wasm/src/kvm2wasm.mjs +661 -0
  64. package/backends/wasm/src/wasm.mjs +1010 -0
  65. package/backends/wasm/tests/integration.sh +182 -0
  66. package/backends/wasm/tests/perf-support.mjs +336 -0
  67. package/backends/wasm/tests/test-wasm.mjs +617 -0
  68. package/browser/repl-browser.mjs +1584 -0
  69. package/browser/shims/assert.mjs +19 -0
  70. package/browser/shims/buffer.mjs +224 -0
  71. package/browser/shims/crypto.mjs +103 -0
  72. package/browser/shims/fs.mjs +159 -0
  73. package/browser/shims/os.mjs +17 -0
  74. package/browser/shims/path.mjs +54 -0
  75. package/browser/shims/process.mjs +44 -0
  76. package/browser/shims/readline.mjs +11 -0
  77. package/browser/shims/url.mjs +12 -0
  78. package/browser/vfs-data.mjs +19 -0
  79. package/codecs/README.md +3 -0
  80. package/codecs/runtime/show-value.mjs +2 -2
  81. package/conformance/helper-reuse/case.json +8 -0
  82. package/conformance/helper-reuse/expected.kv +1 -0
  83. package/conformance/helper-reuse/input.kv +1 -0
  84. package/conformance/helper-reuse/program.k +2 -0
  85. package/conformance/identity/case.json +8 -0
  86. package/conformance/identity/expected.kv +1 -0
  87. package/conformance/identity/input.kv +1 -0
  88. package/conformance/identity/program.k +1 -0
  89. package/conformance/product-projection/case.json +8 -0
  90. package/conformance/product-projection/expected.kv +1 -0
  91. package/conformance/product-projection/input.kv +1 -0
  92. package/conformance/product-projection/program.k +1 -0
  93. package/conformance/run.mjs +149 -0
  94. package/conformance/variant-construction/case.json +8 -0
  95. package/conformance/variant-construction/expected.kv +1 -0
  96. package/conformance/variant-construction/input.kv +1 -0
  97. package/conformance/variant-construction/program.k +1 -0
  98. package/harness/adapters/arm64.mjs +105 -0
  99. package/harness/adapters/kvm.mjs +144 -0
  100. package/harness/adapters/llvm.mjs +118 -0
  101. package/harness/adapters/native.mjs +77 -0
  102. package/harness/adapters/wasm.mjs +169 -0
  103. package/harness/backend.mjs +95 -0
  104. package/harness/cli.mjs +130 -0
  105. package/harness/format.mjs +95 -0
  106. package/harness/index.mjs +25 -0
  107. package/harness/persistent.mjs +121 -0
  108. package/harness/registry.mjs +44 -0
  109. package/harness/suite.mjs +257 -0
  110. package/harness/suites/poly.mjs +156 -0
  111. package/harness/trace.mjs +50 -0
  112. package/harness/util.mjs +92 -0
  113. package/intrinsics.mjs +41 -0
  114. package/kir.mjs +399 -0
  115. package/kvm.mjs +585 -81
  116. package/objects/README.md +37 -3
  117. package/objects/compile.mjs +15 -22
  118. package/objects/inspect.mjs +96 -0
  119. package/objects/validate.mjs +415 -0
  120. package/package.json +51 -19
  121. package/repl-codecs.mjs +105 -6
  122. package/repl.mjs +335 -49
  123. package/run.mjs +2 -7
  124. package/scripts/benchmark.mjs +406 -22
  125. package/scripts/build-repl-html.mjs +1784 -0
  126. package/scripts/perf-ieee.mjs +586 -0
  127. package/scripts/perf-int.mjs +531 -0
  128. package/scripts/perf-poly.mjs +945 -0
  129. package/scripts/render-benchmark.mjs +12 -8
  130. package/scripts/run-tests.mjs +6 -0
  131. package/tests/integration.sh +19 -2
  132. package/tests/test-arithmetics.mjs +54 -0
  133. package/tests/test-ieee-arithmetic.mjs +4 -0
  134. package/tests/test-kir.mjs +85 -0
  135. package/tests/test-kvm-polymorphic.mjs +278 -0
  136. package/tests/test-kvm.mjs +25 -6
  137. package/tests/test-poly.mjs +129 -0
  138. package/tests/test-repl-html.mjs +303 -0
  139. package/tests/test-repl.mjs +144 -1
  140. package/tests/test-validate-object.mjs +40 -0
  141. package/a.klib +0 -1
  142. package/a.kvm +0 -142676
  143. package/a.wasm +0 -0
  144. package/benchmark-results.html +0 -532
  145. package/benchmark-results.json +0 -480
  146. package/k-vscode/.vscode/launch.json +0 -14
  147. package/k-vscode/README.md +0 -75
  148. package/k-vscode/extension.js +0 -273
  149. package/k-vscode/language-configuration.json +0 -42
  150. package/k-vscode/package.json +0 -79
  151. package/k-vscode/snippets/k.json +0 -92
  152. package/k-vscode/syntaxes/k.tmLanguage.json +0 -599
  153. package/k-vscode/test/background-ranges.test.js +0 -50
  154. package/k-vscode/themes/k-contrast-color-theme.json +0 -104
  155. 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,60 @@
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
+ That improves arithmetic workloads such as `factorial:o`, but it is still only
35
+ a first step. Large runs still allocate far more arena memory than the final
36
+ result requires because intermediate relation results, accumulator fragments,
37
+ and temporary products remain in the bump arena.
38
+
39
+ Future memory-management targets:
40
+
41
+ - Add allocation profiling that attributes arena growth to generated relations
42
+ and static allocation sites. Large regressions should be visible without
43
+ manually instrumenting `factorial:o` or similar workloads.
44
+ - Extend local-loop lowering beyond top-level product fields. Hot tail loops
45
+ should keep common accumulator state in locals where possible and materialize
46
+ arena values only at function boundaries or observable return points.
47
+ - Introduce safe lifetime boundaries for successful non-tail calls. The runtime
48
+ needs a way to reclaim scratch values after a callee result has been consumed
49
+ without copying large live values on every call.
50
+ - Make arena checkpoints part of code generation decisions, not just union
51
+ failure handling. Tail loops should be able to reset dead scratch space while
52
+ preserving the next live input/result.
53
+ - Keep unsigned pointer handling explicit. Wasm arena addresses are `i32`
54
+ offsets, and JavaScript sees exported `i32` values as signed numbers, so all
55
+ JS-side arena offsets must be normalized before `DataView` access.
56
+
57
+ The preferred direction is performance first: reduce allocation volume in hot
58
+ generated loops before adding a general garbage collector or compaction pass.
59
+ Copying live arena values can control memory, but it risks slowing exactly the
60
+ large recursive arithmetic workloads that motivated tail-call lowering.
@@ -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
+ });