@fraczak/k 6.3.3 → 6.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/DOCS/CODECS.md +258 -0
  3. package/DOCS/DICTIONARY.md +1172 -0
  4. package/DOCS/KIR_SPECIALIZATION_DESIGN.md +51 -46
  5. package/DOCS/KIR_V1.md +221 -0
  6. package/DOCS/KVM_EXECUTION_MODEL.md +56 -19
  7. package/DOCS/OBJECT_FILE_AND_PATTERN.md +2 -1
  8. package/DOCS/PROFILING_AND_TRACING.md +196 -0
  9. package/DOCS/REPL.md +61 -4
  10. package/DOCS/WEB_REPL_REQUIREMENTS.md +135 -0
  11. package/DOCS/dependency-graph.md +144 -0
  12. package/Examples/arithmetics.k +108 -82
  13. package/Examples/bnat.k +1 -1
  14. package/Examples/buda.k +44 -0
  15. package/Examples/ieee.k +300 -8671
  16. package/Examples/poly.k +67 -0
  17. package/README.md +68 -19
  18. package/Value.mjs +8 -2
  19. package/augmentation.mjs +9 -7
  20. package/backend-api.mjs +11 -2
  21. package/backends/arm64/README.md +104 -0
  22. package/backends/arm64/bin/k-arm64-compile.mjs +101 -0
  23. package/backends/arm64/bin/k-arm64-run.mjs +58 -0
  24. package/backends/arm64/bin/k-arm64.mjs +88 -0
  25. package/backends/arm64/scripts/run-tests.mjs +41 -0
  26. package/backends/arm64/src/arm64.mjs +229 -0
  27. package/backends/arm64/src/cli.mjs +155 -0
  28. package/backends/arm64/src/kvm2arm64.mjs +906 -0
  29. package/backends/arm64/src/runtime.c +728 -0
  30. package/backends/arm64/tests/integration.sh +112 -0
  31. package/backends/arm64/tests/test-arm64.mjs +240 -0
  32. package/backends/llvm/README.md +135 -0
  33. package/backends/llvm/bin/k-llvm-build.mjs +71 -0
  34. package/backends/llvm/bin/k-llvm-compile.mjs +68 -0
  35. package/backends/llvm/bin/k-llvm-jit.mjs +160 -0
  36. package/backends/llvm/bin/k-llvm-run.mjs +90 -0
  37. package/backends/llvm/runtime/krt.c +1508 -0
  38. package/backends/llvm/runtime/krt.h +109 -0
  39. package/backends/llvm/scripts/conformance.mjs +76 -0
  40. package/backends/llvm/scripts/run-tests.mjs +28 -0
  41. package/backends/llvm/src/executable.mjs +562 -0
  42. package/backends/llvm/src/kvm2llvm.mjs +998 -0
  43. package/backends/llvm/src/llvm.mjs +1092 -0
  44. package/backends/llvm/tests/composition-driver.c +22 -0
  45. package/backends/llvm/tests/identity-driver.c +27 -0
  46. package/backends/llvm/tests/integration.sh +153 -0
  47. package/backends/llvm/tests/perf-support.mjs +735 -0
  48. package/backends/llvm/tests/product-driver.c +23 -0
  49. package/backends/llvm/tests/projection-driver.c +19 -0
  50. package/backends/llvm/tests/relation-driver.c +29 -0
  51. package/backends/llvm/tests/test-llvm.mjs +240 -0
  52. package/backends/llvm/tests/union-driver.c +31 -0
  53. package/backends/llvm/tests/variant-driver.c +19 -0
  54. package/backends/llvm/tests/variant-projection-driver.c +21 -0
  55. package/backends/wasm/DOCS/USE-WEB-ASSEMBLY.md +233 -0
  56. package/backends/wasm/README.md +97 -0
  57. package/backends/wasm/TECHNICAL-DEBT.md +58 -0
  58. package/backends/wasm/bin/k-wasm-compile.mjs +50 -0
  59. package/backends/wasm/bin/k-wasm-run.mjs +140 -0
  60. package/backends/wasm/bin/k-wasm.mjs +49 -0
  61. package/backends/wasm/demo_ieee.mjs +319 -0
  62. package/backends/wasm/runtime.wat +475 -0
  63. package/backends/wasm/scripts/run-tests.mjs +41 -0
  64. package/backends/wasm/src/cli.mjs +133 -0
  65. package/backends/wasm/src/kvm2wasm.mjs +697 -0
  66. package/backends/wasm/src/wasm.mjs +1054 -0
  67. package/backends/wasm/tests/integration.sh +182 -0
  68. package/backends/wasm/tests/perf-support.mjs +336 -0
  69. package/backends/wasm/tests/test-wasm.mjs +625 -0
  70. package/browser/repl-browser.mjs +1584 -0
  71. package/browser/shims/assert.mjs +19 -0
  72. package/browser/shims/buffer.mjs +224 -0
  73. package/browser/shims/crypto.mjs +103 -0
  74. package/browser/shims/fs.mjs +159 -0
  75. package/browser/shims/os.mjs +17 -0
  76. package/browser/shims/path.mjs +54 -0
  77. package/browser/shims/process.mjs +44 -0
  78. package/browser/shims/readline.mjs +11 -0
  79. package/browser/shims/url.mjs +12 -0
  80. package/browser/vfs-data.mjs +19 -0
  81. package/codecs/README.md +3 -0
  82. package/codecs/runtime/show-value.mjs +12 -3
  83. package/conformance/helper-reuse/case.json +8 -0
  84. package/conformance/helper-reuse/expected.kv +1 -0
  85. package/conformance/helper-reuse/input.kv +1 -0
  86. package/conformance/helper-reuse/program.k +2 -0
  87. package/conformance/identity/case.json +8 -0
  88. package/conformance/identity/expected.kv +1 -0
  89. package/conformance/identity/input.kv +1 -0
  90. package/conformance/identity/program.k +1 -0
  91. package/conformance/product-projection/case.json +8 -0
  92. package/conformance/product-projection/expected.kv +1 -0
  93. package/conformance/product-projection/input.kv +1 -0
  94. package/conformance/product-projection/program.k +1 -0
  95. package/conformance/run.mjs +149 -0
  96. package/conformance/variant-construction/case.json +8 -0
  97. package/conformance/variant-construction/expected.kv +1 -0
  98. package/conformance/variant-construction/input.kv +1 -0
  99. package/conformance/variant-construction/program.k +1 -0
  100. package/harness/adapters/arm64.mjs +105 -0
  101. package/harness/adapters/kvm.mjs +144 -0
  102. package/harness/adapters/llvm.mjs +118 -0
  103. package/harness/adapters/native.mjs +77 -0
  104. package/harness/adapters/wasm.mjs +169 -0
  105. package/harness/backend.mjs +95 -0
  106. package/harness/cli.mjs +130 -0
  107. package/harness/format.mjs +95 -0
  108. package/harness/index.mjs +25 -0
  109. package/harness/persistent.mjs +121 -0
  110. package/harness/registry.mjs +44 -0
  111. package/harness/suite.mjs +257 -0
  112. package/harness/suites/poly.mjs +156 -0
  113. package/harness/trace.mjs +50 -0
  114. package/harness/util.mjs +92 -0
  115. package/intrinsics.mjs +41 -0
  116. package/kir.mjs +399 -0
  117. package/kvm.mjs +585 -81
  118. package/objects/README.md +37 -3
  119. package/objects/compile.mjs +15 -22
  120. package/objects/inspect.mjs +96 -0
  121. package/objects/validate.mjs +415 -0
  122. package/package.json +51 -19
  123. package/repl-codecs.mjs +105 -6
  124. package/repl.mjs +335 -49
  125. package/run.mjs +2 -7
  126. package/scripts/benchmark.mjs +406 -22
  127. package/scripts/build-repl-html.mjs +1784 -0
  128. package/scripts/perf-ieee.mjs +586 -0
  129. package/scripts/perf-int.mjs +531 -0
  130. package/scripts/perf-poly.mjs +945 -0
  131. package/scripts/render-benchmark.mjs +12 -8
  132. package/scripts/run-tests.mjs +6 -0
  133. package/tests/integration.sh +19 -2
  134. package/tests/test-arithmetics.mjs +54 -0
  135. package/tests/test-ieee-arithmetic.mjs +4 -0
  136. package/tests/test-kir.mjs +85 -0
  137. package/tests/test-kvm-polymorphic.mjs +278 -0
  138. package/tests/test-kvm.mjs +25 -6
  139. package/tests/test-poly.mjs +129 -0
  140. package/tests/test-repl-html.mjs +303 -0
  141. package/tests/test-repl.mjs +144 -1
  142. package/tests/test-validate-object.mjs +40 -0
  143. package/a.klib +0 -1
  144. package/a.kvm +0 -142676
  145. package/a.wasm +0 -0
  146. package/benchmark-results.html +0 -532
  147. package/benchmark-results.json +0 -480
  148. package/k-vscode/.vscode/launch.json +0 -14
  149. package/k-vscode/README.md +0 -75
  150. package/k-vscode/extension.js +0 -273
  151. package/k-vscode/language-configuration.json +0 -42
  152. package/k-vscode/package.json +0 -79
  153. package/k-vscode/snippets/k.json +0 -92
  154. package/k-vscode/syntaxes/k.tmLanguage.json +0 -599
  155. package/k-vscode/test/background-ranges.test.js +0 -50
  156. package/k-vscode/themes/k-contrast-color-theme.json +0 -104
  157. package/scripts/git-hooks/pre-commit +0 -10
@@ -0,0 +1,319 @@
1
+ import fs from "node:fs";
2
+ import assert from "node:assert/strict";
3
+ import wabtFactory from "wabt";
4
+ import {
5
+ codes,
6
+ createState,
7
+ evaluateInput,
8
+ executeKVM,
9
+ exportPatternGraph,
10
+ fromObject,
11
+ isProduct,
12
+ isVariant,
13
+ lowerToKVM,
14
+ parseFloat64,
15
+ patternToPropertyList,
16
+ printFloat64,
17
+ propertyListToPattern,
18
+ valueForCode,
19
+ Value
20
+ } from "@fraczak/k/backend-api.mjs";
21
+ import { lowerToWasm, getTagId, getTagFromId, getFuncNameFromId } from "./src/kvm2wasm.mjs";
22
+
23
+ console.log("==> Starting Wasm IEEE-754 Square Demo");
24
+
25
+ // Initialize WABT
26
+ const wabtInstance = await wabtFactory();
27
+
28
+ function compileWat(filename, watText) {
29
+ const watModule = wabtInstance.parseWat(filename, watText, {
30
+ mutable_globals: true,
31
+ sat_float_to_int: true,
32
+ sign_extension: true,
33
+ multi_value: true,
34
+ bulk_memory: true,
35
+ reference_types: true
36
+ });
37
+ watModule.resolveNames();
38
+ watModule.validate();
39
+ const binary = watModule.toBinary({
40
+ log: false,
41
+ canonicalize_lebs: true,
42
+ relocatable: false,
43
+ write_debug_names: true
44
+ });
45
+ return binary.buffer;
46
+ }
47
+
48
+ // 1. Create REPL state and load ieee.k library
49
+ console.log("Loading IEEE-754 arithmetic library (@fraczak/k/Examples/ieee.k)...");
50
+ const state = createState();
51
+ const ieeePath = fileURLToPath(import.meta.resolve("@fraczak/k/Examples/ieee.k"));
52
+ await evaluateInput(`:load ${ieeePath}`, state);
53
+
54
+ // 2. Define the squaring relation: square = { () x, () y } mul;
55
+ console.log("Defining relation: square = { () x, () y } mul;");
56
+ await evaluateInput("square = { () x, () y } mul;", state);
57
+ await evaluateInput("get_sign = $float64 .sign;", state);
58
+
59
+ // 3. Compile and Link relations recursively starting from square
60
+ console.log("Compiling and linking Wasm module...");
61
+
62
+ const cleanName = (h) => "rel_" + h.replace(/[^a-zA-Z0-9_]/g, "_");
63
+
64
+ function compileModule(mainRelHash) {
65
+ const compiled = new Set();
66
+ const queue = [mainRelHash];
67
+ const wats = [];
68
+
69
+ while (queue.length > 0) {
70
+ const hash = queue.shift();
71
+ if (compiled.has(hash)) continue;
72
+ compiled.add(hash);
73
+
74
+ const relDef = state.rels[hash];
75
+ if (!relDef) {
76
+ throw new Error(`Relation hash ${hash} not found`);
77
+ }
78
+
79
+ const kvmFunc = lowerToKVM(relDef, hash);
80
+ kvmFunc.typePatternGraph = relDef.typePatternGraph;
81
+
82
+ // Scan for call dependencies using raw hashes
83
+ for (const inst of kvmFunc.body) {
84
+ if (inst.op === "call") {
85
+ if (!compiled.has(inst.func) && !queue.includes(inst.func)) {
86
+ queue.push(inst.func);
87
+ }
88
+ }
89
+ if (inst.op === "call_intrinsic") {
90
+ console.log(`FOUND INTRINSIC: ${inst.symbol} in relation ${hash}`);
91
+ }
92
+ if (inst.branches) {
93
+ const scan = (insts) => {
94
+ for (const sub of insts) {
95
+ if (sub.op === "call") {
96
+ if (!compiled.has(sub.func) && !queue.includes(sub.func)) {
97
+ queue.push(sub.func);
98
+ }
99
+ }
100
+ if (sub.op === "call_intrinsic") {
101
+ console.log(`FOUND INTRINSIC: ${sub.symbol} in relation ${hash}`);
102
+ }
103
+ if (sub.branches) {
104
+ for (const br of sub.branches) {
105
+ scan(br.body);
106
+ }
107
+ }
108
+ }
109
+ };
110
+ for (const br of inst.branches) {
111
+ scan(br.body);
112
+ }
113
+ }
114
+ }
115
+
116
+ // Rename functions in KVM IR to valid Wasm identifiers
117
+ kvmFunc.name = cleanName(hash);
118
+ const cleanInsts = (insts) => {
119
+ for (const inst of insts) {
120
+ if (inst.op === "call") {
121
+ inst.func = cleanName(inst.func);
122
+ }
123
+ if (inst.branches) {
124
+ for (const br of inst.branches) {
125
+ cleanInsts(br.body);
126
+ }
127
+ }
128
+ }
129
+ };
130
+ cleanInsts(kvmFunc.body);
131
+
132
+ const wat = lowerToWasm(kvmFunc, kvmFunc.name, { trace: true });
133
+ if (hash === squareHash) {
134
+ console.log("==> KVM IR for square:", JSON.stringify(kvmFunc.body, null, 2));
135
+ console.log("==> Compiled WAT for square:\n", wat);
136
+ }
137
+ wats.push(wat);
138
+ }
139
+
140
+ return wats.join("\n\n");
141
+ }
142
+
143
+ const squareHash = state.relAliases["square"];
144
+ const getSignHash = state.relAliases["get_sign"];
145
+ const moduleWatBody = compileModule(squareHash);
146
+ const getSignWat = lowerToWasm(state.rels[getSignHash], "get_sign", { trace: true });
147
+ console.log("==> Compiled WAT for get_sign:\n", getSignWat);
148
+ const runtimeWat = fs.readFileSync("runtime.wat", "utf8");
149
+
150
+ // Combine Wasm runtime and compiled relations
151
+ const declarations = `
152
+ (import "env" "log_call" (func $log_call (param i32 i32)))
153
+ (import "env" "log_ret" (func $log_ret (param i32 i32 i32)))
154
+ `;
155
+ const runtimeWatWithImports = runtimeWat.replace("(module", "(module\n" + declarations);
156
+ const fullWat = runtimeWatWithImports.trim().slice(0, -1) + "\n" + moduleWatBody + "\n" + getSignWat + "\n)";
157
+ fs.writeFileSync("debug_full.wat", fullWat);
158
+ const binary = compileWat("square_demo.wat", fullWat);
159
+ const module = await WebAssembly.compile(binary);
160
+ const imports = {
161
+ env: {
162
+ log_call: (funcId, ptrIn) => {
163
+ const funcName = getFuncNameFromId(funcId);
164
+ console.log(`[Wasm Trace] Calling ${funcName} with input ptr ${ptrIn}`);
165
+ },
166
+ log_ret: (funcId, ptrOut, ok) => {
167
+ const funcName = getFuncNameFromId(funcId);
168
+ console.log(`[Wasm Trace] Returned from ${funcName} -> ptr ${ptrOut}, ok ${ok}`);
169
+ }
170
+ }
171
+ };
172
+ const instance = await WebAssembly.instantiate(module, imports);
173
+ const exports = instance.exports;
174
+
175
+ // JS Arena helpers
176
+ function readArenaValue(exports, ptr, pattern, patternNodeId) {
177
+ const patternNode = pattern.nodes[patternNodeId];
178
+ const view = new DataView(exports.memory.buffer);
179
+
180
+ if (patternNode.kind === 1 || patternNode.kind === 3) {
181
+ const size = view.getUint32(ptr, true);
182
+ const N = view.getUint32(ptr + 4, true);
183
+ const productObj = {};
184
+
185
+ for (let i = 0; i < N; i++) {
186
+ const edge = patternNode.edges[i];
187
+ const offsetVal = view.getUint32(ptr + 8 + 4 * i, true);
188
+ const childPtr = view.getUint32(ptr + offsetVal, true);
189
+ productObj[edge.label] = readArenaValue(exports, childPtr, pattern, edge.target);
190
+ }
191
+ return Value.product(productObj, pattern);
192
+ } else if (patternNode.kind === 2 || patternNode.kind === 4) {
193
+ const size = view.getUint32(ptr, true);
194
+ const tagId = view.getUint32(ptr + 4, true);
195
+ const payloadPtr = view.getUint32(ptr + 8, true);
196
+
197
+ const tag = getTagFromId(tagId);
198
+ console.log(`[Debug Arena] Read Variant at ptr=${ptr}: size=${size}, tagId=${tagId}, tag=${tag}`);
199
+ const edge = patternNode.edges.find(e => e.label === tag);
200
+ if (!edge) {
201
+ throw new Error(`Variant tag '${tag}' not found in pattern edges`);
202
+ }
203
+ const payloadVal = readArenaValue(exports, payloadPtr, pattern, edge.target);
204
+ return Value.variant(tag, payloadVal, pattern);
205
+ }
206
+ throw new Error(`Unsupported pattern kind: ${patternNode.kind}`);
207
+ }
208
+
209
+ function writeValueToArena(value, pattern, patternNodeId) {
210
+ const patternNode = pattern.nodes[patternNodeId];
211
+
212
+ if (isProduct(value)) {
213
+ const keys = Object.keys(value.product).sort();
214
+ const N = keys.length;
215
+ const totalSize = 8 + 8 * N;
216
+
217
+ // Evaluate and allocate all children first
218
+ const childPtrs = [];
219
+ for (let i = 0; i < N; i++) {
220
+ const label = keys[i];
221
+ const edge = patternNode.edges.find(e => e.label === label);
222
+ const childPtr = writeValueToArena(value.product[label], pattern, edge.target);
223
+ childPtrs.push(childPtr);
224
+ }
225
+
226
+ const ptr = exports.alloc(totalSize);
227
+ const view = new DataView(exports.memory.buffer);
228
+
229
+ view.setUint32(ptr, totalSize, true);
230
+ view.setUint32(ptr + 4, N, true);
231
+
232
+ for (let i = 0; i < N; i++) {
233
+ const offsetVal = 8 + 4 * N + 4 * i;
234
+ view.setUint32(ptr + 8 + 4 * i, offsetVal, true);
235
+ view.setUint32(ptr + offsetVal, childPtrs[i], true);
236
+ }
237
+ return ptr;
238
+ } else if (isVariant(value)) {
239
+ const tagId = getTagId(value.tag);
240
+ const edge = patternNode.edges.find(e => e.label === value.tag);
241
+ const childPtr = writeValueToArena(value.value, pattern, edge.target);
242
+
243
+ const ptr = exports.alloc(12);
244
+ const view = new DataView(exports.memory.buffer);
245
+
246
+ view.setUint32(ptr, 12, true);
247
+ view.setUint32(ptr + 4, tagId, true);
248
+ view.setUint32(ptr + 8, childPtr, true);
249
+ console.log(`[Debug Arena] Wrote Variant at ptr=${ptr}: tag=${value.tag}, tagId=${tagId}`);
250
+ return ptr;
251
+ }
252
+ throw new Error(`Unsupported value type: ${value}`);
253
+ }
254
+
255
+ function getPattern(graph, patternId) {
256
+ const nodeId = graph.find(patternId);
257
+ return propertyListToPattern(patternToPropertyList(exportPatternGraph(graph, nodeId)));
258
+ }
259
+
260
+ // 4. Run on an input
261
+ const inputValStr = "1.5";
262
+ console.log(`\nInput float64 value: ${inputValStr}`);
263
+
264
+ // Convert input string to IEEE float64 tree
265
+ const float64Hash = state.typeAliases.float64;
266
+ const parsedFloatVal = valueForCode(parseFloat64(inputValStr), float64Hash, codes.find);
267
+
268
+ // Resolve patterns
269
+ const squareRel = state.rels[squareHash];
270
+ const graph = squareRel.typePatternGraph;
271
+ const inputPattern = getPattern(graph, squareRel.def.patterns[0]);
272
+ const outputPattern = getPattern(graph, squareRel.def.patterns[1]);
273
+
274
+ // Run the JS interpreter first to check
275
+ const kvmFuncSquare = lowerToKVM(squareRel, squareHash);
276
+ const context = { rels: state.rels, findCode: codes.find, options: { envelopeFree: true, trace: false } };
277
+ const jsRes = executeKVM(kvmFuncSquare, parsedFloatVal, context);
278
+ console.log("JS Interpreter result:", jsRes ? printFloat64(jsRes.product.result) : "failed");
279
+
280
+ // Print keys and patterns for debugging
281
+ console.log("==> parsedFloatVal keys:", Object.keys(parsedFloatVal.product));
282
+ console.log("==> inputPattern node 0:", JSON.stringify(inputPattern.nodes[0], null, 2));
283
+ console.log("==> outputPattern node 0:", JSON.stringify(outputPattern.nodes[0], null, 2));
284
+
285
+ // Write input to the arena
286
+ const ptrIn = writeValueToArena(parsedFloatVal, inputPattern, 0);
287
+
288
+ // Call get_sign to test basic projection
289
+ console.log("Calling Wasm function 'get_sign'...");
290
+ const getSignRes = exports.get_sign(ptrIn);
291
+ if (getSignRes[1] === 1) {
292
+ const getSignRel = state.rels[getSignHash];
293
+ const getSignPattern = getPattern(getSignRel.typePatternGraph, getSignRel.def.patterns[1]);
294
+ const getSignVal = readArenaValue(exports, getSignRes[0], getSignPattern, 0);
295
+ console.log("get_sign output tag:", getSignVal.tag);
296
+ } else {
297
+ console.log("get_sign failed!");
298
+ }
299
+
300
+ // Run the Wasm function
301
+ console.log("Calling Wasm function 'square'...");
302
+ const mainFuncName = cleanName(squareHash);
303
+ const result = exports[mainFuncName](ptrIn);
304
+
305
+ if (result[1] !== 1) {
306
+ console.error("Wasm execution failed!");
307
+ process.exit(1);
308
+ }
309
+
310
+ // Read and decode output from the arena
311
+ const outputVal = readArenaValue(exports, result[0], outputPattern, 0);
312
+
313
+ // Print the result using ieee print float64 codec helper
314
+ const outputResultFloat = outputVal.product.result;
315
+ const printResult = printFloat64(outputResultFloat);
316
+
317
+ console.log(`Result of (${inputValStr} * ${inputValStr}): ${printResult}`);
318
+ console.log("Flags:", outputVal.product.flags.tag);
319
+ console.log("==> Demo finished successfully!");