@fraczak/k 6.3.2 → 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 (156) 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 +76 -14
  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/json.mjs +16 -2
  81. package/codecs/runtime/show-value.mjs +2 -2
  82. package/conformance/helper-reuse/case.json +8 -0
  83. package/conformance/helper-reuse/expected.kv +1 -0
  84. package/conformance/helper-reuse/input.kv +1 -0
  85. package/conformance/helper-reuse/program.k +2 -0
  86. package/conformance/identity/case.json +8 -0
  87. package/conformance/identity/expected.kv +1 -0
  88. package/conformance/identity/input.kv +1 -0
  89. package/conformance/identity/program.k +1 -0
  90. package/conformance/product-projection/case.json +8 -0
  91. package/conformance/product-projection/expected.kv +1 -0
  92. package/conformance/product-projection/input.kv +1 -0
  93. package/conformance/product-projection/program.k +1 -0
  94. package/conformance/run.mjs +149 -0
  95. package/conformance/variant-construction/case.json +8 -0
  96. package/conformance/variant-construction/expected.kv +1 -0
  97. package/conformance/variant-construction/input.kv +1 -0
  98. package/conformance/variant-construction/program.k +1 -0
  99. package/harness/adapters/arm64.mjs +105 -0
  100. package/harness/adapters/kvm.mjs +144 -0
  101. package/harness/adapters/llvm.mjs +118 -0
  102. package/harness/adapters/native.mjs +77 -0
  103. package/harness/adapters/wasm.mjs +169 -0
  104. package/harness/backend.mjs +95 -0
  105. package/harness/cli.mjs +130 -0
  106. package/harness/format.mjs +95 -0
  107. package/harness/index.mjs +25 -0
  108. package/harness/persistent.mjs +121 -0
  109. package/harness/registry.mjs +44 -0
  110. package/harness/suite.mjs +257 -0
  111. package/harness/suites/poly.mjs +156 -0
  112. package/harness/trace.mjs +50 -0
  113. package/harness/util.mjs +92 -0
  114. package/intrinsics.mjs +41 -0
  115. package/kir.mjs +399 -0
  116. package/kvm.mjs +585 -81
  117. package/objects/README.md +37 -3
  118. package/objects/compile.mjs +15 -22
  119. package/objects/inspect.mjs +96 -0
  120. package/objects/validate.mjs +415 -0
  121. package/package.json +51 -19
  122. package/repl-codecs.mjs +133 -20
  123. package/repl.mjs +408 -59
  124. package/run.mjs +2 -7
  125. package/scripts/benchmark.mjs +406 -22
  126. package/scripts/build-repl-html.mjs +1784 -0
  127. package/scripts/perf-ieee.mjs +586 -0
  128. package/scripts/perf-int.mjs +531 -0
  129. package/scripts/perf-poly.mjs +945 -0
  130. package/scripts/render-benchmark.mjs +12 -8
  131. package/scripts/run-tests.mjs +6 -0
  132. package/tests/integration.sh +19 -2
  133. package/tests/test-arithmetics.mjs +54 -0
  134. package/tests/test-ieee-arithmetic.mjs +6 -2
  135. package/tests/test-kir.mjs +85 -0
  136. package/tests/test-kvm-polymorphic.mjs +278 -0
  137. package/tests/test-kvm.mjs +25 -6
  138. package/tests/test-poly.mjs +129 -0
  139. package/tests/test-repl-html.mjs +303 -0
  140. package/tests/test-repl.mjs +175 -1
  141. package/tests/test-validate-object.mjs +40 -0
  142. package/a.klib +0 -1
  143. package/a.kvm +0 -142676
  144. package/a.wasm +0 -0
  145. package/benchmark-results.html +0 -532
  146. package/benchmark-results.json +0 -480
  147. package/k-vscode/.vscode/launch.json +0 -14
  148. package/k-vscode/README.md +0 -75
  149. package/k-vscode/extension.js +0 -273
  150. package/k-vscode/language-configuration.json +0 -42
  151. package/k-vscode/package.json +0 -79
  152. package/k-vscode/snippets/k.json +0 -92
  153. package/k-vscode/syntaxes/k.tmLanguage.json +0 -599
  154. package/k-vscode/test/background-ranges.test.js +0 -50
  155. package/k-vscode/themes/k-contrast-color-theme.json +0 -104
  156. package/scripts/git-hooks/pre-commit +0 -10
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ K_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
6
+ TMP_DIR=$(mktemp -d)
7
+ trap 'rm -rf "$TMP_DIR"' EXIT
8
+
9
+ echo "Running './backends/arm64/tests/integration.sh' ..."
10
+
11
+ compare_json_envelope() {
12
+ local name=$1
13
+ local input=$2
14
+ local program=$3
15
+ printf '%s\n' "$input" |
16
+ node "$K_ROOT/codecs/json.mjs" --parse |
17
+ node "$K_ROOT/k.mjs" "$program" > "$TMP_DIR/native.kv"
18
+ printf '%s\n' "$input" |
19
+ node "$K_ROOT/codecs/json.mjs" --parse |
20
+ node "$K_ROOT/kvm.mjs" "$program" > "$TMP_DIR/kvm.kv"
21
+ printf '%s\n' "$input" |
22
+ node "$K_ROOT/codecs/json.mjs" --parse |
23
+ node "$K_ROOT/backends/arm64/bin/k-arm64.mjs" "$program" > "$TMP_DIR/arm64.kv"
24
+
25
+ if ! cmp -s "$TMP_DIR/native.kv" "$TMP_DIR/kvm.kv" ||
26
+ ! cmp -s "$TMP_DIR/native.kv" "$TMP_DIR/arm64.kv"; then
27
+ echo "output envelope mismatch for $name" >&2
28
+ exit 1
29
+ fi
30
+ }
31
+
32
+ echo "Testing basic tag injection..."
33
+ node "$K_ROOT/codecs/unit.mjs" --parse |
34
+ node "$K_ROOT/backends/arm64/bin/k-arm64.mjs" '|ok' |
35
+ node "$K_ROOT/codecs/k-print.mjs" |
36
+ grep -qx '"ok"'
37
+
38
+ echo "Testing record wrapping..."
39
+ printf '{"a": {}, "b": {}}\n' |
40
+ node "$K_ROOT/codecs/k-parse.mjs" |
41
+ node "$K_ROOT/backends/arm64/bin/k-arm64.mjs" '|ok' |
42
+ node "$K_ROOT/codecs/k-print.mjs" |
43
+ grep -qx '{"ok":{"a":{},"b":{}}}'
44
+
45
+ echo "Testing field projection with JSON codec..."
46
+ printf '{"a":123,"b":true,"c":[1,2,"alsk"]}\n' |
47
+ node "$K_ROOT/codecs/json.mjs" --parse |
48
+ node "$K_ROOT/backends/arm64/bin/k-arm64.mjs" '.c' |
49
+ node "$K_ROOT/codecs/json.mjs" --print |
50
+ grep -qx '\[1,2,"alsk"\]'
51
+
52
+ echo "Testing nested array projection..."
53
+ compare_json_envelope "nested array string projection" \
54
+ '{"a":[1,2,"kupa"], "b": 123}' \
55
+ '.a.2'
56
+
57
+ echo "Testing JSON number projection..."
58
+ compare_json_envelope "projected JSON number" \
59
+ '{"a":[1,2,"kupa"], "b": 123}' \
60
+ '.b'
61
+
62
+ echo "Testing closed product filter..."
63
+ compare_json_envelope "closed product filter" \
64
+ '{"a":[1,2,"kupa"], "b": 123}' \
65
+ '?{X a, Y b}'
66
+
67
+ echo "Testing record construction..."
68
+ printf '{"a":[1,2,"kupa"], "b": 123}\n' |
69
+ node "$K_ROOT/codecs/json.mjs" --parse |
70
+ node "$K_ROOT/backends/arm64/bin/k-arm64.mjs" '{ .a.2 word, .b number }' |
71
+ node "$K_ROOT/codecs/json.mjs" --print |
72
+ grep -qx '{"number":123,"word":"kupa"}'
73
+
74
+ echo "Testing standalone executable compilation and execution..."
75
+ node "$K_ROOT/backends/arm64/bin/k-arm64-compile.mjs" -o "$TMP_DIR/dot-c" '.c'
76
+ printf '{"a":123,"b":true,"c":[1,2,"alsk"]}\n' |
77
+ node "$K_ROOT/codecs/json.mjs" --parse |
78
+ node "$K_ROOT/backends/arm64/bin/k-arm64-run.mjs" "$TMP_DIR/dot-c" |
79
+ node "$K_ROOT/codecs/json.mjs" --print |
80
+ grep -qx '\[1,2,"alsk"\]'
81
+
82
+ echo "Testing direct execution of compiled executable with --json..."
83
+ printf '{"a":123,"b":true,"c":[1,2,"alsk"]}\n' |
84
+ node "$K_ROOT/codecs/json.mjs" --parse |
85
+ "$TMP_DIR/dot-c" --json |
86
+ grep -q 'exponent'
87
+
88
+ echo "Testing compilation from .ko object..."
89
+ node "$K_ROOT/objects/compile.mjs" '.c' "$TMP_DIR/dot-c.ko"
90
+ printf '{"a":123,"b":true,"c":[1,2,"alsk"]}\n' |
91
+ node "$K_ROOT/codecs/json.mjs" --parse |
92
+ node "$K_ROOT/backends/arm64/bin/k-arm64.mjs" "$TMP_DIR/dot-c.ko" |
93
+ node "$K_ROOT/codecs/json.mjs" --print |
94
+ grep -qx '\[1,2,"alsk"\]'
95
+
96
+ echo "Testing compilation to assembly (-S)..."
97
+ node "$K_ROOT/backends/arm64/bin/k-arm64-compile.mjs" -S '.c' "$TMP_DIR/dot-c.s"
98
+ test -s "$TMP_DIR/dot-c.s"
99
+ grep -q "rel___main__" "$TMP_DIR/dot-c.s"
100
+
101
+ echo "Testing library dependencies (--lib and --export)..."
102
+ node "$K_ROOT/backends/arm64/bin/k-arm64-compile.mjs" \
103
+ --lib "$K_ROOT/Examples/arithmetics.k" \
104
+ --export plus:+ --export succ --export int \
105
+ '{succ int x,int y}+' \
106
+ -o "$TMP_DIR/lib-add"
107
+
108
+ node "$K_ROOT/codecs/k-parse.mjs" <<< '{"x":{"succ":"zero"},"y":{"succ":{"succ":"zero"}}}' |
109
+ "$TMP_DIR/lib-add" --json |
110
+ grep -Fxq '{"+":{"1":"_"}}'
111
+
112
+ echo "==> ARM64 Integration Tests Completed Successfully!"
@@ -0,0 +1,240 @@
1
+ import assert from "node:assert/strict";
2
+ import fs from "node:fs";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { execFileSync, execSync } from "node:child_process";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ import {
9
+ compileARM64Artifact,
10
+ compileARM64ArtifactFromKVM,
11
+ compileARM64ArtifactFromObject,
12
+ runARM64Artifact
13
+ } from "../src/arm64.mjs";
14
+ import {
15
+ compileKVMModuleToARM64,
16
+ emitMetadataC,
17
+ getTagEntries,
18
+ resetTagIds
19
+ } from "../src/kvm2arm64.mjs";
20
+ import { compileObjectBuffer, decodeObject } from "../../../object.mjs";
21
+ import { objectToKVMArtifact } from "../../../kvm.mjs";
22
+
23
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
24
+ const ROOT = path.resolve(__dirname, "../../..");
25
+
26
+ console.log("==> Running ARM64 Backend Test Suite");
27
+
28
+ // Helper to convert JSON value to wire buffer via codecs/k-parse.mjs
29
+ function jsonToWire(jsonObj) {
30
+ const jsonStr = typeof jsonObj === "string" ? jsonObj : JSON.stringify(jsonObj);
31
+ return execFileSync("node", [path.join(ROOT, "codecs/k-parse.mjs")], {
32
+ input: jsonStr
33
+ });
34
+ }
35
+
36
+ // Helper to convert wire buffer to JSON value via codecs/k-print.mjs
37
+ function wireToJSON(wireBuf) {
38
+ const outputStr = execFileSync("node", [path.join(ROOT, "codecs/k-print.mjs")], {
39
+ input: wireBuf,
40
+ encoding: "utf8"
41
+ });
42
+ return JSON.parse(outputStr.trim());
43
+ }
44
+
45
+ // 1. Identity / Unit Relation
46
+ console.log("==> Test 1: Identity / Unit Relation");
47
+ {
48
+ const source = `()`;
49
+ const artifact = compileARM64Artifact(source);
50
+ const inputWire = jsonToWire({});
51
+ const outWire = runARM64Artifact(artifact, inputWire);
52
+ const outJSON = wireToJSON(outWire);
53
+ assert.deepEqual(outJSON, {}, "Unit relation must return empty object {}");
54
+
55
+ // Test --json mode
56
+ const outJsonStr = runARM64Artifact(artifact, inputWire, { json: true });
57
+ assert.equal(outJsonStr.trim(), "{}", "--json mode must return {}");
58
+ console.log(" Passed!");
59
+ }
60
+
61
+ // 2. Boolean Negation (Variant Projection & Creation)
62
+ console.log("==> Test 2: Boolean Negation (Variants)");
63
+ {
64
+ const source = `
65
+ true = {} | true;
66
+ false = {} | false;
67
+ neg = < /true false, /false true >;
68
+ neg
69
+ `;
70
+ const artifact = compileARM64Artifact(source);
71
+
72
+ // Test neg(true) -> false
73
+ const trueWire = jsonToWire({ true: {} });
74
+ const falseWireOut = runARM64Artifact(artifact, trueWire);
75
+ assert.deepEqual(wireToJSON(falseWireOut), "false");
76
+
77
+ // Test neg(false) -> true
78
+ const falseWire = jsonToWire({ false: {} });
79
+ const trueWireOut = runARM64Artifact(artifact, falseWire);
80
+ assert.deepEqual(wireToJSON(trueWireOut), "true");
81
+
82
+ // Test --json mode
83
+ const jsonOut = runARM64Artifact(artifact, trueWire, { json: true });
84
+ assert.equal(jsonOut.trim(), '"false"');
85
+ console.log(" Passed!");
86
+ }
87
+
88
+ // 3. Product Projection and Field Swapping
89
+ console.log("==> Test 3: Product Projection and Record Construction");
90
+ {
91
+ const source = `
92
+ swap = { .y x, .x y };
93
+ swap
94
+ `;
95
+ const artifact = compileARM64Artifact(source);
96
+ const inWire = jsonToWire({ x: "a", y: "b" });
97
+ const outWire = runARM64Artifact(artifact, inWire);
98
+ assert.deepEqual(wireToJSON(outWire), { x: "b", y: "a" });
99
+ console.log(" Passed!");
100
+ }
101
+
102
+ // 4. Multi-branch Union with Backtracking
103
+ console.log("==> Test 4: Multi-branch Union with Backtracking");
104
+ {
105
+ const source = `
106
+ $ t = < {} a, {} b, {} c >;
107
+ classify = <
108
+ /a ({} | first),
109
+ /b ({} | second),
110
+ /c ({} | third)
111
+ >;
112
+ classify
113
+ `;
114
+ const artifact = compileARM64Artifact(source);
115
+
116
+ assert.deepEqual(wireToJSON(runARM64Artifact(artifact, jsonToWire({ a: {} }))), "first");
117
+ assert.deepEqual(wireToJSON(runARM64Artifact(artifact, jsonToWire({ b: {} }))), "second");
118
+ assert.deepEqual(wireToJSON(runARM64Artifact(artifact, jsonToWire({ c: {} }))), "third");
119
+ console.log(" Passed!");
120
+ }
121
+
122
+ // 5. Peano Addition with Tail-Call Optimization
123
+ console.log("==> Test 5: Peano Addition with Tail Recursion Optimization");
124
+ {
125
+ const source = `
126
+ $ nat = < {} 0, nat +1 >;
127
+ 0 = {} | 0 $ nat;
128
+ inc = | +1 $ nat;
129
+ dec = $ nat / +1;
130
+ add = $ { nat x, nat y } <
131
+ { . x dec x, . y inc y } add,
132
+ . y
133
+ >;
134
+ add
135
+ `;
136
+ const artifact = compileARM64Artifact(source);
137
+
138
+ // 3 + 2 = 5
139
+ const n0 = "0";
140
+ const n1 = { "+1": n0 };
141
+ const n2 = { "+1": n1 };
142
+ const n3 = { "+1": n2 };
143
+ const n5 = { "+1": { "+1": n3 } };
144
+
145
+ const inWire = jsonToWire({ x: n3, y: n2 });
146
+ const outWire = runARM64Artifact(artifact, inWire);
147
+ assert.deepEqual(wireToJSON(outWire), n5);
148
+
149
+ // Test 0 + 2 = 2
150
+ const inWireZero = jsonToWire({ x: n0, y: n2 });
151
+ const outWireZero = runARM64Artifact(artifact, inWireZero);
152
+ assert.deepEqual(wireToJSON(outWireZero), n2);
153
+ console.log(" Passed!");
154
+ }
155
+
156
+ // 6. Deep Tail Recursion (testing stack safety with loop)
157
+ console.log("==> Test 6: Deep Tail Recursion Loop");
158
+ {
159
+ const source = `
160
+ $ nat = < {} 0, nat +1 >;
161
+ 0 = {} | 0 $ nat;
162
+ inc = | +1 $ nat;
163
+ dec = $ nat / +1;
164
+ add = $ { nat x, nat y } <
165
+ { . x dec x, . y inc y } add,
166
+ . y
167
+ >;
168
+ add
169
+ `;
170
+ const artifact = compileARM64Artifact(source);
171
+
172
+ // Compute 50 + 1 = 51
173
+ let cur = "0";
174
+ for (let i = 0; i < 50; i++) cur = { "+1": cur };
175
+ const one = { "+1": "0" };
176
+
177
+ const inWire = jsonToWire({ x: cur, y: one });
178
+ const outWire = runARM64Artifact(artifact, inWire);
179
+ const outJSON = wireToJSON(outWire);
180
+
181
+ // Count the +1 depth
182
+ let count = 0;
183
+ let p = outJSON;
184
+ while (p && typeof p === "object" && "+1" in p) {
185
+ count++;
186
+ p = p["+1"];
187
+ }
188
+ assert.equal(count, 51, "50 + 1 must yield depth 51");
189
+ console.log(" Passed!");
190
+ }
191
+
192
+ // 7. Compilation to Assembly Text (-S)
193
+ console.log("==> Test 7: Assembly Text Generation");
194
+ {
195
+ const source = `true = {} | true; true`;
196
+ const { assembly, entryName } = compileARM64Artifact(source, { emit: "assembly" });
197
+ assert.ok(typeof assembly === "string", "Assembly output must be a string");
198
+ assert.ok(assembly.includes(".arch armv8-a"), "Assembly must target armv8-a");
199
+ assert.ok(assembly.includes(`.global ${entryName}`), "Assembly must export entry symbol");
200
+ assert.ok(assembly.includes("ret"), "Assembly must contain return instructions");
201
+ console.log(" Passed!");
202
+ }
203
+
204
+ // 8. Compilation from .kvm Artifact
205
+ console.log("==> Test 8: Compilation from .kvm Artifact");
206
+ {
207
+ const script = `
208
+ $ bool = < {} true, {} false >;
209
+ not = $ bool < /true ({} | false), /false ({} | true) >;
210
+ not
211
+ `;
212
+ const obj = decodeObject(compileObjectBuffer(script));
213
+ const kvm = objectToKVMArtifact(obj);
214
+
215
+ const artifact = compileARM64ArtifactFromKVM(kvm);
216
+ const inWire = jsonToWire({ true: {} });
217
+ const outWire = runARM64Artifact(artifact, inWire);
218
+ assert.deepEqual(wireToJSON(outWire), "false");
219
+ console.log(" Passed!");
220
+ }
221
+
222
+ // 9. Failure Case (Partial Relation Non-Match)
223
+ console.log("==> Test 9: Failure Case (Relation Rejection)");
224
+ {
225
+ const source = `
226
+ onlyA = /a ({} | success);
227
+ onlyA
228
+ `;
229
+ const artifact = compileARM64Artifact(source);
230
+ const inWireFail = jsonToWire({ b: {} });
231
+
232
+ assert.throws(
233
+ () => runARM64Artifact(artifact, inWireFail),
234
+ /failed with exit status 1/,
235
+ "Executable must exit with status 1 on partial relation failure"
236
+ );
237
+ console.log(" Passed!");
238
+ }
239
+
240
+ console.log("==> All ARM64 Backend Unit Tests Passed Successfully!");
@@ -0,0 +1,135 @@
1
+ # k-llvm
2
+
3
+ Experimental LLVM backend prototype for `k`.
4
+
5
+ This package lives under the `k` monorepo as `backends/llvm`. It consumes the
6
+ backend bridge from the root `@fraczak/k` package and starts from compiled
7
+ `.ko` objects:
8
+
9
+ ```text
10
+ .k source -> .ko -> envelope-specialized KIR-P -> LLVM IR prototype
11
+ ```
12
+
13
+ The first milestone is not performance. It is a stable backend pipeline that
14
+ can load an object, specialize it through KIR-P, and produce an inspectable
15
+ LLVM module.
16
+
17
+ ## Quick Start
18
+
19
+ From the monorepo root, install the workspace dependencies, then run the
20
+ backend from `backends/llvm`:
21
+
22
+ ```sh
23
+ npm install
24
+ cd backends/llvm
25
+ node ../../objects/compile.mjs '()' /tmp/id.ko
26
+ node ./bin/k-llvm-compile.mjs --input-pattern '[["open-product",[]]]' /tmp/id.ko /tmp/id.ll
27
+ ```
28
+
29
+ The generated `.ll` embeds the envelope-specialized KIR-P contract as module
30
+ data and exposes the first runtime ABI slice:
31
+
32
+ ```llvm
33
+ %k_result = type { i32, ptr }
34
+
35
+ define %k_result @k_main(ptr %rt, ptr %input)
36
+ ```
37
+
38
+ `%rt` is an opaque runtime handle and `%input` is an opaque boxed `k_value*`.
39
+ The first executable lowerings support identity, typed filters and singleton
40
+ code filters, product field projection, product construction, variant
41
+ construction, and variant projection. Unsupported operations return a nonzero
42
+ status in `k_result`. These operations can compose through KIR `comp`.
43
+
44
+ ## CLI
45
+
46
+ ```sh
47
+ k-llvm-build [options] object.ko output-exe
48
+ k-llvm-compile [options] object.ko [output.ll]
49
+ k-llvm-jit [options] object.ko
50
+ k-llvm-run [options] object.ko [input.kv]
51
+ ```
52
+
53
+ Options:
54
+
55
+ - `--retype rel`: current option spelling for the relation to
56
+ envelope-specialize; defaults to the object's `main`.
57
+ - `--input-pattern json-or-file`: KIR property-list input pattern; required
58
+ for `k-llvm-build`.
59
+ - `--expect value-or-file`: for `k-llvm-run`, compare the output value against
60
+ expected value text.
61
+ - `-h`, `--help`: show usage.
62
+
63
+ Only `.ko` / `.klib` object input is supported in this first prototype.
64
+ Source compilation remains owned by core `k`.
65
+ Without `--expect`, `k-llvm-run` prints the result value as compact JSON.
66
+ `k-llvm-build` emits a native executable that reads and writes the binary
67
+ k pattern+value envelope used by `codecs/k-parse.mjs` and `codecs/k-print.mjs`.
68
+ The executable checks the stdin envelope pattern against the compiled input
69
+ pattern and encodes stdout with the compiled output pattern.
70
+ `k-llvm-jit` reads the stdin binary envelope first, specializes the object with
71
+ that input pattern, caches the native executable, and writes the compiled
72
+ output envelope to stdout.
73
+ The native envelope codec supports the k Unicode string encoding used for
74
+ labels and tags.
75
+
76
+ ## Tests
77
+
78
+ ```sh
79
+ npm test
80
+ node ./scripts/conformance.mjs
81
+ npm run perf:int
82
+ npm run perf:ieee
83
+ ```
84
+
85
+ The conformance runner reuses supported fixtures from `../../conformance`,
86
+ emits LLVM IR for each fixture, generates a small C driver for the fixture
87
+ input and expected value, links it with `runtime/krt.c`, and runs the binary.
88
+
89
+ The performance runners mirror the `k-wasm` integer and IEEE harnesses. They
90
+ load the real example programs from `@fraczak/k`, generate the same operation
91
+ matrices, compare backend output to native `k` results, and time the native JS,
92
+ kVM, and LLVM executable lanes. Set `LLVM_ONLY=1` to skip native timing,
93
+ `ITERATIONS=N` to change samples, and `LLVM_STRICT=1` to make unsupported LLVM
94
+ cases fail the process. The LLVM lane uses persistent executables by default;
95
+ set `LLVM_PIPELINE=1` to measure parallel request pipelining or
96
+ `LLVM_SPAWN_PER_CALL=1` to reproduce the older spawn-per-operation timing.
97
+
98
+ ## Scope
99
+
100
+ Current output:
101
+
102
+ - KIR-P envelope specialization through `@fraczak/k/backend-api.mjs`;
103
+ - textual LLVM IR with embedded envelope-specialized KIR-P metadata;
104
+ - boxed runtime ABI declarations;
105
+ - identity, filter/code erasure, product projection/construction, and variant
106
+ construction/projection lowerings as `@k_main(k_rt*, k_value*) -> k_result`;
107
+ - KIR `comp` lowering for sequencing supported operations;
108
+ - KIR `empty` failure and ordered `union` branch selection;
109
+ - KIR `ref` lowering to internal `%k_result` relation functions;
110
+ - a tiny C runtime under `runtime/`.
111
+
112
+ Next backend steps:
113
+
114
+ - add an executable conformance mode once the runtime ABI exists.
115
+
116
+ ## Runtime ABI
117
+
118
+ The C side owns all runtime allocation:
119
+
120
+ ```c
121
+ typedef struct k_rt k_rt;
122
+ typedef struct k_value k_value;
123
+
124
+ typedef struct {
125
+ int32_t status;
126
+ k_value *value;
127
+ } k_result;
128
+
129
+ k_result k_main(k_rt *rt, k_value *input);
130
+ ```
131
+
132
+ `runtime/krt.h` provides the initial boxed helpers for units, products,
133
+ variants, and pointer equality. The representation is intentionally opaque so
134
+ future KIR specialization can add unboxed fast paths without changing the
135
+ external ABI.
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import { argv, exit } from "node:process";
5
+ import { decodeObject } from "@fraczak/k/object.mjs";
6
+ import { compileObjectToExecutable } from "../src/executable.mjs";
7
+
8
+ function usage(stream = console.error) {
9
+ const prog = argv[1] || "k-llvm-build.mjs";
10
+ stream(`Usage: node ${prog} [options] object-file output-exe`);
11
+ stream("Compile a k .ko/.klib object into a native executable.");
12
+ stream("");
13
+ stream("The executable reads a binary k pattern+value envelope from stdin and");
14
+ stream("writes a binary k pattern+value envelope to stdout.");
15
+ stream("The stdin envelope pattern must match the compiled input pattern;");
16
+ stream("stdout is encoded with the compiled output pattern.");
17
+ stream("");
18
+ stream("Options:");
19
+ stream(" --retype rel Relation to specialize. Defaults to object main.");
20
+ stream(" --input-pattern value Required input pattern property-list JSON, or a file containing it.");
21
+ stream(" -h, --help Show this help.");
22
+ }
23
+
24
+ function readMaybeFile(textOrPath) {
25
+ return fs.existsSync(textOrPath) ? fs.readFileSync(textOrPath, "utf8") : textOrPath;
26
+ }
27
+
28
+ function readPattern(inputPattern) {
29
+ if (inputPattern == null) return null;
30
+ return JSON.parse(readMaybeFile(inputPattern));
31
+ }
32
+
33
+ try {
34
+ const args = argv.slice(2);
35
+ if (args.includes("-h") || args.includes("--help")) {
36
+ usage(console.log);
37
+ exit(0);
38
+ }
39
+
40
+ let relation = null;
41
+ let inputPattern = null;
42
+ while (args.length > 0 && args[0].startsWith("--")) {
43
+ const option = args.shift();
44
+ if (option === "--retype") {
45
+ relation = args.shift();
46
+ if (!relation) throw new Error("--retype requires a relation name");
47
+ } else if (option === "--input-pattern") {
48
+ inputPattern = args.shift();
49
+ if (!inputPattern) throw new Error("--input-pattern requires JSON or a file path");
50
+ } else {
51
+ throw new Error(`Unknown option: ${option}`);
52
+ }
53
+ }
54
+
55
+ const objectPath = args.shift() || null;
56
+ const outputPath = args.shift() || null;
57
+ if (objectPath == null) throw new Error("object-file is required");
58
+ if (outputPath == null) throw new Error("output-exe is required");
59
+ if (args.length > 0) throw new Error(`Unexpected argument: ${args[0]}`);
60
+ if (inputPattern == null) throw new Error("--input-pattern is required for k-llvm-build");
61
+
62
+ const object = decodeObject(fs.readFileSync(objectPath));
63
+ compileObjectToExecutable(object, outputPath, {
64
+ relation: relation || object.main,
65
+ inputPattern: readPattern(inputPattern)
66
+ });
67
+ } catch (error) {
68
+ console.error(error.stack || error.message || String(error));
69
+ usage();
70
+ exit(1);
71
+ }
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import { argv, exit, stdin, stdout } from "node:process";
5
+ import { compileBufferToLLVM } from "../src/llvm.mjs";
6
+
7
+ function usage(stream = console.error) {
8
+ const prog = argv[1] || "k-llvm-compile.mjs";
9
+ stream(`Usage: node ${prog} [options] object-file [output.ll]`);
10
+ stream("Compile a k .ko/.klib object into prototype LLVM IR.");
11
+ stream("");
12
+ stream("Arguments:");
13
+ stream(" object-file Input .ko or .klib file. Reads bytes from stdin when omitted.");
14
+ stream(" output.ll Output LLVM IR path. Writes to stdout when omitted.");
15
+ stream("");
16
+ stream("Options:");
17
+ stream(" --retype rel Relation to specialize. Defaults to object main.");
18
+ stream(" --input-pattern value Input pattern property-list JSON, or a file containing it.");
19
+ stream(" -h, --help Show this help.");
20
+ }
21
+
22
+ async function readStdinBytes() {
23
+ const chunks = [];
24
+ for await (const chunk of stdin) {
25
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
26
+ }
27
+ return Buffer.concat(chunks);
28
+ }
29
+
30
+ try {
31
+ const args = argv.slice(2);
32
+ if (args.includes("-h") || args.includes("--help")) {
33
+ usage(console.log);
34
+ exit(0);
35
+ }
36
+
37
+ let relation = null;
38
+ let inputPattern = null;
39
+ while (args.length > 0 && args[0].startsWith("--")) {
40
+ const option = args.shift();
41
+ if (option === "--retype") {
42
+ relation = args.shift();
43
+ if (!relation) throw new Error("--retype requires a relation name");
44
+ } else if (option === "--input-pattern") {
45
+ inputPattern = args.shift();
46
+ if (!inputPattern) throw new Error("--input-pattern requires JSON or a file path");
47
+ } else {
48
+ throw new Error(`Unknown option: ${option}`);
49
+ }
50
+ }
51
+ if (inputPattern == null) throw new Error("--input-pattern is required");
52
+
53
+ const inputPath = args.shift() || null;
54
+ const outputPath = args.shift() || null;
55
+ if (args.length > 0) throw new Error(`Unexpected argument: ${args[0]}`);
56
+
57
+ const input = inputPath == null ? await readStdinBytes() : fs.readFileSync(inputPath);
58
+ const { llvm } = compileBufferToLLVM(input, { relation, inputPattern });
59
+ if (outputPath == null) {
60
+ stdout.write(llvm);
61
+ } else {
62
+ fs.writeFileSync(outputPath, llvm);
63
+ }
64
+ } catch (error) {
65
+ console.error(error.stack || error.message || String(error));
66
+ usage();
67
+ exit(1);
68
+ }