@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.
- package/DOCS/CODECS.md +258 -0
- package/DOCS/DICTIONARY.md +1172 -0
- package/DOCS/KIR_SPECIALIZATION_DESIGN.md +51 -46
- package/DOCS/KIR_V1.md +221 -0
- package/DOCS/KVM_EXECUTION_MODEL.md +56 -19
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +2 -1
- package/DOCS/PROFILING_AND_TRACING.md +196 -0
- package/DOCS/REPL.md +61 -4
- package/DOCS/WEB_REPL_REQUIREMENTS.md +135 -0
- package/DOCS/dependency-graph.md +144 -0
- package/Examples/arithmetics.k +51 -48
- package/Examples/bnat.k +1 -1
- package/Examples/buda.k +44 -0
- package/Examples/ieee.k +300 -8671
- package/Examples/poly.k +67 -0
- package/README.md +68 -19
- package/augmentation.mjs +9 -7
- package/backend-api.mjs +11 -2
- package/backends/arm64/README.md +104 -0
- package/backends/arm64/bin/k-arm64-compile.mjs +101 -0
- package/backends/arm64/bin/k-arm64-run.mjs +58 -0
- package/backends/arm64/bin/k-arm64.mjs +88 -0
- package/backends/arm64/scripts/run-tests.mjs +41 -0
- package/backends/arm64/src/arm64.mjs +229 -0
- package/backends/arm64/src/cli.mjs +155 -0
- package/backends/arm64/src/kvm2arm64.mjs +906 -0
- package/backends/arm64/src/runtime.c +728 -0
- package/backends/arm64/tests/integration.sh +112 -0
- package/backends/arm64/tests/test-arm64.mjs +240 -0
- package/backends/llvm/README.md +135 -0
- package/backends/llvm/bin/k-llvm-build.mjs +71 -0
- package/backends/llvm/bin/k-llvm-compile.mjs +68 -0
- package/backends/llvm/bin/k-llvm-jit.mjs +160 -0
- package/backends/llvm/bin/k-llvm-run.mjs +90 -0
- package/backends/llvm/runtime/krt.c +1508 -0
- package/backends/llvm/runtime/krt.h +109 -0
- package/backends/llvm/scripts/conformance.mjs +76 -0
- package/backends/llvm/scripts/run-tests.mjs +28 -0
- package/backends/llvm/src/executable.mjs +562 -0
- package/backends/llvm/src/kvm2llvm.mjs +998 -0
- package/backends/llvm/src/llvm.mjs +1092 -0
- package/backends/llvm/tests/composition-driver.c +22 -0
- package/backends/llvm/tests/identity-driver.c +27 -0
- package/backends/llvm/tests/integration.sh +153 -0
- package/backends/llvm/tests/perf-support.mjs +735 -0
- package/backends/llvm/tests/product-driver.c +23 -0
- package/backends/llvm/tests/projection-driver.c +19 -0
- package/backends/llvm/tests/relation-driver.c +29 -0
- package/backends/llvm/tests/test-llvm.mjs +240 -0
- package/backends/llvm/tests/union-driver.c +31 -0
- package/backends/llvm/tests/variant-driver.c +19 -0
- package/backends/llvm/tests/variant-projection-driver.c +21 -0
- package/backends/wasm/DOCS/USE-WEB-ASSEMBLY.md +233 -0
- package/backends/wasm/README.md +97 -0
- package/backends/wasm/TECHNICAL-DEBT.md +60 -0
- package/backends/wasm/bin/k-wasm-compile.mjs +50 -0
- package/backends/wasm/bin/k-wasm-run.mjs +140 -0
- package/backends/wasm/bin/k-wasm.mjs +49 -0
- package/backends/wasm/demo_ieee.mjs +319 -0
- package/backends/wasm/runtime.wat +102 -0
- package/backends/wasm/scripts/run-tests.mjs +41 -0
- package/backends/wasm/src/cli.mjs +133 -0
- package/backends/wasm/src/kvm2wasm.mjs +661 -0
- package/backends/wasm/src/wasm.mjs +1010 -0
- package/backends/wasm/tests/integration.sh +182 -0
- package/backends/wasm/tests/perf-support.mjs +336 -0
- package/backends/wasm/tests/test-wasm.mjs +617 -0
- package/browser/repl-browser.mjs +1584 -0
- package/browser/shims/assert.mjs +19 -0
- package/browser/shims/buffer.mjs +224 -0
- package/browser/shims/crypto.mjs +103 -0
- package/browser/shims/fs.mjs +159 -0
- package/browser/shims/os.mjs +17 -0
- package/browser/shims/path.mjs +54 -0
- package/browser/shims/process.mjs +44 -0
- package/browser/shims/readline.mjs +11 -0
- package/browser/shims/url.mjs +12 -0
- package/browser/vfs-data.mjs +19 -0
- package/codecs/README.md +3 -0
- package/codecs/runtime/show-value.mjs +2 -2
- package/conformance/helper-reuse/case.json +8 -0
- package/conformance/helper-reuse/expected.kv +1 -0
- package/conformance/helper-reuse/input.kv +1 -0
- package/conformance/helper-reuse/program.k +2 -0
- package/conformance/identity/case.json +8 -0
- package/conformance/identity/expected.kv +1 -0
- package/conformance/identity/input.kv +1 -0
- package/conformance/identity/program.k +1 -0
- package/conformance/product-projection/case.json +8 -0
- package/conformance/product-projection/expected.kv +1 -0
- package/conformance/product-projection/input.kv +1 -0
- package/conformance/product-projection/program.k +1 -0
- package/conformance/run.mjs +149 -0
- package/conformance/variant-construction/case.json +8 -0
- package/conformance/variant-construction/expected.kv +1 -0
- package/conformance/variant-construction/input.kv +1 -0
- package/conformance/variant-construction/program.k +1 -0
- package/harness/adapters/arm64.mjs +105 -0
- package/harness/adapters/kvm.mjs +144 -0
- package/harness/adapters/llvm.mjs +118 -0
- package/harness/adapters/native.mjs +77 -0
- package/harness/adapters/wasm.mjs +169 -0
- package/harness/backend.mjs +95 -0
- package/harness/cli.mjs +130 -0
- package/harness/format.mjs +95 -0
- package/harness/index.mjs +25 -0
- package/harness/persistent.mjs +121 -0
- package/harness/registry.mjs +44 -0
- package/harness/suite.mjs +257 -0
- package/harness/suites/poly.mjs +156 -0
- package/harness/trace.mjs +50 -0
- package/harness/util.mjs +92 -0
- package/intrinsics.mjs +41 -0
- package/kir.mjs +399 -0
- package/kvm.mjs +585 -81
- package/objects/README.md +37 -3
- package/objects/compile.mjs +15 -22
- package/objects/inspect.mjs +96 -0
- package/objects/validate.mjs +415 -0
- package/package.json +51 -19
- package/repl-codecs.mjs +105 -6
- package/repl.mjs +335 -49
- package/run.mjs +2 -7
- package/scripts/benchmark.mjs +406 -22
- package/scripts/build-repl-html.mjs +1784 -0
- package/scripts/perf-ieee.mjs +586 -0
- package/scripts/perf-int.mjs +531 -0
- package/scripts/perf-poly.mjs +945 -0
- package/scripts/render-benchmark.mjs +12 -8
- package/scripts/run-tests.mjs +6 -0
- package/tests/integration.sh +19 -2
- package/tests/test-arithmetics.mjs +54 -0
- package/tests/test-ieee-arithmetic.mjs +4 -0
- package/tests/test-kir.mjs +85 -0
- package/tests/test-kvm-polymorphic.mjs +278 -0
- package/tests/test-kvm.mjs +25 -6
- package/tests/test-poly.mjs +129 -0
- package/tests/test-repl-html.mjs +303 -0
- package/tests/test-repl.mjs +144 -1
- package/tests/test-validate-object.mjs +40 -0
- package/a.klib +0 -1
- package/a.kvm +0 -142676
- package/a.wasm +0 -0
- package/benchmark-results.html +0 -532
- package/benchmark-results.json +0 -480
- package/k-vscode/.vscode/launch.json +0 -14
- package/k-vscode/README.md +0 -75
- package/k-vscode/extension.js +0 -273
- package/k-vscode/language-configuration.json +0 -42
- package/k-vscode/package.json +0 -79
- package/k-vscode/snippets/k.json +0 -92
- package/k-vscode/syntaxes/k.tmLanguage.json +0 -599
- package/k-vscode/test/background-ranges.test.js +0 -50
- package/k-vscode/themes/k-contrast-color-theme.json +0 -104
- 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.
|