@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,23 @@
1
+ #include "krt.h"
2
+
3
+ extern k_result k_main(k_rt *rt, k_value *input);
4
+
5
+ int main(void) {
6
+ k_rt *rt = k_rt_new();
7
+ if (rt == NULL) return 1;
8
+
9
+ k_value *unit = k_unit(rt);
10
+ k_value *val_a = k_variant(rt, "A", unit);
11
+ k_value *val_b = k_variant(rt, "B", unit);
12
+ k_value *input = k_product(rt, 2);
13
+ k_product_set(input, "x", val_a);
14
+ k_product_set(input, "y", val_b);
15
+
16
+ k_result result = k_main(rt, input);
17
+ if (result.status != K_STATUS_OK) return 2;
18
+ if (k_product_get(result.value, "fieldA") != val_a) return 3;
19
+ if (k_product_get(result.value, "fieldB") != val_b) return 4;
20
+
21
+ k_rt_free(rt);
22
+ return 0;
23
+ }
@@ -0,0 +1,19 @@
1
+ #include "krt.h"
2
+
3
+ extern k_result k_main(k_rt *rt, k_value *input);
4
+
5
+ int main(void) {
6
+ k_rt *rt = k_rt_new();
7
+ if (rt == NULL) return 1;
8
+
9
+ k_value *unit = k_unit(rt);
10
+ k_value *input = k_product(rt, 1);
11
+ k_product_set(input, "x", unit);
12
+
13
+ k_result result = k_main(rt, input);
14
+ if (result.status != K_STATUS_OK) return 2;
15
+ if (result.value != unit) return 3;
16
+
17
+ k_rt_free(rt);
18
+ return 0;
19
+ }
@@ -0,0 +1,29 @@
1
+ #include "krt.h"
2
+
3
+ extern k_result k_main(k_rt *rt, k_value *input);
4
+
5
+ int main(void) {
6
+ k_rt *rt = k_rt_new();
7
+ if (rt == NULL) return 1;
8
+
9
+ k_value *unit = k_unit(rt);
10
+ k_value *left_value = k_variant(rt, "left", unit);
11
+ k_value *right_value = k_variant(rt, "right", unit);
12
+
13
+ k_value *a = k_product(rt, 1);
14
+ k_product_set(a, "x", left_value);
15
+ k_value *b = k_product(rt, 1);
16
+ k_product_set(b, "x", right_value);
17
+
18
+ k_value *input = k_product(rt, 2);
19
+ k_product_set(input, "a", a);
20
+ k_product_set(input, "b", b);
21
+
22
+ k_result result = k_main(rt, input);
23
+ if (result.status != K_STATUS_OK) return 2;
24
+ if (k_product_get(result.value, "left") != left_value) return 3;
25
+ if (k_product_get(result.value, "right") != right_value) return 4;
26
+
27
+ k_rt_free(rt);
28
+ return 0;
29
+ }
@@ -0,0 +1,240 @@
1
+ import assert from "node:assert";
2
+ import { compileObjectBuffer, decodeObject } from "@fraczak/k/object.mjs";
3
+ import { compileObjectToLLVM, emitLLVMModule, llvmIdentifier } from "../src/llvm.mjs";
4
+
5
+ function kirP(body, { patternGraph = null } = {}) {
6
+ return {
7
+ format: "k-ir",
8
+ version: 1,
9
+ layer: "KIR-P",
10
+ sourceFormat: "test",
11
+ kind: "executable",
12
+ main: "__main__",
13
+ codes: {},
14
+ rels: {
15
+ __main__: {
16
+ inputPattern: 0,
17
+ outputPattern: 1,
18
+ typeDerivation: { status: "converged" },
19
+ ...(patternGraph ? { patternGraph } : {}),
20
+ body
21
+ }
22
+ },
23
+ relAlias: {},
24
+ compileStats: {},
25
+ meta: {}
26
+ };
27
+ }
28
+
29
+ const object = decodeObject(compileObjectBuffer("()", { source: "llvm-test.k" }));
30
+ const { kir, relation, inputPattern, outputPattern, llvm } = compileObjectToLLVM(object, {
31
+ inputPattern: [["open-product", []]]
32
+ });
33
+
34
+ assert.equal(kir.layer, "KIR-P");
35
+ assert.equal(kir.kind, "executable");
36
+ assert.equal(kir.main, "__main__");
37
+ assert.equal(relation, "__main__");
38
+ assert.deepEqual(inputPattern, [["open-product", []]]);
39
+ assert.deepEqual(outputPattern, [["open-product", []]]);
40
+ assert(!("instanceKey" in kir));
41
+ assert(!("callSites" in kir));
42
+ assert.match(llvm, /^; k-llvm prototype artifact/m);
43
+ assert.match(llvm, /@k_llvm_metadata = private unnamed_addr constant/);
44
+ assert.match(llvm, /%k_rt_mark = type \{ ptr, i64 \}/);
45
+ assert.match(llvm, /%k_result = type \{ i32, ptr \}/);
46
+ assert.match(llvm, /declare %k_rt_mark @k_rt_mark\(ptr\)/);
47
+ assert.match(llvm, /declare void @k_rt_rewind\(ptr, %k_rt_mark\)/);
48
+ assert.match(llvm, /declare ptr @k_rt_alloc\(ptr, i64\)/);
49
+ assert.match(llvm, /declare ptr @k_bit0\(ptr\)/);
50
+ assert.match(llvm, /declare ptr @k_bit1\(ptr\)/);
51
+ assert.match(llvm, /declare ptr @k_variant_borrowed_direct_n\(ptr, ptr, i64, ptr\)/);
52
+ assert.match(llvm, /declare ptr @k_variant_unit_borrowed_n\(ptr, ptr, i64\)/);
53
+ assert.match(llvm, /declare ptr @k_product_get_n\(ptr, ptr, i64\)/);
54
+ assert.match(llvm, /declare ptr @k_product_get_at\(ptr, i64\)/);
55
+ assert.match(llvm, /declare void @k_product_set_borrowed_n\(ptr, ptr, i64, ptr\)/);
56
+ assert.match(llvm, /declare void @k_product_set_at\(ptr, i64, ptr, i64, ptr\)/);
57
+ assert.match(llvm, /define %k_result @k_main\(ptr %rt, ptr %input\)/);
58
+ assert.match(llvm, /insertvalue %k_result undef, i32 0, 0/);
59
+ assert.match(llvm, /insertvalue %k_result %status\d+, ptr %input, 1/);
60
+
61
+ const custom = emitLLVMModule(kir, { symbol: "rel name!" });
62
+ assert.match(custom, /source_filename = "k-llvm:rel_name_"/);
63
+ assert.equal(llvmIdentifier("a b/c"), "a_b_c");
64
+
65
+ const filterLLVM = emitLLVMModule(kirP({
66
+ op: "comp",
67
+ items: [
68
+ {
69
+ op: "filter",
70
+ filter: ["closed-product", []],
71
+ patterns: [0, 0]
72
+ },
73
+ {
74
+ op: "code",
75
+ code: "@code",
76
+ patterns: [0, 0]
77
+ }
78
+ ],
79
+ patterns: [0, 0]
80
+ }));
81
+ assert.match(filterLLVM, /insertvalue %k_result %status\d+, ptr %input, 1/);
82
+ assert.doesNotMatch(filterLLVM, /k_filter/);
83
+ assert.doesNotMatch(filterLLVM, /k_code/);
84
+
85
+ const projectionObject = decodeObject(compileObjectBuffer(".x", { source: "llvm-projection.k" }));
86
+ const { llvm: projectionLLVM } = compileObjectToLLVM(projectionObject, {
87
+ inputPattern: [
88
+ ["closed-product", [["x", 1]]],
89
+ ["closed-product", []]
90
+ ]
91
+ });
92
+ assert.match(projectionLLVM, /load i32, ptr %product_kind_slot\d+/);
93
+ assert.match(projectionLLVM, /load ptr, ptr %product_fields_ptr_slot\d+/);
94
+ assert.doesNotMatch(projectionLLVM, /call ptr @k_product_get_at\(ptr %(?:input|tail_input), i64 0\)/);
95
+
96
+ const productObject = decodeObject(compileObjectBuffer("{ .x fieldA, .y fieldB }", { source: "llvm-product.k" }));
97
+ const { llvm: productLLVM } = compileObjectToLLVM(productObject, {
98
+ inputPattern: [
99
+ ["closed-product", [["x", 1], ["y", 2]]],
100
+ ["closed-product", [["valA", 1]]],
101
+ ["closed-product", [["valB", 2]]]
102
+ ]
103
+ });
104
+ assert.match(productLLVM, /store i32 1, ptr %i32_slot\d+/);
105
+ assert.match(productLLVM, /store i64 2, ptr %i64_slot\d+/);
106
+ assert.match(productLLVM, /store ptr %product_fields\d+, ptr %ptr_slot\d+/);
107
+ assert.doesNotMatch(productLLVM, /call ptr @k_product\(ptr %rt/);
108
+ assert.doesNotMatch(productLLVM, /call void @k_product_set_at\(ptr %product\d+/);
109
+
110
+ const variantObject = decodeObject(compileObjectBuffer("|tag", { source: "llvm-variant.k" }));
111
+ const { llvm: variantLLVM } = compileObjectToLLVM(variantObject, {
112
+ inputPattern: [["closed-product", []]]
113
+ });
114
+ assert.match(variantLLVM, /call ptr @k_rt_alloc\(ptr %rt, i64 40\)/);
115
+ assert.match(variantLLVM, /store i32 2, ptr %i32_slot\d+/);
116
+ assert.match(variantLLVM, /store ptr %(?:input|tail_input), ptr %ptr_slot\d+/);
117
+ assert.doesNotMatch(variantLLVM, /call ptr @k_variant_borrowed_direct_n\(ptr %rt/);
118
+
119
+ const variantProjectionObject = decodeObject(compileObjectBuffer("/tag", { source: "llvm-variant-projection.k" }));
120
+ const { llvm: variantProjectionLLVM } = compileObjectToLLVM(variantProjectionObject, {
121
+ inputPattern: [
122
+ ["closed-union", [["tag", 1]]],
123
+ ["closed-product", []]
124
+ ]
125
+ });
126
+ assert.match(variantProjectionLLVM, /load i32, ptr %tag_kind_slot\d+/);
127
+ assert.match(variantProjectionLLVM, /icmp eq i64 %tag_length\d+, 3/);
128
+ assert.match(variantProjectionLLVM, /load i8, ptr %tag_byte_ptr\d+/);
129
+ assert.match(variantProjectionLLVM, /load ptr, ptr %payload_slot\d+/);
130
+ assert.doesNotMatch(variantProjectionLLVM, /call i32 @k_variant_tag_matches\(ptr %(?:input|tail_input)/);
131
+ assert.doesNotMatch(variantProjectionLLVM, /call ptr @k_variant_payload\(ptr %(?:input|tail_input)\)/);
132
+
133
+ const bitLLVM = emitLLVMModule(kirP({
134
+ op: "comp",
135
+ items: [
136
+ { op: "product", fields: [], patterns: [0, 1] },
137
+ { op: "vid", tag: "1", patterns: [1, 2] }
138
+ ],
139
+ patterns: [0, 2]
140
+ }, {
141
+ patternGraph: {
142
+ nodes: [
143
+ { id: 0, kind: "closed-product", edges: [] },
144
+ { id: 1, kind: "closed-product", edges: [] },
145
+ { id: 2, kind: "closed-union", edges: [{ label: "1", target: 1 }] }
146
+ ]
147
+ }
148
+ }));
149
+ assert.match(bitLLVM, /load ptr, ptr %rt_bit1_slot\d+/);
150
+ assert.match(bitLLVM, /store ptr %raw_alloc\d+, ptr %rt_bit1_slot\d+/);
151
+ assert.doesNotMatch(bitLLVM, /call ptr @k_bit1\(ptr %rt\)/);
152
+ assert.doesNotMatch(bitLLVM, /call ptr @k_unit\(ptr %rt\)/);
153
+ assert.doesNotMatch(bitLLVM, /call ptr @k_variant_borrowed_n\(ptr %rt/);
154
+
155
+ const unitVariantLLVM = emitLLVMModule(kirP({
156
+ op: "comp",
157
+ items: [
158
+ { op: "product", fields: [], patterns: [0, 1] },
159
+ { op: "vid", tag: "nil", patterns: [1, 2] }
160
+ ],
161
+ patterns: [0, 2]
162
+ }, {
163
+ patternGraph: {
164
+ nodes: [
165
+ { id: 0, kind: "closed-product", edges: [] },
166
+ { id: 1, kind: "closed-product", edges: [] },
167
+ { id: 2, kind: "closed-union", edges: [{ label: "nil", target: 1 }] }
168
+ ]
169
+ }
170
+ }));
171
+ assert.match(unitVariantLLVM, /load ptr, ptr %rt_unit_slot\d+/);
172
+ assert.match(unitVariantLLVM, /store ptr %raw_alloc\d+, ptr %rt_unit_slot\d+/);
173
+ assert.doesNotMatch(unitVariantLLVM, /call ptr @k_unit\(ptr %rt\)/);
174
+ assert.match(unitVariantLLVM, /call ptr @k_rt_alloc\(ptr %rt, i64 40\)/);
175
+ assert.doesNotMatch(unitVariantLLVM, /call ptr @k_variant_unit_borrowed_n\(ptr %rt/);
176
+
177
+ const compositionObject = decodeObject(compileObjectBuffer("(.x .y)", { source: "llvm-composition.k" }));
178
+ const { llvm: compositionLLVM } = compileObjectToLLVM(compositionObject, {
179
+ inputPattern: [
180
+ ["closed-product", [["x", 1]]],
181
+ ["closed-product", [["y", 2]]],
182
+ ["closed-product", []]
183
+ ]
184
+ });
185
+ assert.match(compositionLLVM, /load ptr, ptr %product_fields_ptr_slot\d+/);
186
+ assert.doesNotMatch(compositionLLVM, /call ptr @k_product_get_at\(ptr %(?:input|tail_input), i64 0\)/);
187
+ assert.doesNotMatch(compositionLLVM, /call ptr @k_product_get_at\(ptr %field\d+, i64 0\)/);
188
+
189
+ const relationObject = decodeObject(compileObjectBuffer("pick = .x; {.a pick left, .b pick right}", { source: "llvm-relation.k" }));
190
+ const { llvm: relationLLVM } = compileObjectToLLVM(relationObject, {
191
+ inputPattern: [
192
+ ["open-product", [["a", 1], ["b", 2]]],
193
+ ["open-product", [["x", 3]]],
194
+ ["open-product", [["x", 4]]],
195
+ ["closed-product", []],
196
+ ["closed-product", []]
197
+ ]
198
+ });
199
+ assert.match(relationLLVM, /define internal %k_result @k_rel_pick_\d+\(ptr %rt, ptr %input\)/);
200
+ assert.match(relationLLVM, /call %k_result @k_rel_pick_\d+\(ptr %rt, ptr %field_value\d+\)/);
201
+ assert.match(relationLLVM, /extractvalue %k_result %call\d+, 0/);
202
+ assert.match(relationLLVM, /extractvalue %k_result %call\d+, 1/);
203
+
204
+ const emptyLLVM = emitLLVMModule(kirP({
205
+ op: "empty",
206
+ patterns: [0, 1]
207
+ }));
208
+ assert.match(emptyLLVM, /insertvalue %k_result undef, i32 1, 0/);
209
+
210
+ const unionObject = decodeObject(compileObjectBuffer("< /x |left, /y |right >", { source: "llvm-union.k" }));
211
+ const { llvm: unionLLVM } = compileObjectToLLVM(unionObject, {
212
+ inputPattern: [
213
+ ["closed-union", [["x", 1], ["y", 2]]],
214
+ ["closed-product", []],
215
+ ["closed-product", []]
216
+ ]
217
+ });
218
+ assert.match(unionLLVM, /define internal %k_result @k_union_arm_0\(ptr %rt, ptr %input\)/);
219
+ assert.match(unionLLVM, /define internal %k_result @k_union_arm_1\(ptr %rt, ptr %input\)/);
220
+ assert.match(unionLLVM, /call %k_result @k_union_arm_0\(ptr %rt, ptr %input\)/);
221
+ assert.match(unionLLVM, /call %k_result @k_union_arm_1\(ptr %rt, ptr %input\)/);
222
+ assert.match(unionLLVM, /load ptr, ptr %mark_block_slot\d+/);
223
+ assert.match(unionLLVM, /%rewind_fast_ok\d+ = and i1 %rewind_has_mark\d+, %rewind_same_block\d+/);
224
+ assert.match(unionLLVM, /call void @k_rt_rewind\(ptr %rt, %k_rt_mark %mark\d+\)/);
225
+
226
+ const nestedUnionObject = decodeObject(compileObjectBuffer("{ < /x |left, /y |right > z }", { source: "llvm-nested-union.k" }));
227
+ const { llvm: nestedUnionLLVM } = compileObjectToLLVM(nestedUnionObject, {
228
+ inputPattern: [
229
+ ["closed-union", [["x", 1], ["y", 2]]],
230
+ ["closed-product", []],
231
+ ["closed-product", []]
232
+ ]
233
+ });
234
+ assert.match(nestedUnionLLVM, /define internal %k_result @k_union_expr_\d+\(ptr %rt, ptr %input\)/);
235
+ assert.match(nestedUnionLLVM, /call %k_result @k_union_expr_\d+\(ptr %rt, ptr %(?:input|tail_input)\)/);
236
+ assert.match(nestedUnionLLVM, /store ptr %union_value\d+, ptr %ptr_slot\d+/);
237
+ assert.doesNotMatch(nestedUnionLLVM, /call void @k_product_set_at\(ptr %product\d+/);
238
+ assert.doesNotMatch(nestedUnionLLVM, /ptr false/);
239
+
240
+ console.log("OK");
@@ -0,0 +1,31 @@
1
+ #include "krt.h"
2
+
3
+ #include <string.h>
4
+
5
+ extern k_result k_main(k_rt *rt, k_value *input);
6
+
7
+ static int expect_tag(k_result result, const char *tag, k_value *payload) {
8
+ if (result.status != K_STATUS_OK) return 1;
9
+ if (strcmp(k_variant_tag(result.value), tag) != 0) return 2;
10
+ if (k_variant_payload(result.value) != payload) return 3;
11
+ return 0;
12
+ }
13
+
14
+ int main(void) {
15
+ k_rt *rt = k_rt_new();
16
+ if (rt == NULL) return 1;
17
+
18
+ k_value *unit = k_unit(rt);
19
+
20
+ k_value *x = k_variant(rt, "x", unit);
21
+ if (expect_tag(k_main(rt, x), "left", unit) != 0) return 2;
22
+
23
+ k_value *y = k_variant(rt, "y", unit);
24
+ if (expect_tag(k_main(rt, y), "right", unit) != 0) return 3;
25
+
26
+ k_value *z = k_variant(rt, "z", unit);
27
+ if (k_main(rt, z).status == K_STATUS_OK) return 4;
28
+
29
+ k_rt_free(rt);
30
+ return 0;
31
+ }
@@ -0,0 +1,19 @@
1
+ #include "krt.h"
2
+
3
+ #include <string.h>
4
+
5
+ extern k_result k_main(k_rt *rt, k_value *input);
6
+
7
+ int main(void) {
8
+ k_rt *rt = k_rt_new();
9
+ if (rt == NULL) return 1;
10
+
11
+ k_value *unit = k_unit(rt);
12
+ k_result result = k_main(rt, unit);
13
+ if (result.status != K_STATUS_OK) return 2;
14
+ if (strcmp(k_variant_tag(result.value), "tag") != 0) return 3;
15
+ if (k_variant_payload(result.value) != unit) return 4;
16
+
17
+ k_rt_free(rt);
18
+ return 0;
19
+ }
@@ -0,0 +1,21 @@
1
+ #include "krt.h"
2
+
3
+ extern k_result k_main(k_rt *rt, k_value *input);
4
+
5
+ int main(void) {
6
+ k_rt *rt = k_rt_new();
7
+ if (rt == NULL) return 1;
8
+
9
+ k_value *unit = k_unit(rt);
10
+ k_value *matching = k_variant(rt, "tag", unit);
11
+ k_result result = k_main(rt, matching);
12
+ if (result.status != K_STATUS_OK) return 2;
13
+ if (result.value != unit) return 3;
14
+
15
+ k_value *other = k_variant(rt, "other", unit);
16
+ k_result mismatch = k_main(rt, other);
17
+ if (mismatch.status == K_STATUS_OK) return 4;
18
+
19
+ k_rt_free(rt);
20
+ return 0;
21
+ }
@@ -0,0 +1,233 @@
1
+ # Using WebAssembly
2
+
3
+ The experimental WebAssembly backend can compile a k program into a binary
4
+ `.wasm` artifact and run that artifact later without loading the original k
5
+ source. It uses the same binary `pattern + value` streams as the normal `k`
6
+ runtime, so the existing codecs remain the pipeline boundaries.
7
+
8
+ ## Install the Commands
9
+
10
+ From the monorepo root:
11
+
12
+ ```bash
13
+ npm install
14
+ cd backends/wasm
15
+ npm link
16
+ ```
17
+
18
+ This installs three commands:
19
+
20
+ | Command | Purpose |
21
+ | --- | --- |
22
+ | `k-wasm` | Compile k source, `.ko`, or `.kvm` input in memory and run it immediately |
23
+ | `k-wasm-compile` | Compile k source, `.ko`, or `.kvm` input into a standalone `.wasm` artifact |
24
+ | `k-wasm-run` | Run a previously compiled `.wasm` artifact |
25
+
26
+ The same tools can be called directly from a checkout with
27
+ `node ./bin/k-wasm.mjs`, `node ./bin/k-wasm-compile.mjs`, and
28
+ `node ./bin/k-wasm-run.mjs`.
29
+
30
+ ## Compile and Run a Source File
31
+
32
+ A source file must end with the expression that becomes its entry point:
33
+
34
+ ```k
35
+ |ok
36
+ ```
37
+
38
+ Compile it:
39
+
40
+ ```bash
41
+ k-wasm-compile program.k program.wasm
42
+ ```
43
+
44
+ Run it over a binary input stream:
45
+
46
+ ```bash
47
+ k-unit --parse |
48
+ k-wasm-run program.wasm |
49
+ k-print
50
+ ```
51
+
52
+ Expected output:
53
+
54
+ ```json
55
+ "ok"
56
+ ```
57
+
58
+ The `.wasm` artifact is a standard WebAssembly binary module:
59
+
60
+ ```bash
61
+ file program.wasm
62
+ ```
63
+
64
+ It can be stored or transferred as one file. The runner does not need
65
+ `program.k` after compilation.
66
+
67
+ ## Compile an Expression
68
+
69
+ For a small program, pass a k expression directly:
70
+
71
+ ```bash
72
+ k-wasm-compile '|ok' program.wasm
73
+ ```
74
+
75
+ The `k-wasm` convenience command performs compilation and execution in one
76
+ process:
77
+
78
+ ```bash
79
+ k-unit --parse |
80
+ k-wasm '|ok' |
81
+ k-print
82
+ ```
83
+
84
+ For compile inputs, existing paths are read as files. Missing names with
85
+ `.k`, `.ko`, `.kvm`, `.klib`, or `.wasm` extensions are reported as missing
86
+ files; other arguments are interpreted as inline source snippets.
87
+
88
+ ## Read Input from a File
89
+
90
+ Both runners accept an optional binary input file:
91
+
92
+ ```bash
93
+ k-unit --parse > input.kv
94
+ k-wasm-run program.wasm input.kv > output.kv
95
+ k-print < output.kv
96
+ ```
97
+
98
+ The one-step command has the same input-file form:
99
+
100
+ ```bash
101
+ k-wasm program.k input.kv > output.kv
102
+ ```
103
+
104
+ ## Compile from k Objects or kVM
105
+
106
+ `k-wasm-compile` can consume the object and kVM outputs produced by
107
+ `k-compile`:
108
+
109
+ ```bash
110
+ k-compile program.k program.ko
111
+ k-wasm-compile program.ko program.wasm
112
+
113
+ k-compile program.k program.kvm
114
+ k-wasm-compile program.kvm program.wasm
115
+ ```
116
+
117
+ Use `.ko` when you want to preserve the compiled object form for the normal k
118
+ toolchain. Use `.kvm` when you want to inspect or cache the lowered kVM program
119
+ before producing WebAssembly.
120
+
121
+ ## Compile with Libraries
122
+
123
+ `k-wasm-compile` and `k-wasm` accept one `--lib` option before the program.
124
+ Use repeated `--export` options to bring aliases from that library into the
125
+ source scope. The export spec is `name` or `libname:localname`.
126
+
127
+ For a library that defines `transform`:
128
+
129
+ ```bash
130
+ k-compile library.k library.klib
131
+ k-wasm-compile --lib library.klib --export transform 'transform' program.wasm
132
+ k-parse |
133
+ k-wasm-run program.wasm |
134
+ k-print
135
+ ```
136
+
137
+ The `.klib` file is required while compiling the artifact. It is not required
138
+ when running the resulting `.wasm` file.
139
+
140
+ ## Profile IEEE Execution
141
+
142
+ The comparative IEEE benchmark moved with the backend:
143
+
144
+ ```bash
145
+ npm run perf:ieee
146
+ ```
147
+
148
+ To isolate WebAssembly execution and report arena allocation statistics:
149
+
150
+ ```bash
151
+ WASM_ONLY=1 WASM_PROFILE=1 ITERATIONS=3 npm run perf:ieee
152
+ ```
153
+
154
+ Set `WASM_RESET=0` to reproduce retained-arena growth and
155
+ `WASM_WARMUP_ITERATIONS=0` to include cold-start behavior.
156
+
157
+ ## What the Artifact Contains
158
+
159
+ `k-wasm-compile` produces one WebAssembly binary module. The module contains:
160
+
161
+ - the bump-allocator runtime from [`runtime.wat`](../runtime.wat)
162
+ - one WebAssembly function for each reachable k relation
163
+ - the exported `rel___main__` entry point
164
+ - a WebAssembly custom section named `k.metadata`
165
+
166
+ The custom section stores runner metadata:
167
+
168
+ | Field | Meaning |
169
+ | --- | --- |
170
+ | `format` | Artifact family, currently `k-wasm` |
171
+ | `version` | Artifact format version, currently `1` |
172
+ | `abi` | Runtime ABI, currently `arena-v1` |
173
+ | `entry` | Exported WebAssembly function called by the runner |
174
+ | `inputPattern` | Pattern graph used to serialize the input into the arena |
175
+ | `outputPattern` | Pattern graph used to decode the output from the arena |
176
+ | `tags` | Stable integer IDs assigned to statically known variant tags |
177
+
178
+ Embedding metadata in a custom section keeps the artifact self-contained.
179
+ Unknown WebAssembly engines ignore custom sections, while `k-wasm-run` reads
180
+ the section with `WebAssembly.Module.customSections(...)`.
181
+
182
+ ## Compilation Pipeline
183
+
184
+ Compilation follows these steps:
185
+
186
+ 1. Resolve the input as inline source, a source file, a `.ko` object, or a
187
+ `.kvm` program.
188
+ 2. For source input, parse and annotate the source, including any loaded
189
+ `.klib` dependencies and `--export` aliases.
190
+ 3. For `.ko` input, use the hydrated relation definitions directly.
191
+ 4. For `.kvm` input, use the already-lowered kVM functions directly.
192
+ 5. Lower each reachable kVM function to WebAssembly text.
193
+ 6. Combine the generated functions with `runtime.wat`.
194
+ 7. Use WABT to validate the text and emit a binary WebAssembly module.
195
+ 8. Append the `k.metadata` custom section to the binary module.
196
+
197
+ The implementation lives in [`src/wasm.mjs`](../src/wasm.mjs). The command-line
198
+ wrappers are [`k-wasm-compile.mjs`](../bin/k-wasm-compile.mjs),
199
+ [`k-wasm-run.mjs`](../bin/k-wasm-run.mjs), and
200
+ [`k-wasm.mjs`](../bin/k-wasm.mjs).
201
+
202
+ ## Execution Pipeline
203
+
204
+ `k-wasm-run` performs these steps:
205
+
206
+ 1. Load and compile the `.wasm` module with Node.js `WebAssembly.compile(...)`.
207
+ 2. Read and validate the `k.metadata` custom section.
208
+ 3. Decode the input `pattern + value` stream.
209
+ 4. Serialize the input tree into the module's linear-memory arena.
210
+ 5. Call the artifact entry point with the input arena pointer.
211
+ 6. Decode the returned arena pointer under the stored output pattern.
212
+ 7. Write the result as a binary `pattern + value` stream.
213
+
214
+ The WebAssembly entry-point ABI is:
215
+
216
+ ```text
217
+ (param input_pointer i32) -> (result output_pointer i32, ok i32)
218
+ ```
219
+
220
+ An `ok` result of `1` means that the partial function produced a value. A
221
+ result of `0` means that the k relation was undefined for that input.
222
+
223
+ ## Current Limitations
224
+
225
+ - The artifact is a WebAssembly module, not a native executable. It still needs
226
+ a host runner that understands k binary streams and the `k.metadata` section.
227
+ - `k-wasm-run` currently targets Node.js. A browser runner can use the same
228
+ artifact contract but has not been added yet.
229
+ - `.klib` files are compile-time dependencies, not standalone WebAssembly
230
+ inputs. Load them with `--lib` and compile source, `.ko`, or `.kvm` input with
231
+ a main relation.
232
+ - The backend is experimental. Use `k` as the general-purpose runtime while
233
+ WebAssembly pattern coverage and optimization continue to evolve.