@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
@@ -11,7 +11,10 @@ const outputPath = path.resolve(root, process.argv[3] || "benchmark-results.html
11
11
  const rowOrder = [
12
12
  "Native JS (Envelope-Aware)",
13
13
  "Native JS (Envelope-Free)",
14
- "kVM Interpreter (Env-Free)"
14
+ "kVM Interpreter (Env-Free)",
15
+ "KIR-P Export",
16
+ "k-wasm",
17
+ "k-llvm-jit"
15
18
  ];
16
19
 
17
20
  const columnGroups = [
@@ -90,7 +93,7 @@ function cellFor(result, best) {
90
93
  const ratio = best ? result.avgMs / best.avgMs : NaN;
91
94
  return `
92
95
  <div class="time">${fmtMs(result.avgMs)} <span>${fmtRatio(ratio)}</span></div>
93
- <div class="sub">rss ${fmtMiB(result.maxRssMiB)}</div>`;
96
+ <div class="sub">warmup ${fmtMs(result.warmupMs)} · rss ${fmtMiB(result.maxRssMiB)}</div>`;
94
97
  }
95
98
 
96
99
  function factorialCell(byCase, allResults) {
@@ -151,6 +154,7 @@ function buildDetails(results) {
151
154
  <td class="num">${fmtMs(result.avgMs)}</td>
152
155
  <td class="num">${fmtMs(result.minMs)}</td>
153
156
  <td class="num">${fmtMs(result.maxMs)}</td>
157
+ <td class="num">${fmtMs(result.warmupMs)}</td>
154
158
  <td class="num">${fmtMiB(result.maxRssMiB)}</td>
155
159
  <td class="hash">${escapeHtml(result.resultDigest || "")}</td>
156
160
  </tr>`)
@@ -167,7 +171,7 @@ function render(doc) {
167
171
  <head>
168
172
  <meta charset="utf-8">
169
173
  <meta name="viewport" content="width=device-width, initial-scale=1">
170
- <title>k Benchmark Results</title>
174
+ <title>k Backend Benchmark Results</title>
171
175
  <style>
172
176
  :root {
173
177
  color-scheme: light;
@@ -201,7 +205,7 @@ function render(doc) {
201
205
  font-size: 14px;
202
206
  }
203
207
  main {
204
- max-width: 1320px;
208
+ max-width: 1480px;
205
209
  margin: 0 auto;
206
210
  padding: 24px 32px 40px;
207
211
  }
@@ -237,7 +241,7 @@ function render(doc) {
237
241
  font-weight: 700;
238
242
  }
239
243
  .matrix {
240
- min-width: 980px;
244
+ min-width: 1120px;
241
245
  }
242
246
  .matrix .group {
243
247
  text-align: center;
@@ -253,7 +257,7 @@ function render(doc) {
253
257
  margin-top: 2px;
254
258
  }
255
259
  .row-head {
256
- width: 230px;
260
+ width: 250px;
257
261
  color: var(--ink);
258
262
  font-weight: 800;
259
263
  background: #fbfcfe;
@@ -302,7 +306,7 @@ function render(doc) {
302
306
  </head>
303
307
  <body>
304
308
  <header>
305
- <h1>k Benchmark Results</h1>
309
+ <h1>k Backend Benchmark Results</h1>
306
310
  <div class="meta">
307
311
  <span>Generated: ${escapeHtml(generatedAt)}</span>
308
312
  <span>Node: ${escapeHtml(doc.node || "unknown")}</span>
@@ -326,7 +330,7 @@ function render(doc) {
326
330
  <div class="panel">
327
331
  <table>
328
332
  <thead>
329
- <tr><th>Case</th><th>Mode</th><th>Status</th><th>Avg</th><th>Min</th><th>Max</th><th>Max RSS</th><th>Digest</th></tr>
333
+ <tr><th>Case</th><th>Mode</th><th>Status</th><th>Avg</th><th>Min</th><th>Max</th><th>Warmup</th><th>Max RSS</th><th>Digest</th></tr>
330
334
  </thead>
331
335
  <tbody>${buildDetails(results)}</tbody>
332
336
  </table>
@@ -21,9 +21,15 @@ const tests = [
21
21
  ["tests/test-structural-values.mjs", node, ["tests/test-structural-values.mjs"]],
22
22
  ["tests/test-deep-wire-value.mjs", node, ["tests/test-deep-wire-value.mjs"]],
23
23
  ["tests/test-k-object.mjs", node, ["tests/test-k-object.mjs"]],
24
+ ["tests/test-kir.mjs", node, ["tests/test-kir.mjs"]],
25
+ ["tests/test-validate-object.mjs", node, ["tests/test-validate-object.mjs"]],
26
+ ["conformance/run.mjs", node, ["conformance/run.mjs"]],
24
27
  ["tests/test-repl.mjs", node, ["tests/test-repl.mjs"]],
28
+ ["tests/test-repl-html.mjs", node, ["tests/test-repl-html.mjs"]],
25
29
  ["tests/test-kvm.mjs", node, ["tests/test-kvm.mjs"]],
30
+ ["tests/test-kvm-polymorphic.mjs", node, ["tests/test-kvm-polymorphic.mjs"]],
26
31
  ["tests/test-arithmetics.mjs", node, ["tests/test-arithmetics.mjs"]],
32
+ ["tests/test-poly.mjs", node, ["tests/test-poly.mjs"]],
27
33
  ["tests/test-ieee-arithmetic.mjs", node, ["tests/test-ieee-arithmetic.mjs"]],
28
34
  ["tests/integration.sh", path.join(root, "tests/integration.sh"), []]
29
35
  ];
@@ -10,11 +10,28 @@ trap 'rm -rf "$TMP_DIR"' EXIT
10
10
 
11
11
  ./objects/compile.mjs 'x = |x; x x' "$TMP_DIR/inline.ko"
12
12
  ./objects/decompile.mjs "$TMP_DIR/inline.ko" | grep -q '^----- main -----$'
13
+ ./objects/inspect.mjs "$TMP_DIR/inline.ko" | grep -q '^format: k-object$'
14
+ ./objects/inspect.mjs --kir "$TMP_DIR/inline.ko" | grep -q '"format": "k-ir"'
15
+ ./kir.mjs --help | grep -q 'Export the KIR-P JSON view'
16
+ ./kir.mjs "$TMP_DIR/inline.ko" | grep -q '"format": "k-ir"'
17
+ ./objects/validate.mjs "$TMP_DIR/inline.ko" | grep -q '^OK object$'
18
+ ./kir.mjs "$TMP_DIR/inline.ko" > "$TMP_DIR/inline.kir.json"
19
+ ./objects/validate.mjs --kir "$TMP_DIR/inline.kir.json" | grep -q '^OK KIR-P$'
20
+ printf '[["open-product",[]]]' > "$TMP_DIR/input.pattern.json"
21
+ ./kir.mjs --retype __main__ --input-pattern "$TMP_DIR/input.pattern.json" "$TMP_DIR/inline.ko" > "$TMP_DIR/inline.retyped.kir.json"
22
+ ./objects/validate.mjs --kir "$TMP_DIR/inline.retyped.kir.json" | grep -q '^OK KIR-P$'
23
+ printf '[["closed-product",[]]]' > "$TMP_DIR/unit.pattern.json"
13
24
  printf '()' | ./objects/compile.mjs > "$TMP_DIR/stdin.ko"
14
25
  ./objects/decompile.mjs "$TMP_DIR/stdin.ko" | grep -q '^----- main -----$'
15
- ./objects/compile.mjs --format kvm '()' | grep -q '"__main__"'
16
- ./objects/compile.mjs "$TMP_DIR/stdin.ko" "$TMP_DIR/stdin.kvm"
26
+ ./objects/compile.mjs --format kvm '()' | grep -q '"format": "k-vm"'
27
+ ./objects/compile.mjs --format kvm '()' > "$TMP_DIR/stdin.kvm"
28
+ grep -q '"format": "k-vm"' "$TMP_DIR/stdin.kvm"
29
+ grep -q '"layer": "KVM-P"' "$TMP_DIR/stdin.kvm"
30
+ grep -q '"isPolymorphic": true' "$TMP_DIR/stdin.kvm"
17
31
  grep -q '"__main__"' "$TMP_DIR/stdin.kvm"
32
+ ./objects/compile.mjs "$TMP_DIR/stdin.ko" "$TMP_DIR/poly-object.kvm"
33
+ grep -q '"layer": "KVM-P"' "$TMP_DIR/poly-object.kvm"
34
+ grep -q '"isPolymorphic": true' "$TMP_DIR/poly-object.kvm"
18
35
  ./objects/compile.mjs 'id = ();' "$TMP_DIR/export.klib"
19
36
  ./objects/compile.mjs --lib "$TMP_DIR/export.klib" --export id:alias 'alias' "$TMP_DIR/export.ko"
20
37
  ./objects/decompile.mjs "$TMP_DIR/export.ko" | grep -q '^----- main -----$'
@@ -89,6 +89,60 @@ try {
89
89
  );
90
90
  }
91
91
 
92
+ // Regression tests for inc/dec normalization and div
93
+ const resDec = run(node, [
94
+ "k.mjs",
95
+ "--lib", libPath,
96
+ "--export", "dec:dec",
97
+ "--export", "zero_int?:zero_int?",
98
+ "dec dec zero_int?"
99
+ ], { input: parseIntWire("2") });
100
+ assertOk(resDec, "2 int dec dec zero_int? should succeed");
101
+
102
+ const divTestCases = [
103
+ { x: "4", yAlias: "1", yVal: 1n },
104
+ { x: "10", yAlias: "2", yVal: 2n },
105
+ { x: "12", yAlias: "3", yVal: 3n },
106
+ { x: "11", yAlias: "3", yVal: 3n },
107
+ { x: "100", yAlias: "7", yVal: 7n },
108
+ { x: "-100", yAlias: "7", yVal: 7n },
109
+ { x: "1000", yAlias: "10", yVal: 10n }
110
+ ];
111
+
112
+ for (const { x, yAlias, yVal } of divTestCases) {
113
+ const xBig = BigInt(x);
114
+ const expectedDiv = (xBig / yVal).toString();
115
+ const xAbs = xBig < 0n ? -xBig : xBig;
116
+ const yAbs = yVal < 0n ? -yVal : yVal;
117
+ const expectedRem = (xAbs % yAbs).toString();
118
+
119
+ const wire = parseIntWire(x);
120
+
121
+ const resDiv = run(node, [
122
+ "k.mjs",
123
+ "--lib", libPath,
124
+ "--export", "div:div",
125
+ "--export", "int:int",
126
+ "--export", `${yAlias}:divisor`,
127
+ "{() x, divisor int y} div .div"
128
+ ], { input: wire });
129
+ assertOk(resDiv, `native div(${x}, ${yAlias}) quotient`);
130
+ const divOut = printIntWire(resDiv.stdout, `div quotient`);
131
+ assert.equal(divOut, expectedDiv, `div(${x}, ${yAlias}) quotient should match BigInt oracle`);
132
+
133
+ const resRem = run(node, [
134
+ "k.mjs",
135
+ "--lib", libPath,
136
+ "--export", "div:div",
137
+ "--export", "int:int",
138
+ "--export", `${yAlias}:divisor`,
139
+ "{() x, divisor int y} div .rem int"
140
+ ], { input: wire });
141
+ assertOk(resRem, `native div(${x}, ${yAlias}) remainder`);
142
+ const remOut = printIntWire(resRem.stdout, `div remainder`);
143
+ assert.equal(remOut, expectedRem, `div(${x}, ${yAlias}) remainder should match BigInt oracle`);
144
+ }
145
+
92
146
  console.log("OK");
93
147
  } finally {
94
148
  fs.rmSync(tmpDir, { recursive: true, force: true });
@@ -69,6 +69,10 @@ const cases = [
69
69
  { op: "mul", x: "-2", y: "4", result: "-8", flags: "none" },
70
70
  { op: "mul", x: "Infinity", y: "0", result: "NaN", flags: "invalid" },
71
71
  { op: "div", x: "1", y: "2", result: "0.5" },
72
+ { op: "div", x: "9", y: "3", result: "3", flags: "none", projection: true },
73
+ { op: "div", x: "10", y: "2", result: "5", flags: "none" },
74
+ { op: "div", x: "1", y: "3", result: "0.3333333333333333", flags: "inexact" },
75
+ { op: "div", x: "-6", y: "2", result: "-3", flags: "none" },
72
76
  { op: "div", x: "1", y: "0", result: "Infinity", flags: "div_by_zero" },
73
77
  { op: "div", x: "0", y: "0", result: "NaN", flags: "invalid" }
74
78
  ];
@@ -0,0 +1,85 @@
1
+ import assert from "node:assert";
2
+ import { compileLibraryBuffer, compileObjectBuffer, decodeObject } from "../object.mjs";
3
+ import { objectToKIRP, retypeObjectRelation } from "../kir.mjs";
4
+ import {
5
+ objectToKIRP as backendObjectToKIRP,
6
+ objectToKVMArtifact,
7
+ retypeObjectRelation as backendRetypeObjectRelation
8
+ } from "../backend-api.mjs";
9
+ import { validateKIRP } from "../objects/validate.mjs";
10
+
11
+ const object = decodeObject(compileObjectBuffer(`
12
+ $ bit = < {} 0, {} 1 >;
13
+ id = ();
14
+ .x id
15
+ `, { source: "kir-test.k" }));
16
+ const kir = objectToKIRP(object);
17
+ assert.equal(backendObjectToKIRP(object).format, "k-ir");
18
+
19
+ assert.equal(kir.format, "k-ir");
20
+ assert.equal(kir.version, 1);
21
+ assert.equal(kir.layer, "KIR-P");
22
+ assert.equal(kir.sourceFormat, "k-object");
23
+ assert.equal(kir.kind, "executable");
24
+ assert.equal(kir.main, "__main__");
25
+ assert.equal(kir.rels.__main__.typeDerivation.status, "converged");
26
+ assert.equal(typeof kir.rels.__main__.inputPattern, "number");
27
+ assert.equal(typeof kir.rels.__main__.outputPattern, "number");
28
+ assert(Array.isArray(kir.rels.__main__.patternGraph.nodes));
29
+ assert(kir.rels.__main__.patternGraph.nodes.every((node, index) => node.id === index));
30
+ assert.deepEqual(new Set(kir.rels.__main__.patternGraph.nodes.map((node) => node.kind)).has("open-product"), true);
31
+ assert.equal(kir.rels.__main__.body.op, "dot");
32
+ assert.equal(kir.rels.__main__.body.label, "x");
33
+ const retyped = validateKIRP(retypeObjectRelation(object, "__main__", [
34
+ ["closed-product", [["x", 1]]],
35
+ ["closed-product", []]
36
+ ]));
37
+ assert.equal(retyped.layer, "KIR-P");
38
+ assert.equal(retyped.kind, "executable");
39
+ assert.equal(retyped.main, "__main__");
40
+ assert.equal(retyped.rels.__main__.body.op, "ref");
41
+ assert.equal(retyped.rels.__main__.body.ref, "__kir_target__");
42
+ assert(!("instanceKey" in retyped));
43
+ assert(!("callSites" in retyped));
44
+ assert.equal(backendRetypeObjectRelation(object, "__main__", [["open-product", []]]).layer, "KIR-P");
45
+ assert.throws(
46
+ () => objectToKVMArtifact(object, "__main__", [["open-product", []]]),
47
+ /\.kvm emission requires a singleton input pattern/
48
+ );
49
+ const kvmArtifact = objectToKVMArtifact(object, "__main__", [
50
+ ["closed-product", [["x", 1]]],
51
+ ["closed-product", []]
52
+ ]);
53
+ assert.equal(kvmArtifact.format, "k-vm");
54
+ assert.equal(kvmArtifact.layer, "KVM");
55
+ assert.equal(kvmArtifact.entry, "__main__");
56
+ assert.deepEqual(kvmArtifact.inputPattern, [
57
+ ["closed-product", [["x", 1]]],
58
+ ["closed-product", []]
59
+ ]);
60
+ assert.deepEqual(kvmArtifact.outputPattern, [["closed-product", []]]);
61
+ assert.ok(kvmArtifact.functions.__main__);
62
+ assert.equal(kvmArtifact.kir.layer, "KIR-P");
63
+ assert(!("instanceKey" in kvmArtifact));
64
+
65
+ const helperObject = decodeObject(compileObjectBuffer("pick = .x; {.a pick left, .b pick right}", { source: "kir-helper.k" }));
66
+ const helperRetyped = validateKIRP(retypeObjectRelation(helperObject, "__main__", [
67
+ ["open-product", [["a", 1], ["b", 2]]],
68
+ ["open-product", [["x", 3]]],
69
+ ["open-product", [["x", 4]]],
70
+ ["closed-product", []],
71
+ ["closed-product", []]
72
+ ]));
73
+ assert.equal(helperRetyped.layer, "KIR-P");
74
+ assert.equal(helperRetyped.kind, "executable");
75
+ assert.ok(helperRetyped.rels.pick);
76
+ assert(!("instanceKey" in helperRetyped));
77
+ assert(!("callSites" in helperRetyped));
78
+
79
+ const library = decodeObject(compileLibraryBuffer("succ = |succ;\n", { source: "kir-lib.k" }));
80
+ const libraryKir = objectToKIRP(library);
81
+ assert.equal(libraryKir.kind, "library");
82
+ assert.equal(libraryKir.main, null);
83
+ assert(Object.values(libraryKir.rels).some((rel) => rel.body.op === "vid"));
84
+
85
+ console.log("OK");
@@ -0,0 +1,278 @@
1
+ import assert from "node:assert";
2
+ import k from "../index.mjs";
3
+ import {
4
+ objectToKVMArtifact,
5
+ specializeKVM,
6
+ executeKVM
7
+ } from "../kvm.mjs";
8
+ import { compileObjectBuffer, decodeObject } from "../object.mjs";
9
+ import { objectToKIRP } from "../kir.mjs";
10
+ import { fromObject, Value } from "../Value.mjs";
11
+ import { lowerToWasm } from "../backends/wasm/src/kvm2wasm.mjs";
12
+ import wabtFactory from "wabt";
13
+ import fs from "node:fs";
14
+ import path from "node:path";
15
+ import { spawnSync } from "node:child_process";
16
+ import { fileURLToPath } from "node:url";
17
+
18
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
19
+ const runtimeWat = fs.readFileSync(path.join(__dirname, "../backends/wasm/runtime.wat"), "utf8");
20
+
21
+ function toJSON(value) {
22
+ if (value === undefined) return undefined;
23
+ return JSON.parse(JSON.stringify(value));
24
+ }
25
+
26
+ console.log("==> Starting Polymorphic kVM & Specialization Tests");
27
+
28
+ // Test 1: Compile Polymorphic kVM Artifact (AOT) without input pattern
29
+ {
30
+ const script = `
31
+ map = { .a first, .b second };
32
+ map
33
+ `;
34
+ const obj = decodeObject(compileObjectBuffer(script));
35
+ const kvmArtifact = objectToKVMArtifact(obj);
36
+
37
+ assert.equal(kvmArtifact.format, "k-vm");
38
+ assert.equal(kvmArtifact.layer, "KVM-P");
39
+ assert.equal(kvmArtifact.isPolymorphic, true);
40
+ assert.ok(kvmArtifact.functions["__main__"]);
41
+ assert.ok(Array.isArray(kvmArtifact.inputPattern));
42
+ console.log("Test 1 (Polymorphic kVM AOT Artifact): Passed");
43
+ }
44
+
45
+ // Test 2: Specialize Polymorphic kVM with Conforming Envelope & Subtyping
46
+ {
47
+ const script = `
48
+ map = { .a first, .b second };
49
+ map
50
+ `;
51
+ const obj = decodeObject(compileObjectBuffer(script));
52
+ const kvmArtifact = objectToKVMArtifact(obj);
53
+
54
+ // Input envelope carries extra field 'extra'
55
+ const inputEnvelope = [
56
+ ["closed-product", [["a", 1], ["b", 2], ["extra", 3]]],
57
+ ["closed-product", []],
58
+ ["closed-union", [["valB", 4]]],
59
+ ["closed-product", []],
60
+ ["closed-product", []]
61
+ ];
62
+
63
+ const specialized = specializeKVM(kvmArtifact, inputEnvelope);
64
+ assert.equal(specialized.isSpecialized, true);
65
+ assert.equal(specialized.layer, "KVM-M");
66
+
67
+ const specFunc = specialized.functions[specialized.entry];
68
+ assert.ok(specFunc);
69
+ assert.equal(specFunc.isSpecialized, true);
70
+
71
+ // Execute in envelopeFree mode
72
+ const val = fromObject({
73
+ a: { unit: {} },
74
+ b: { valB: {} },
75
+ extra: { dummy: {} }
76
+ });
77
+
78
+ const res = executeKVM(specFunc, val, {
79
+ rels: kvmArtifact.kir.rels,
80
+ codes: kvmArtifact.codes,
81
+ options: { envelopeFree: true }
82
+ });
83
+
84
+ assert.deepEqual(toJSON(res), {
85
+ first: "unit",
86
+ second: "valB"
87
+ });
88
+ console.log("Test 2 (Specialize with Subtyping & Envelope-Free Execution): Passed");
89
+ }
90
+
91
+ // Test 3: Type Error on Envelope Mismatch
92
+ {
93
+ const script = `
94
+ $ bool = < {} true, {} false >;
95
+ check = $bool;
96
+ check
97
+ `;
98
+ const obj = decodeObject(compileObjectBuffer(script));
99
+ const kvmArtifact = objectToKVMArtifact(obj);
100
+
101
+ // An envelope with variant 'other' does not conform to bool
102
+ const incompatibleEnvelope = [
103
+ ["closed-union", [["other", 1]]],
104
+ ["closed-product", []]
105
+ ];
106
+
107
+ assert.throws(
108
+ () => specializeKVM(kvmArtifact, incompatibleEnvelope),
109
+ (err) => {
110
+ assert.ok(err instanceof TypeError);
111
+ assert.ok(err.message.includes("Type Error"));
112
+ return true;
113
+ },
114
+ "Expected TypeError on incompatible envelope"
115
+ );
116
+ console.log("Test 3 (Type Error on Envelope Mismatch): Passed");
117
+ }
118
+
119
+ // Test 4: Dead Branch Elimination in Union Specialization
120
+ {
121
+ const script = `
122
+ choose = < /x, /y >;
123
+ choose
124
+ `;
125
+ const obj = decodeObject(compileObjectBuffer(script));
126
+ const kvmArtifact = objectToKVMArtifact(obj);
127
+ const unspecFunc = kvmArtifact.functions[kvmArtifact.entry];
128
+ const unspecUnion = unspecFunc.body.find(inst => inst.op === "union");
129
+ assert.equal(unspecUnion.branches.length, 2, "Unspecialized union has 2 branches");
130
+
131
+ // Specialize with envelope containing ONLY variant 'x'
132
+ const xEnvelope = [
133
+ ["closed-union", [["x", 1]]],
134
+ ["closed-product", []]
135
+ ];
136
+
137
+ const specialized = specializeKVM(kvmArtifact, xEnvelope);
138
+ const specFunc = specialized.functions[specialized.entry];
139
+ const specUnion = specFunc.body.find(inst => inst.op === "union");
140
+
141
+ // The 'y' branch should be pruned!
142
+ assert.equal(specUnion.branches.length, 1, "Specialized union should prune unreachable branch");
143
+ assert.equal(specUnion.branches[0].body[0].tag, "x");
144
+
145
+ // Execution on { x: payload }
146
+ const valX = fromObject({ x: { payload: {} } });
147
+ const resX = executeKVM(specFunc, valX, {
148
+ rels: kvmArtifact.kir.rels,
149
+ codes: kvmArtifact.codes,
150
+ options: { envelopeFree: true }
151
+ });
152
+ assert.deepEqual(toJSON(resX), "payload");
153
+
154
+ console.log("Test 4 (Dead Branch Elimination in Union): Passed");
155
+ }
156
+
157
+ // Test 5: Redundant Guard Elimination
158
+ {
159
+ const script = `
160
+ filterTest = ?{ ... } (.a);
161
+ filterTest
162
+ `;
163
+ const obj = decodeObject(compileObjectBuffer(script));
164
+ const kvmArtifact = objectToKVMArtifact(obj);
165
+
166
+ const inputEnvelope = [
167
+ ["closed-product", [["a", 1]]],
168
+ ["closed-product", []]
169
+ ];
170
+
171
+ const specialized = specializeKVM(kvmArtifact, inputEnvelope);
172
+ const specFunc = specialized.functions[specialized.entry];
173
+
174
+ // The guard_pattern was checking open product, which inputEnvelope already satisfies.
175
+ // It should be simplified to 'id' or eliminated!
176
+ const hasUnsimplifiedGuard = specFunc.body.some(inst => inst.op === "guard_pattern");
177
+ assert.equal(hasUnsimplifiedGuard, false, "Redundant guard should be eliminated or simplified to id");
178
+
179
+ console.log("Test 5 (Redundant Guard Elimination): Passed");
180
+ }
181
+
182
+ // Test 6: Fast Compilation to WebAssembly from Specialized kVM
183
+ {
184
+ const script = `
185
+ map = { .a first, .b second };
186
+ map
187
+ `;
188
+ const obj = decodeObject(compileObjectBuffer(script));
189
+ const kvmArtifact = objectToKVMArtifact(obj);
190
+
191
+ const inputEnvelope = [
192
+ ["closed-product", [["a", 1], ["b", 2], ["extra", 3]]],
193
+ ["closed-product", []],
194
+ ["closed-product", []],
195
+ ["closed-product", []]
196
+ ];
197
+
198
+ const specialized = specializeKVM(kvmArtifact, inputEnvelope);
199
+ const specFunc = specialized.functions[specialized.entry];
200
+
201
+ // Lower directly to Wasm WAT
202
+ const watBody = lowerToWasm(specFunc, "map_spec");
203
+ assert.ok(watBody.includes("(func $map_spec"));
204
+
205
+ // Assemble with wabt to ensure it is 100% valid Wasm
206
+ const wabt = await wabtFactory();
207
+ const fullWat = runtimeWat.trim().slice(0, -1) + "\n" + watBody + "\n)";
208
+ const wasmModule = wabt.parseWat("test.wat", fullWat, {
209
+ mutable_globals: true,
210
+ sat_float_to_int: true,
211
+ sign_extension: true,
212
+ multi_value: true,
213
+ bulk_memory: true,
214
+ reference_types: true
215
+ });
216
+ wasmModule.resolveNames();
217
+ wasmModule.validate();
218
+ const binary = wasmModule.toBinary({ log: false, write_debug_names: false });
219
+ assert.ok(binary.buffer.byteLength > 0);
220
+
221
+ console.log("Test 6 (Direct Lowering to WebAssembly): Passed");
222
+ }
223
+
224
+ // Test 7: CLI Compilation to Polymorphic .kvm without --input-pattern
225
+ {
226
+ const compileScript = path.join(__dirname, "../objects/compile.mjs");
227
+ const res = spawnSync(process.execPath, [compileScript, "--format", "kvm", "Examples/arithmetics.k"], {
228
+ cwd: path.join(__dirname, ".."),
229
+ encoding: "utf8"
230
+ });
231
+ assert.equal(res.status, 0, `CLI compile failed: ${res.stderr}`);
232
+ const kvm = JSON.parse(res.stdout);
233
+ assert.equal(kvm.format, "k-vm");
234
+ assert.equal(kvm.layer, "KVM-P");
235
+ assert.equal(kvm.isPolymorphic, true);
236
+ assert.ok(kvm.functions["__main__"]);
237
+ console.log("Test 7 (CLI Compilation to Polymorphic .kvm): Passed");
238
+ }
239
+
240
+ // Test 8: CLI Compilation with --lib and explicit --export (no auto-export)
241
+ {
242
+ const compileScript = path.join(__dirname, "../objects/compile.mjs");
243
+ // Fails without explicit --export
244
+ const failRes = spawnSync(process.execPath, [
245
+ compileScript,
246
+ "--lib", "Examples/arithmetics.k",
247
+ "{succ int x,int y}+"
248
+ ], {
249
+ cwd: path.join(__dirname, ".."),
250
+ encoding: "utf8"
251
+ });
252
+ assert.notEqual(failRes.status, 0, "Should fail without explicit --export");
253
+
254
+ // Succeeds with explicit --export
255
+ const successRes = spawnSync(process.execPath, [
256
+ compileScript,
257
+ "--lib", "Examples/arithmetics.k",
258
+ "--export", "plus:+",
259
+ "--export", "succ",
260
+ "--export", "int",
261
+ "--format", "kvm",
262
+ "{succ int x,int y}+"
263
+ ], {
264
+ cwd: path.join(__dirname, ".."),
265
+ encoding: "utf8",
266
+ maxBuffer: 10 * 1024 * 1024
267
+ });
268
+ assert.equal(successRes.status, 0, `CLI compile with --export failed: ${successRes.stderr}`);
269
+ const kvm = JSON.parse(successRes.stdout);
270
+ assert.equal(kvm.format, "k-vm");
271
+ assert.equal(kvm.layer, "KVM-P");
272
+ assert.equal(kvm.isPolymorphic, true);
273
+ assert.ok(kvm.functions["__main__"]);
274
+ console.log("Test 8 (CLI Compilation with --lib and explicit --export): Passed");
275
+ }
276
+
277
+ console.log("==> All Polymorphic kVM Tests Passed Successfully!");
278
+
@@ -1,17 +1,25 @@
1
1
  import assert from "node:assert";
2
2
  import k from "../index.mjs";
3
- import { lowerToKVM, executeKVM } from "../kvm.mjs";
3
+ import { lowerKIRRelationToKVM, executeKVM } from "../kvm.mjs";
4
4
  import codes from "../codes.mjs";
5
5
  import { fromObject } from "../Value.mjs";
6
6
  import run, { run_converged } from "../run.mjs";
7
+ import { compileObjectBuffer, decodeObject } from "../object.mjs";
8
+ import { objectToKIRP } from "../kir.mjs";
7
9
 
8
10
  function runKVM(script, data, options = {}) {
9
- const defs = k.annotate(script, {
11
+ const object = decodeObject(compileObjectBuffer(script, {
10
12
  convergence: { strategy: "auto" }
11
- });
12
- const mainRel = defs.rels.__main__;
13
- const kvmFunc = lowerToKVM(mainRel, "__main__");
14
- const context = { rels: defs.rels, findCode: codes.find, options };
13
+ }));
14
+ const kir = objectToKIRP(object);
15
+ const mainRel = kir.rels[kir.main];
16
+ const kvmFunc = lowerKIRRelationToKVM(mainRel, kir.main, { codes: kir.codes });
17
+ const context = {
18
+ rels: kir.rels,
19
+ codes: kir.codes,
20
+ findCode: (hash) => kir.codes[hash] || codes.find(hash),
21
+ options
22
+ };
15
23
  return executeKVM(kvmFunc, fromObject(data), context);
16
24
  }
17
25
 
@@ -160,4 +168,15 @@ console.log("==> Starting kVM Tests");
160
168
  console.log("Test 9 (KVM vs JS run equivalence & Peano addition): Passed");
161
169
  }
162
170
 
171
+ // Test 10: Intrinsic handling is explicit, not based on identifier spelling
172
+ {
173
+ const result = runKVM("_user = .a; _user", { a: {}, b: {} });
174
+ assert.deepEqual(toJSON(result), {});
175
+ assert.throws(
176
+ () => runKVM("_log!", { unit: {} }),
177
+ /kVM interpreter: unsupported intrinsic '_log!'/
178
+ );
179
+ console.log("Test 10 (Explicit intrinsics): Passed");
180
+ }
181
+
163
182
  console.log("==> All kVM Tests Passed!");