@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
package/codecs/README.md CHANGED
@@ -79,6 +79,9 @@ notation for k values. That notation is documented in
79
79
  [`../DOCS/TEXTUAL_VALUES.md`](../DOCS/TEXTUAL_VALUES.md). It is a readable
80
80
  notation for k values, not a separate JSON container format.
81
81
 
82
+ For the contributor-facing guide to writing a new external codec module, see
83
+ [`../DOCS/CODECS.md`](../DOCS/CODECS.md).
84
+
82
85
  `k.mjs` is only the command-line adapter for that boundary. The operational
83
86
  runtime sees and preserves the pattern on the `Value` itself.
84
87
 
package/codecs/json.mjs CHANGED
@@ -5,6 +5,9 @@ import { decodeWire, encodeToWire } from "./runtime/prefix-codec.mjs";
5
5
  import { isMainEntrypoint } from "./runtime/cli-entry.mjs";
6
6
  import { fromJsonValue, toJsonValue, patternFromJsonValue } from "./json-codec.mjs";
7
7
 
8
+ const name = "json";
9
+ const universal = true;
10
+
8
11
  function usage(stream = console.error) {
9
12
  stream(`Usage: ${argv[1]} --parse | --print`);
10
13
  stream(" --parse Read JSON from stdin, write binary pattern+value stream.");
@@ -21,6 +24,14 @@ function readAll(stream) {
21
24
  });
22
25
  }
23
26
 
27
+ function parse(text) {
28
+ return fromJsonValue(JSON.parse(text));
29
+ }
30
+
31
+ function print(value) {
32
+ return JSON.stringify(toJsonValue(value));
33
+ }
34
+
24
35
  async function main() {
25
36
  const args = argv.slice(2);
26
37
  if (args.includes("-h") || args.includes("--help")) {
@@ -36,12 +47,13 @@ async function main() {
36
47
  const buf = await readAll(stdin);
37
48
 
38
49
  if (args[0] === "--parse") {
39
- const json = JSON.parse(buf.toString("utf8"));
50
+ const text = buf.toString("utf8");
51
+ const json = JSON.parse(text);
40
52
  const value = fromJsonValue(json);
41
53
  stdout.write(encodeToWire(value, patternFromJsonValue(json)));
42
54
  } else {
43
55
  const { value } = decodeWire(buf);
44
- stdout.write(`${JSON.stringify(toJsonValue(value))}\n`);
56
+ stdout.write(`${print(value)}\n`);
45
57
  }
46
58
  }
47
59
 
@@ -51,3 +63,5 @@ if (isMainEntrypoint(import.meta.url, argv[1])) {
51
63
  exit(1);
52
64
  });
53
65
  }
66
+
67
+ export { name, universal, parse, print };
@@ -6,7 +6,7 @@ function pLabel(label) {
6
6
  return nameRE.test(label) ? ` ${label}` : ` ${JSON.stringify(label)}`;
7
7
  }
8
8
 
9
- function propertyListToFilter(propertyList) {
9
+ function propertyListToFilter(propertyList, varPrefix = "X") {
10
10
  if (!propertyList || propertyList.length === 0) return "(...)";
11
11
 
12
12
  const refCount = new Array(propertyList.length).fill(0);
@@ -18,7 +18,7 @@ function propertyListToFilter(propertyList) {
18
18
  const varNames = new Map();
19
19
  let varCounter = 0;
20
20
  for (let i = 0; i < propertyList.length; i++) {
21
- if (refCount[i] > 1) varNames.set(i, `X${varCounter++}`);
21
+ if (refCount[i] > 1) varNames.set(i, `${varPrefix}${varCounter++}`);
22
22
  }
23
23
 
24
24
  const defined = new Set();
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "helper reuse",
3
+ "program": "program.k",
4
+ "input": "input.kv",
5
+ "expected": "expected.kv",
6
+ "modes": ["source", "object", "kir", "retyped"],
7
+ "tags": ["runtime", "retyping", "call-sites"]
8
+ }
@@ -0,0 +1 @@
1
+ {"left":"left","right":"right"}
@@ -0,0 +1 @@
1
+ {"a":{"x":"left","z":{}},"b":{"x":"right","z":{}}}
@@ -0,0 +1,2 @@
1
+ pick = .x;
2
+ {.a pick left, .b pick right}
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "identity",
3
+ "program": "program.k",
4
+ "input": "input.kv",
5
+ "expected": "expected.kv",
6
+ "modes": ["source", "object", "kir", "retyped"],
7
+ "tags": ["runtime", "identity"]
8
+ }
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1 @@
1
+ ()
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "product projection",
3
+ "program": "program.k",
4
+ "input": "input.kv",
5
+ "expected": "expected.kv",
6
+ "modes": ["source", "object", "kir", "retyped"],
7
+ "tags": ["runtime", "projection", "product"]
8
+ }
@@ -0,0 +1 @@
1
+ "left"
@@ -0,0 +1 @@
1
+ {"x":"left","y":"right"}
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import { argv, exit } from "node:process";
6
+ import { fileURLToPath } from "node:url";
7
+ import k from "../index.mjs";
8
+ import { parseValue } from "../valueIO.mjs";
9
+ import { compileObjectBuffer, decodeObject, objectToFunction } from "../object.mjs";
10
+ import { objectToKIRP, retypeObjectRelation } from "../kir.mjs";
11
+ import { validateKIRP } from "../objects/validate.mjs";
12
+ import { exportPatternGraph } from "../codecs/runtime/codec.mjs";
13
+ import { patternToPropertyList } from "../codecs/runtime/pattern-json.mjs";
14
+
15
+ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
16
+ const conformanceRoot = path.join(root, "conformance");
17
+ const DEFAULT_MODES = ["source", "object", "kir", "retyped"];
18
+
19
+ function helpText() {
20
+ return [
21
+ "Run k conformance fixtures.",
22
+ "",
23
+ `Usage: ${argv[1]} [options] [fixture-dir ...]`,
24
+ "",
25
+ "Options:",
26
+ " --mode list Comma-separated modes: source, object, kir, retyped.",
27
+ " -h, --help Show this help.",
28
+ "",
29
+ "With no fixture dirs, every directory under conformance/ with a case.json is run."
30
+ ].join("\n");
31
+ }
32
+
33
+ function usage(stream = console.error) {
34
+ stream(helpText());
35
+ }
36
+
37
+ function fixtureDirs(args) {
38
+ if (args.length > 0) return args.map((arg) => path.resolve(root, arg));
39
+ return fs.readdirSync(conformanceRoot, { withFileTypes: true })
40
+ .filter((entry) => entry.isDirectory())
41
+ .map((entry) => path.join(conformanceRoot, entry.name))
42
+ .filter((dir) => fs.existsSync(path.join(dir, "case.json")))
43
+ .sort();
44
+ }
45
+
46
+ function readFixture(dir) {
47
+ const spec = JSON.parse(fs.readFileSync(path.join(dir, "case.json"), "utf8"));
48
+ return {
49
+ dir,
50
+ name: spec.name || path.basename(dir),
51
+ modes: spec.modes || DEFAULT_MODES,
52
+ program: fs.readFileSync(path.join(dir, spec.program || "program.k"), "utf8"),
53
+ input: parseValue(fs.readFileSync(path.join(dir, spec.input || "input.kv"), "utf8")),
54
+ expected: parseValue(fs.readFileSync(path.join(dir, spec.expected || "expected.kv"), "utf8"))
55
+ };
56
+ }
57
+
58
+ function assertSameValue(actual, expected, label) {
59
+ const actualJson = JSON.stringify(actual.toJSON());
60
+ const expectedJson = JSON.stringify(expected.toJSON());
61
+ if (actualJson !== expectedJson) {
62
+ throw new Error(`${label}: expected ${expectedJson}, got ${actualJson}`);
63
+ }
64
+ }
65
+
66
+ function runSource(fixture) {
67
+ const result = k.compile(fixture.program)(fixture.input);
68
+ assertSameValue(result, fixture.expected, `${fixture.name}/source`);
69
+ }
70
+
71
+ function runObject(fixture) {
72
+ const object = decodeObject(compileObjectBuffer(fixture.program, {
73
+ source: path.relative(root, fixture.dir)
74
+ }));
75
+ const result = objectToFunction(object)(fixture.input);
76
+ assertSameValue(result, fixture.expected, `${fixture.name}/object`);
77
+ }
78
+
79
+ function runKIR(fixture) {
80
+ const object = decodeObject(compileObjectBuffer(fixture.program, {
81
+ source: path.relative(root, fixture.dir)
82
+ }));
83
+ const kir = validateKIRP(objectToKIRP(object));
84
+ if (kir.kind !== "executable") throw new Error(`${fixture.name}/kir: expected executable KIR`);
85
+ if (!kir.rels[kir.main]) throw new Error(`${fixture.name}/kir: main relation missing`);
86
+ }
87
+
88
+ function runRetyped(fixture) {
89
+ const object = decodeObject(compileObjectBuffer(fixture.program, {
90
+ source: path.relative(root, fixture.dir)
91
+ }));
92
+ const mainRel = object.rels[object.main];
93
+ const inputPatternId = mainRel.typePatternGraph.find(mainRel.def.patterns[0]);
94
+ const inputPattern = fixture.input.pattern || patternToPropertyList(exportPatternGraph(mainRel.typePatternGraph, inputPatternId));
95
+ const kir = validateKIRP(retypeObjectRelation(object, object.main, inputPattern));
96
+ if (kir.kind !== "executable") throw new Error(`${fixture.name}/retyped: expected executable KIR`);
97
+ if (!kir.rels[kir.main]) throw new Error(`${fixture.name}/retyped: main relation missing`);
98
+ }
99
+
100
+ function runMode(mode, fixture) {
101
+ if (mode === "source") return runSource(fixture);
102
+ if (mode === "object") return runObject(fixture);
103
+ if (mode === "kir") return runKIR(fixture);
104
+ if (mode === "retyped") return runRetyped(fixture);
105
+ throw new Error(`Unknown conformance mode '${mode}'`);
106
+ }
107
+
108
+ function parseArgs() {
109
+ const args = argv.slice(2);
110
+ if (args.includes("-h") || args.includes("--help")) {
111
+ usage(console.log);
112
+ exit(0);
113
+ }
114
+
115
+ let modes = DEFAULT_MODES;
116
+ const dirs = [];
117
+ while (args.length > 0) {
118
+ const arg = args.shift();
119
+ if (arg === "--mode") {
120
+ const value = args.shift();
121
+ if (!value) throw new Error("--mode requires a comma-separated list");
122
+ modes = value.split(",").map((mode) => mode.trim()).filter(Boolean);
123
+ } else if (arg.startsWith("--")) {
124
+ throw new Error(`Unknown option: ${arg}`);
125
+ } else {
126
+ dirs.push(arg);
127
+ }
128
+ }
129
+ return { modes, dirs };
130
+ }
131
+
132
+ try {
133
+ const { modes, dirs } = parseArgs();
134
+ const fixtures = fixtureDirs(dirs).map(readFixture);
135
+ let count = 0;
136
+ for (const fixture of fixtures) {
137
+ const fixtureModes = modes.filter((mode) => fixture.modes.includes(mode));
138
+ for (const mode of fixtureModes) {
139
+ runMode(mode, fixture);
140
+ count++;
141
+ console.log(`ok ${fixture.name}/${mode}`);
142
+ }
143
+ }
144
+ console.log(`OK ${count} checks`);
145
+ } catch (error) {
146
+ console.error(error.stack || error.message || String(error));
147
+ usage();
148
+ exit(1);
149
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "variant construction",
3
+ "program": "program.k",
4
+ "input": "input.kv",
5
+ "expected": "expected.kv",
6
+ "modes": ["source", "object", "kir", "retyped"],
7
+ "tags": ["runtime", "variant"]
8
+ }
@@ -0,0 +1 @@
1
+ {"some":{}}
@@ -0,0 +1 @@
1
+ |some
@@ -0,0 +1,105 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { BackendAdapter, BackendRunner } from "../backend.mjs";
4
+ import { PersistentExecutable } from "../persistent.mjs";
5
+ import { compileARM64ArtifactFromObject } from "../../backends/arm64/src/arm64.mjs";
6
+ import { decodeWire } from "../../backend-api.mjs";
7
+
8
+ class ARM64Runner extends BackendRunner {
9
+ constructor(backendId, servers = new Map()) {
10
+ super(backendId);
11
+ this.servers = servers;
12
+ }
13
+
14
+ getServer(exePath) {
15
+ let server = this.servers.get(exePath);
16
+ if (!server) {
17
+ server = new PersistentExecutable(exePath);
18
+ this.servers.set(exePath, server);
19
+ }
20
+ return server;
21
+ }
22
+
23
+ async runSingle(testCase, options = {}) {
24
+ const server = this.getServer(testCase.exePath);
25
+ if (options.trace) {
26
+ const res = await server.requestWithTrace(testCase.inputWire);
27
+ const decoded = decodeWire(res.payload);
28
+ return {
29
+ outputWire: res.payload,
30
+ outputVal: decoded.value,
31
+ outputPattern: decoded.pattern,
32
+ trace: res.trace,
33
+ profile: res.trace?.profile
34
+ };
35
+ } else {
36
+ const payload = await server.request(testCase.inputWire);
37
+ const decoded = decodeWire(payload);
38
+ return {
39
+ outputWire: payload,
40
+ outputVal: decoded.value,
41
+ outputPattern: decoded.pattern
42
+ };
43
+ }
44
+ }
45
+
46
+ async runBatch(compiledCases) {
47
+ for (const c of compiledCases) {
48
+ const server = this.getServer(c.exePath);
49
+ await server.request(c.inputWire);
50
+ }
51
+ }
52
+
53
+ async close() {
54
+ for (const server of this.servers.values()) {
55
+ server.close();
56
+ }
57
+ this.servers.clear();
58
+ }
59
+ }
60
+
61
+ export class ARM64Adapter extends BackendAdapter {
62
+ constructor(options = {}) {
63
+ const optLevel = options.optLevel || "-O2";
64
+ super("arm64", `Linux ARM64 ${optLevel} (persistent)`, options);
65
+ this.optLevel = optLevel;
66
+ }
67
+
68
+ isAvailable() {
69
+ return process.arch === "arm64" && process.platform === "linux";
70
+ }
71
+
72
+ async compile(testCase, options = {}) {
73
+ const cacheDir = options.cacheDir || path.join(process.cwd(), ".cache");
74
+ fs.mkdirSync(cacheDir, { recursive: true });
75
+ const exePath = path.join(cacheDir, `harness_arm64_${testCase.op || testCase.relName || "case"}`);
76
+
77
+ try {
78
+ compileARM64ArtifactFromObject(testCase.object, {
79
+ entry: testCase.relName || testCase.op || testCase.relationName,
80
+ inputPattern: testCase.inputPattern,
81
+ outputPattern: testCase.outputPattern,
82
+ outputPath: exePath,
83
+ optLevel: this.optLevel,
84
+ profile: Boolean(options.profile)
85
+ });
86
+
87
+ return {
88
+ status: "ok",
89
+ exePath,
90
+ inputWire: testCase.inputWire,
91
+ inputVal: testCase.inputVal,
92
+ outputPattern: testCase.outputPattern
93
+ };
94
+ } catch (error) {
95
+ return {
96
+ status: "failed",
97
+ error: error.stack || error.message || String(error)
98
+ };
99
+ }
100
+ }
101
+
102
+ async createRunner(compiledCases) {
103
+ return new ARM64Runner(this.id);
104
+ }
105
+ }
@@ -0,0 +1,144 @@
1
+ import {
2
+ codes,
3
+ decodeWire,
4
+ encodeToWire,
5
+ executeKVM,
6
+ lowerToKVM,
7
+ specializeKVM
8
+ } from "../../backend-api.mjs";
9
+ import { BackendAdapter, BackendRunner } from "../backend.mjs";
10
+
11
+ class KVMRunner extends BackendRunner {
12
+ constructor(backendId, state, options = {}) {
13
+ super(backendId);
14
+ this.state = state;
15
+ this.wire = options.wire !== false;
16
+ }
17
+
18
+ getContext(profile = null) {
19
+ return {
20
+ rels: this.state?.rels || {},
21
+ codes: this.state?.codes || {},
22
+ findCode: codes.find,
23
+ profile,
24
+ hashToName: this.state?.hashToName || null,
25
+ options: {
26
+ envelopeFree: true
27
+ }
28
+ };
29
+ }
30
+
31
+ async runSingle(testCase, options = {}) {
32
+ const profile = options.profile ? {} : null;
33
+ const context = this.getContext(profile);
34
+ const targetFunc = testCase.specKvmFunc || testCase.kvmFunc;
35
+
36
+ let inputVal = testCase.inputVal;
37
+ const t0 = process.hrtime.bigint();
38
+ let tDecode = t0;
39
+
40
+ if (this.wire && testCase.inputWire) {
41
+ const decoded = decodeWire(testCase.inputWire);
42
+ inputVal = decoded.value;
43
+ tDecode = process.hrtime.bigint();
44
+ }
45
+
46
+ const tEvalStart = process.hrtime.bigint();
47
+ const result = executeKVM(targetFunc, inputVal, context);
48
+ const tEvalEnd = process.hrtime.bigint();
49
+
50
+ let outputWire = null;
51
+ let tEncode = tEvalEnd;
52
+ if (this.wire && result !== undefined) {
53
+ const outPattern = testCase.outputPattern || targetFunc.outputPattern;
54
+ outputWire = encodeToWire(result, outPattern);
55
+ tEncode = process.hrtime.bigint();
56
+ }
57
+
58
+ const decodeNs = Number(tDecode - t0);
59
+ const evalNs = Number(tEvalEnd - tEvalStart);
60
+ const encodeNs = Number(tEncode - tEvalEnd);
61
+ const totalNs = Number(tEncode - t0);
62
+
63
+ const trace = {
64
+ ipcReadNs: 0,
65
+ decodeNs,
66
+ flatInNs: 0,
67
+ evalNs,
68
+ flatOutNs: 0,
69
+ encodeNs,
70
+ ipcWriteNs: 0,
71
+ totalNs
72
+ };
73
+
74
+ return {
75
+ outputVal: result,
76
+ outputWire,
77
+ trace,
78
+ profile
79
+ };
80
+ }
81
+
82
+ async runBatch(compiledCases) {
83
+ const context = this.getContext();
84
+ for (const c of compiledCases) {
85
+ const targetFunc = c.specKvmFunc || c.kvmFunc;
86
+ if (this.wire && c.inputWire) {
87
+ const decoded = decodeWire(c.inputWire);
88
+ const result = executeKVM(targetFunc, decoded.value, context);
89
+ if (result !== undefined) {
90
+ const outPattern = c.outputPattern || targetFunc.outputPattern;
91
+ encodeToWire(result, outPattern);
92
+ }
93
+ } else {
94
+ executeKVM(targetFunc, c.inputVal, context);
95
+ }
96
+ }
97
+ }
98
+ }
99
+
100
+ export class KVMAdapter extends BackendAdapter {
101
+ constructor(state = null, options = {}) {
102
+ const wire = options.wire !== false;
103
+ const id = options.id || (wire ? "kvm" : "kvm-pure");
104
+ const name = options.name || (wire ? "kVM Interpreter (wire codec)" : "kVM Interpreter (in-memory)");
105
+ super(id, name, options);
106
+ this.state = state;
107
+ this.wire = wire;
108
+ }
109
+
110
+ setState(state) {
111
+ this.state = state;
112
+ }
113
+
114
+ async compile(testCase, options = {}) {
115
+ try {
116
+ const kvmFunc = testCase.kvmFunc || lowerToKVM(testCase.relDef, testCase.relName || testCase.op);
117
+ let specKvmFunc = kvmFunc;
118
+ if (testCase.inputPattern) {
119
+ try {
120
+ specKvmFunc = specializeKVM(kvmFunc, testCase.inputPattern);
121
+ } catch {
122
+ specKvmFunc = kvmFunc;
123
+ }
124
+ }
125
+ return {
126
+ status: "ok",
127
+ kvmFunc,
128
+ specKvmFunc,
129
+ inputVal: testCase.inputVal,
130
+ inputWire: testCase.inputWire,
131
+ outputPattern: testCase.outputPattern
132
+ };
133
+ } catch (error) {
134
+ return {
135
+ status: "failed",
136
+ error: error.stack || error.message || String(error)
137
+ };
138
+ }
139
+ }
140
+
141
+ async createRunner(compiledCases) {
142
+ return new KVMRunner(this.id, this.state, { wire: this.wire });
143
+ }
144
+ }
@@ -0,0 +1,118 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { execSync } from "node:child_process";
4
+ import { BackendAdapter, BackendRunner } from "../backend.mjs";
5
+ import { PersistentExecutable } from "../persistent.mjs";
6
+ import { compileObjectToExecutable } from "../../backends/llvm/src/executable.mjs";
7
+ import { decodeWire } from "../../backend-api.mjs";
8
+ import { decodeObject, encodeObject } from "../../object.mjs";
9
+
10
+ function cloneObjectPayload(object) {
11
+ return decodeObject(encodeObject(object));
12
+ }
13
+
14
+ class LLVMRunner extends BackendRunner {
15
+ constructor(backendId, servers = new Map()) {
16
+ super(backendId);
17
+ this.servers = servers;
18
+ }
19
+
20
+ getServer(exePath) {
21
+ let server = this.servers.get(exePath);
22
+ if (!server) {
23
+ server = new PersistentExecutable(exePath);
24
+ this.servers.set(exePath, server);
25
+ }
26
+ return server;
27
+ }
28
+
29
+ async runSingle(testCase, options = {}) {
30
+ const server = this.getServer(testCase.exePath);
31
+ if (options.trace) {
32
+ const res = await server.requestWithTrace(testCase.inputWire);
33
+ const decoded = decodeWire(res.payload);
34
+ return {
35
+ outputWire: res.payload,
36
+ outputVal: decoded.value,
37
+ outputPattern: decoded.pattern,
38
+ trace: res.trace,
39
+ profile: res.trace?.profile
40
+ };
41
+ } else {
42
+ const payload = await server.request(testCase.inputWire);
43
+ const decoded = decodeWire(payload);
44
+ return {
45
+ outputWire: payload,
46
+ outputVal: decoded.value,
47
+ outputPattern: decoded.pattern
48
+ };
49
+ }
50
+ }
51
+
52
+ async runBatch(compiledCases) {
53
+ for (const c of compiledCases) {
54
+ const server = this.getServer(c.exePath);
55
+ await server.request(c.inputWire);
56
+ }
57
+ }
58
+
59
+ async close() {
60
+ for (const server of this.servers.values()) {
61
+ server.close();
62
+ }
63
+ this.servers.clear();
64
+ }
65
+ }
66
+
67
+ export class LLVMAdapter extends BackendAdapter {
68
+ constructor(options = {}) {
69
+ const clangOpt = options.clangOpt || "-O3";
70
+ super("llvm", `LLVM Executable (persistent, ${clangOpt})`, options);
71
+ this.clangOpt = clangOpt;
72
+ this._available = null;
73
+ }
74
+
75
+ isAvailable() {
76
+ if (this._available !== null) return this._available;
77
+ try {
78
+ execSync("which clang", { stdio: "ignore" });
79
+ this._available = true;
80
+ } catch {
81
+ this._available = false;
82
+ }
83
+ return this._available;
84
+ }
85
+
86
+ async compile(testCase, options = {}) {
87
+ const cacheDir = options.cacheDir || path.join(process.cwd(), ".cache");
88
+ fs.mkdirSync(cacheDir, { recursive: true });
89
+ const exePath = path.join(cacheDir, `harness_llvm_${testCase.op || testCase.relName || "case"}`);
90
+
91
+ try {
92
+ const relation = testCase.relName || testCase.op || testCase.relationName || testCase.object.main;
93
+ compileObjectToExecutable(cloneObjectPayload(testCase.object), exePath, {
94
+ relation,
95
+ inputPattern: testCase.inputPattern,
96
+ runtimeMode: options.runtimeMode || "fast",
97
+ clangOpt: this.clangOpt
98
+ });
99
+
100
+ return {
101
+ status: "ok",
102
+ exePath,
103
+ inputWire: testCase.inputWire,
104
+ inputVal: testCase.inputVal,
105
+ outputPattern: testCase.outputPattern
106
+ };
107
+ } catch (error) {
108
+ return {
109
+ status: "failed",
110
+ error: error.stack || error.message || String(error)
111
+ };
112
+ }
113
+ }
114
+
115
+ async createRunner(compiledCases) {
116
+ return new LLVMRunner(this.id);
117
+ }
118
+ }