@fraczak/k 7.0.2 → 7.2.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/CHANGELOG.md +75 -0
- package/DOCS/CODECS.md +37 -2
- package/DOCS/CODEC_ARCHITECTURE.md +12 -5
- package/DOCS/FILE_FORMATS.md +238 -15
- package/DOCS/POLYMORPHIC_IR.md +104 -0
- package/DOCS/REPL.md +11 -3
- package/DOCS/WEB_REPL_REQUIREMENTS.md +1 -1
- package/JOURNAL.md +288 -0
- package/README.md +12 -3
- package/Value.mjs +28 -3
- package/access-table.mjs +343 -0
- package/backend-api.mjs +23 -1
- package/backends/llvm/README.md +20 -21
- package/backends/llvm/bin/k-llvm-build.mjs +105 -32
- package/backends/llvm/bin/k-llvm-compile.mjs +63 -24
- package/backends/llvm/bin/k-llvm.mjs +292 -0
- package/backends/llvm/runtime/krt.c +8 -0
- package/backends/llvm/runtime/krt.h +1 -0
- package/backends/llvm/src/cli.mjs +95 -17
- package/backends/llvm/src/executable.mjs +128 -11
- package/backends/llvm/src/kvm2llvm.mjs +10 -5
- package/backends/llvm/src/llvm.mjs +121 -9
- package/backends/llvm/tests/integration.sh +11 -11
- package/backends/llvm/{bin → tests}/k-llvm-run.mjs +48 -22
- package/backends/llvm/tests/perf-support.mjs +24 -3
- package/backends/llvm/tests/test-llvm.mjs +22 -1
- package/backends/wasm/bin/k-wasm-compile.mjs +46 -20
- package/backends/wasm/bin/k-wasm-run.mjs +61 -20
- package/backends/wasm/bin/k-wasm.mjs +47 -13
- package/backends/wasm/src/cli.mjs +141 -19
- package/backends/wasm/src/wasm.mjs +130 -23
- package/browser/repl-browser.mjs +16 -5
- package/browser/tree-view.mjs +47 -8
- package/browser/vfs-data.mjs +6 -5
- package/codecs/README.md +1 -0
- package/codecs/djson.mjs +270 -0
- package/codecs/int.mjs +2 -1
- package/codecs/json.mjs +7 -2
- package/codecs/k-parse.mjs +36 -9
- package/codecs/k-print.mjs +26 -6
- package/codecs/runtime/codec-sdk.mjs +24 -6
- package/codecs/runtime/pattern-json.mjs +80 -1
- package/codecs/runtime/prefix-codec.mjs +629 -67
- package/codecs/runtime/show-value.mjs +93 -51
- package/codecs/runtime/unicode-string.mjs +29 -6
- package/codecs/show.mjs +24 -6
- package/codecs/utf16.mjs +2 -1
- package/k.mjs +56 -16
- package/kir.mjs +58 -19
- package/kvm.mjs +49 -12
- package/objects/compile.mjs +37 -23
- package/objects/decompile.mjs +40 -10
- package/objects/extract-aliases.mjs +44 -14
- package/objects/inspect.mjs +19 -14
- package/objects/validate.mjs +18 -11
- package/package.json +11 -3
- package/pkir.mjs +772 -0
- package/repl.mjs +92 -23
- package/scripts/build-repl-html.mjs +22 -3
- package/scripts/perf-ieee.mjs +264 -13
- package/scripts/perf-int.mjs +315 -22
- package/scripts/perf-multiplication.mjs +58 -7
- package/scripts/perf-poly.mjs +306 -24
- package/scripts/run-tests.mjs +3 -0
- package/tests/test-access-table.mjs +213 -0
- package/tests/test-codecs.mjs +168 -0
- package/tests/test-pkir.mjs +530 -0
- package/tests/test-polymorphic-tdd.mjs +196 -0
- package/tests/test-repl-html.mjs +16 -2
- package/tests/test-repl.mjs +63 -1
- package/backends/llvm/bin/k-llvm-jit.mjs +0 -160
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import assert from "node:assert/strict";
|
|
5
|
+
import { createState, evaluateInput } from "../backend-api.mjs";
|
|
6
|
+
import {
|
|
7
|
+
compileRelationToPKIR,
|
|
8
|
+
executePKIR,
|
|
9
|
+
specializePKIR,
|
|
10
|
+
valueToKVal,
|
|
11
|
+
kvalToValue,
|
|
12
|
+
PKIR_FORMAT,
|
|
13
|
+
PKIR_VERSION
|
|
14
|
+
} from "../pkir.mjs";
|
|
15
|
+
import { buildAccessTable } from "../access-table.mjs";
|
|
16
|
+
import { Value } from "../Value.mjs";
|
|
17
|
+
import {
|
|
18
|
+
compileWasmArtifactFromPKIR,
|
|
19
|
+
instantiateWasmArtifact
|
|
20
|
+
} from "../backends/wasm/src/wasm.mjs";
|
|
21
|
+
import {
|
|
22
|
+
compileLLVMArtifactFromPKIR
|
|
23
|
+
} from "../backends/llvm/src/llvm.mjs";
|
|
24
|
+
import {
|
|
25
|
+
compilePKIRAndRun,
|
|
26
|
+
compilePKIRToExecutable
|
|
27
|
+
} from "../backends/llvm/src/executable.mjs";
|
|
28
|
+
|
|
29
|
+
console.log("==> Running PKIR Test Suite (tests/test-pkir.mjs)");
|
|
30
|
+
|
|
31
|
+
// --------------------------------------------------------------------
|
|
32
|
+
// Helper to parse and type a relation in K state
|
|
33
|
+
// --------------------------------------------------------------------
|
|
34
|
+
async function compileKRel(script, relName) {
|
|
35
|
+
const state = createState();
|
|
36
|
+
await evaluateInput(script, state);
|
|
37
|
+
const hashKey = state.relAliases[relName];
|
|
38
|
+
assert.ok(hashKey, `Relation ${relName} not found in state aliases`);
|
|
39
|
+
const relDef = state.rels[hashKey];
|
|
40
|
+
return { relDef, hashKey, state };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// --------------------------------------------------------------------
|
|
44
|
+
// Test 1: compileRelationToPKIR on extract_id
|
|
45
|
+
// --------------------------------------------------------------------
|
|
46
|
+
{
|
|
47
|
+
console.log("--> Test 1: compileRelationToPKIR on extract_id");
|
|
48
|
+
const script = "extract_id = </click.id, /sensor.id, /ping.id>;";
|
|
49
|
+
const { relDef } = await compileKRel(script, "extract_id");
|
|
50
|
+
|
|
51
|
+
const pkir = compileRelationToPKIR(relDef, "extract_id");
|
|
52
|
+
assert.equal(pkir.format, PKIR_FORMAT);
|
|
53
|
+
assert.equal(pkir.version, PKIR_VERSION);
|
|
54
|
+
assert.equal(pkir.name, "extract_id");
|
|
55
|
+
assert.equal(pkir.inputReg, "%v0");
|
|
56
|
+
assert.ok(pkir.outputReg);
|
|
57
|
+
assert.equal(pkir.instructions.length, 1);
|
|
58
|
+
assert.equal(pkir.instructions[0].op, "union");
|
|
59
|
+
assert.equal(pkir.instructions[0].branches.length, 3);
|
|
60
|
+
|
|
61
|
+
// Check accessProfile records queried fields and tags
|
|
62
|
+
assert.ok(pkir.accessProfile);
|
|
63
|
+
const allFields = Object.values(pkir.accessProfile)
|
|
64
|
+
.flatMap((p) => p.fields);
|
|
65
|
+
const allVariants = Object.values(pkir.accessProfile)
|
|
66
|
+
.flatMap((p) => p.variants);
|
|
67
|
+
assert.ok(allFields.includes("id"));
|
|
68
|
+
assert.ok(allVariants.includes("click"));
|
|
69
|
+
assert.ok(allVariants.includes("sensor"));
|
|
70
|
+
assert.ok(allVariants.includes("ping"));
|
|
71
|
+
console.log(" Passed: extract_id lowered to valid PKIR structure.");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// --------------------------------------------------------------------
|
|
75
|
+
// Test 2: compileRelationToPKIR on recursive search_
|
|
76
|
+
// --------------------------------------------------------------------
|
|
77
|
+
{
|
|
78
|
+
console.log("--> Test 2: compileRelationToPKIR on recursive search_");
|
|
79
|
+
const script = `
|
|
80
|
+
search_ = ?{X list, X result}
|
|
81
|
+
<
|
|
82
|
+
{.list/nil if, .result then}.then,
|
|
83
|
+
<
|
|
84
|
+
{.list/cons.car.flag/true if, {.list/cons.cdr list, {.list/cons.car car, .result cdr}|cons result} then} .then,
|
|
85
|
+
{.list/cons.cdr list, .result result}
|
|
86
|
+
> search_
|
|
87
|
+
>;
|
|
88
|
+
`;
|
|
89
|
+
const { relDef } = await compileKRel(script, "search_");
|
|
90
|
+
const pkir = compileRelationToPKIR(relDef, "search_");
|
|
91
|
+
|
|
92
|
+
assert.equal(pkir.format, PKIR_FORMAT);
|
|
93
|
+
assert.equal(pkir.name, "search_");
|
|
94
|
+
assert.equal(pkir.instructions[0].op, "union");
|
|
95
|
+
|
|
96
|
+
// Verify recursive call_rel instruction is emitted
|
|
97
|
+
const jsonStr = JSON.stringify(pkir.instructions);
|
|
98
|
+
assert.ok(jsonStr.includes('"op":"call_rel"'));
|
|
99
|
+
console.log(" Passed: Recursive search_ compiled to PKIR.");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// --------------------------------------------------------------------
|
|
103
|
+
// Test 3: executePKIR on extract_id across variants
|
|
104
|
+
// --------------------------------------------------------------------
|
|
105
|
+
{
|
|
106
|
+
console.log("--> Test 3: executePKIR on extract_id with AccessTable");
|
|
107
|
+
const script = "extract_id = </click.id, /sensor.id, /ping.id>;";
|
|
108
|
+
const { relDef } = await compileKRel(script, "extract_id");
|
|
109
|
+
const pkir = compileRelationToPKIR(relDef, "extract_id");
|
|
110
|
+
|
|
111
|
+
// Schema S1: { id, status } | click
|
|
112
|
+
const S1 = [
|
|
113
|
+
["closed-union", [["click", 1]]],
|
|
114
|
+
["closed-product", [["id", 2], ["status", 2]]],
|
|
115
|
+
["any", []]
|
|
116
|
+
];
|
|
117
|
+
const P = [
|
|
118
|
+
["open-union", [["click", 1], ["sensor", 2], ["ping", 3]]],
|
|
119
|
+
["open-product", [["id", 4]]],
|
|
120
|
+
["open-product", [["id", 4]]],
|
|
121
|
+
["open-product", [["id", 4]]],
|
|
122
|
+
["any", []]
|
|
123
|
+
];
|
|
124
|
+
const table1 = buildAccessTable(S1, P);
|
|
125
|
+
|
|
126
|
+
const valClick = Value.variant(
|
|
127
|
+
"click",
|
|
128
|
+
Value.product({
|
|
129
|
+
id: Value.variant("evt_click_id", {}),
|
|
130
|
+
status: Value.variant("active", {})
|
|
131
|
+
})
|
|
132
|
+
);
|
|
133
|
+
const kvalClick = valueToKVal(valClick, table1.rootState);
|
|
134
|
+
const res1 = executePKIR(pkir, kvalClick, table1);
|
|
135
|
+
assert.equal(kvalToValue(res1).tag, "evt_click_id");
|
|
136
|
+
|
|
137
|
+
// Schema S2: { battery_low, id, reading } | sensor
|
|
138
|
+
// Sorted field order: battery_low (slot 0), id (slot 1),
|
|
139
|
+
// reading (slot 2)
|
|
140
|
+
const S2 = [
|
|
141
|
+
["closed-union", [["sensor", 1]]],
|
|
142
|
+
["closed-product", [["battery_low", 2], ["id", 2], ["reading", 2]]],
|
|
143
|
+
["any", []]
|
|
144
|
+
];
|
|
145
|
+
const table2 = buildAccessTable(S2, P);
|
|
146
|
+
|
|
147
|
+
const valSensor = Value.variant(
|
|
148
|
+
"sensor",
|
|
149
|
+
Value.product({
|
|
150
|
+
battery_low: Value.variant("warning", {}),
|
|
151
|
+
id: Value.variant("evt_sensor_id", {}),
|
|
152
|
+
reading: Value.variant("val_99", {})
|
|
153
|
+
})
|
|
154
|
+
);
|
|
155
|
+
const kvalSensor = valueToKVal(valSensor, table2.rootState);
|
|
156
|
+
const res2 = executePKIR(pkir, kvalSensor, table2);
|
|
157
|
+
assert.equal(kvalToValue(res2).tag, "evt_sensor_id");
|
|
158
|
+
|
|
159
|
+
// Schema S3: { id } | ping
|
|
160
|
+
const S3 = [
|
|
161
|
+
["closed-union", [["ping", 1]]],
|
|
162
|
+
["closed-product", [["id", 2]]],
|
|
163
|
+
["any", []]
|
|
164
|
+
];
|
|
165
|
+
const table3 = buildAccessTable(S3, P);
|
|
166
|
+
|
|
167
|
+
const valPing = Value.variant(
|
|
168
|
+
"ping",
|
|
169
|
+
Value.product({ id: Value.variant("evt_ping_id", {}) })
|
|
170
|
+
);
|
|
171
|
+
const kvalPing = valueToKVal(valPing, table3.rootState);
|
|
172
|
+
const res3 = executePKIR(pkir, kvalPing, table3);
|
|
173
|
+
assert.equal(kvalToValue(res3).tag, "evt_ping_id");
|
|
174
|
+
|
|
175
|
+
console.log(" Passed: Multi-variant dispatch executed across layouts.");
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// --------------------------------------------------------------------
|
|
179
|
+
// Test 4: executePKIR on search_ with opaque payloads
|
|
180
|
+
// --------------------------------------------------------------------
|
|
181
|
+
{
|
|
182
|
+
console.log("--> Test 4: executePKIR on recursive search_");
|
|
183
|
+
const script = `
|
|
184
|
+
search_ = ?{X list, X result}
|
|
185
|
+
<
|
|
186
|
+
{.list/nil if, .result then}.then,
|
|
187
|
+
<
|
|
188
|
+
{.list/cons.car.flag/true if, {.list/cons.cdr list, {.list/cons.car car, .result cdr}|cons result} then} .then,
|
|
189
|
+
{.list/cons.cdr list, .result result}
|
|
190
|
+
> search_
|
|
191
|
+
>;
|
|
192
|
+
`;
|
|
193
|
+
const { relDef, hashKey } = await compileKRel(script, "search_");
|
|
194
|
+
const pkir = compileRelationToPKIR(relDef, "search_");
|
|
195
|
+
const context = { rels: { [hashKey]: pkir } };
|
|
196
|
+
|
|
197
|
+
const item1 = Value.product({
|
|
198
|
+
data: Value.variant("payload_a", {}),
|
|
199
|
+
flag: Value.variant("true", {}),
|
|
200
|
+
id: Value.variant("alpha", {})
|
|
201
|
+
});
|
|
202
|
+
const item2 = Value.product({
|
|
203
|
+
data: Value.variant("payload_b", {}),
|
|
204
|
+
flag: Value.variant("false", {}),
|
|
205
|
+
id: Value.variant("beta", {})
|
|
206
|
+
});
|
|
207
|
+
const item3 = Value.product({
|
|
208
|
+
data: Value.variant("payload_c", {}),
|
|
209
|
+
flag: Value.variant("true", {}),
|
|
210
|
+
id: Value.variant("gamma", {})
|
|
211
|
+
});
|
|
212
|
+
const nilVal = Value.variant("nil", {});
|
|
213
|
+
|
|
214
|
+
const listVal = Value.variant(
|
|
215
|
+
"cons",
|
|
216
|
+
Value.product({
|
|
217
|
+
car: item1,
|
|
218
|
+
cdr: Value.variant(
|
|
219
|
+
"cons",
|
|
220
|
+
Value.product({
|
|
221
|
+
car: item2,
|
|
222
|
+
cdr: Value.variant("cons", Value.product({ car: item3, cdr: nilVal }))
|
|
223
|
+
})
|
|
224
|
+
)
|
|
225
|
+
})
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
const inputVal = Value.product({ list: listVal, result: nilVal });
|
|
229
|
+
const kval = valueToKVal(inputVal, 0);
|
|
230
|
+
|
|
231
|
+
const resKval = executePKIR(pkir, kval, null, context);
|
|
232
|
+
const resVal = kvalToValue(resKval);
|
|
233
|
+
|
|
234
|
+
// Result should contain gamma then alpha; beta excluded
|
|
235
|
+
assert.equal(resVal.tag, "cons");
|
|
236
|
+
const firstCar = resVal.value.product.car.product;
|
|
237
|
+
assert.equal(firstCar.id.tag, "gamma");
|
|
238
|
+
assert.equal(firstCar.data.tag, "payload_c");
|
|
239
|
+
|
|
240
|
+
const secondCons = resVal.value.product.cdr;
|
|
241
|
+
assert.equal(secondCons.tag, "cons");
|
|
242
|
+
const secondCar = secondCons.value.product.car.product;
|
|
243
|
+
assert.equal(secondCar.id.tag, "alpha");
|
|
244
|
+
assert.equal(secondCar.data.tag, "payload_a");
|
|
245
|
+
|
|
246
|
+
assert.equal(secondCons.value.product.cdr.tag, "nil");
|
|
247
|
+
console.log(" Passed: Recursive search executed; payloads preserved.");
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// --------------------------------------------------------------------
|
|
251
|
+
// Test 5: specializePKIR with dead branch elimination
|
|
252
|
+
// --------------------------------------------------------------------
|
|
253
|
+
{
|
|
254
|
+
console.log("--> Test 5: specializePKIR with dead branch elimination");
|
|
255
|
+
const script = "extract_id = </click.id, /sensor.id, /ping.id>;";
|
|
256
|
+
const { relDef } = await compileKRel(script, "extract_id");
|
|
257
|
+
const pkir = compileRelationToPKIR(relDef, "extract_id");
|
|
258
|
+
|
|
259
|
+
// Schema S only provides the click variant
|
|
260
|
+
const S_click = [
|
|
261
|
+
["closed-union", [["click", 1]]],
|
|
262
|
+
["closed-product", [["id", 2], ["status", 2]]],
|
|
263
|
+
["any", []]
|
|
264
|
+
];
|
|
265
|
+
const P = [
|
|
266
|
+
["open-union", [["click", 1], ["sensor", 2], ["ping", 3]]],
|
|
267
|
+
["open-product", [["id", 4]]],
|
|
268
|
+
["open-product", [["id", 4]]],
|
|
269
|
+
["open-product", [["id", 4]]],
|
|
270
|
+
["any", []]
|
|
271
|
+
];
|
|
272
|
+
|
|
273
|
+
const table = buildAccessTable(S_click, P);
|
|
274
|
+
const spec = specializePKIR(pkir, table);
|
|
275
|
+
|
|
276
|
+
assert.equal(spec.isSpecialized, true);
|
|
277
|
+
// Dead branch elimination: only 1 branch survives out of 3
|
|
278
|
+
assert.equal(spec.instructions[0].branches.length, 1);
|
|
279
|
+
|
|
280
|
+
const branchInsts = spec.instructions[0].branches[0].instructions;
|
|
281
|
+
// First instruction must be match_tag_imm
|
|
282
|
+
assert.equal(branchInsts[0].op, "match_tag_imm");
|
|
283
|
+
assert.equal(branchInsts[0].tag, "click");
|
|
284
|
+
assert.equal(branchInsts[0].tagId, 0);
|
|
285
|
+
|
|
286
|
+
// Second instruction must be project_offset with static byte offset
|
|
287
|
+
assert.equal(branchInsts[1].op, "project_offset");
|
|
288
|
+
assert.equal(branchInsts[1].offset, 0);
|
|
289
|
+
assert.equal(branchInsts[1].label, "id");
|
|
290
|
+
|
|
291
|
+
// Verify specialized execution without AccessTable
|
|
292
|
+
const valClick = Value.variant(
|
|
293
|
+
"click",
|
|
294
|
+
Value.product({
|
|
295
|
+
id: Value.variant("spec_click_val", {}),
|
|
296
|
+
status: Value.variant("spec_status", {})
|
|
297
|
+
})
|
|
298
|
+
);
|
|
299
|
+
const kval = valueToKVal(valClick, table.rootState);
|
|
300
|
+
const res = executePKIR(spec, kval, null);
|
|
301
|
+
assert.equal(kvalToValue(res).tag, "spec_click_val");
|
|
302
|
+
console.log(" Passed: Dead branches eliminated & offsets baked in.");
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// --------------------------------------------------------------------
|
|
306
|
+
// Test 6: specializePKIR on sensor variant (non-zero offset)
|
|
307
|
+
// --------------------------------------------------------------------
|
|
308
|
+
{
|
|
309
|
+
console.log("--> Test 6: specializePKIR with non-zero offset inlining");
|
|
310
|
+
const script = "extract_id = </click.id, /sensor.id, /ping.id>;";
|
|
311
|
+
const { relDef } = await compileKRel(script, "extract_id");
|
|
312
|
+
const pkir = compileRelationToPKIR(relDef, "extract_id");
|
|
313
|
+
|
|
314
|
+
// Schema S has battery_low (slot 0), id (slot 1), reading (slot 2)
|
|
315
|
+
const S_sensor = [
|
|
316
|
+
["closed-union", [["sensor", 1]]],
|
|
317
|
+
["closed-product", [["battery_low", 2], ["id", 2], ["reading", 2]]],
|
|
318
|
+
["any", []]
|
|
319
|
+
];
|
|
320
|
+
const P = [
|
|
321
|
+
["open-union", [["click", 1], ["sensor", 2], ["ping", 3]]],
|
|
322
|
+
["open-product", [["id", 4]]],
|
|
323
|
+
["open-product", [["id", 4]]],
|
|
324
|
+
["open-product", [["id", 4]]],
|
|
325
|
+
["any", []]
|
|
326
|
+
];
|
|
327
|
+
|
|
328
|
+
const table = buildAccessTable(S_sensor, P);
|
|
329
|
+
const spec = specializePKIR(pkir, table);
|
|
330
|
+
|
|
331
|
+
assert.equal(spec.instructions[0].branches.length, 1);
|
|
332
|
+
const branchInsts = spec.instructions[0].branches[0].instructions;
|
|
333
|
+
assert.equal(branchInsts[0].op, "match_tag_imm");
|
|
334
|
+
assert.equal(branchInsts[0].tag, "sensor");
|
|
335
|
+
|
|
336
|
+
// In alphabetical order: battery_low = 0, id = 8 bytes offset
|
|
337
|
+
assert.equal(branchInsts[1].op, "project_offset");
|
|
338
|
+
assert.equal(branchInsts[1].offset, 8);
|
|
339
|
+
assert.equal(branchInsts[1].skipCount, 1);
|
|
340
|
+
|
|
341
|
+
const valSensor = Value.variant(
|
|
342
|
+
"sensor",
|
|
343
|
+
Value.product({
|
|
344
|
+
battery_low: Value.variant("low", {}),
|
|
345
|
+
id: Value.variant("sensor_target", {}),
|
|
346
|
+
reading: Value.variant("100", {})
|
|
347
|
+
})
|
|
348
|
+
);
|
|
349
|
+
const kval = valueToKVal(valSensor, table.rootState);
|
|
350
|
+
const res = executePKIR(spec, kval, null);
|
|
351
|
+
assert.equal(kvalToValue(res).tag, "sensor_target");
|
|
352
|
+
console.log(" Passed: Static byteOffset=8 inlined and verified.");
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// --------------------------------------------------------------------
|
|
356
|
+
// Test 7: valueToKVal and kvalToValue round-trip fidelity
|
|
357
|
+
// --------------------------------------------------------------------
|
|
358
|
+
{
|
|
359
|
+
console.log("--> Test 7: valueToKVal and kvalToValue round-trip");
|
|
360
|
+
const original = Value.variant(
|
|
361
|
+
"node",
|
|
362
|
+
Value.product({
|
|
363
|
+
alpha: Value.variant("val_a", {}),
|
|
364
|
+
nested: Value.product({
|
|
365
|
+
inner_1: Value.variant("x", {}),
|
|
366
|
+
inner_2: Value.variant("y", {})
|
|
367
|
+
})
|
|
368
|
+
})
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
const kval = valueToKVal(original, 0);
|
|
372
|
+
const reconstructed = kvalToValue(kval);
|
|
373
|
+
|
|
374
|
+
assert.equal(reconstructed.tag, "node");
|
|
375
|
+
assert.equal(reconstructed.value.product.alpha.tag, "val_a");
|
|
376
|
+
assert.equal(reconstructed.value.product.nested.product.inner_1.tag, "x");
|
|
377
|
+
assert.equal(reconstructed.value.product.nested.product.inner_2.tag, "y");
|
|
378
|
+
console.log(" Passed: Deep nested structures round-trip losslessly.");
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// --------------------------------------------------------------------
|
|
382
|
+
// Test 8: Partial function failure semantics
|
|
383
|
+
// --------------------------------------------------------------------
|
|
384
|
+
{
|
|
385
|
+
console.log("--> Test 8: Partial function failure semantics in PKIR");
|
|
386
|
+
const script = "extract_id = </click.id, /sensor.id, /ping.id>;";
|
|
387
|
+
const { relDef } = await compileKRel(script, "extract_id");
|
|
388
|
+
const pkir = compileRelationToPKIR(relDef, "extract_id");
|
|
389
|
+
|
|
390
|
+
// An unexpected variant tag /other should fail gracefully
|
|
391
|
+
const unexpectedVal = Value.variant(
|
|
392
|
+
"other",
|
|
393
|
+
Value.product({ id: Value.variant("val", {}) })
|
|
394
|
+
);
|
|
395
|
+
const kval = valueToKVal(unexpectedVal, 0);
|
|
396
|
+
const res = executePKIR(pkir, kval, null);
|
|
397
|
+
assert.equal(res, null);
|
|
398
|
+
console.log(" Passed: Non-matching variant returns null (fail).");
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// --------------------------------------------------------------------
|
|
402
|
+
// Test 9: WebAssembly compilation via compileWasmArtifactFromPKIR
|
|
403
|
+
// --------------------------------------------------------------------
|
|
404
|
+
{
|
|
405
|
+
console.log("--> Test 9: WebAssembly compilation from PKIR");
|
|
406
|
+
const script = "extract_id = </click.id, /sensor.id, /ping.id>;";
|
|
407
|
+
const { relDef } = await compileKRel(script, "extract_id");
|
|
408
|
+
const pkir = compileRelationToPKIR(relDef, "extract_id");
|
|
409
|
+
|
|
410
|
+
const wasmBuffer = await compileWasmArtifactFromPKIR(pkir, {
|
|
411
|
+
entry: "extract_id"
|
|
412
|
+
});
|
|
413
|
+
assert.ok(wasmBuffer && wasmBuffer.length > 0);
|
|
414
|
+
|
|
415
|
+
const runner = await instantiateWasmArtifact(wasmBuffer);
|
|
416
|
+
const inputClick = Value.variant(
|
|
417
|
+
"click",
|
|
418
|
+
Value.product({ id: Value.variant("123", Value.product({})) })
|
|
419
|
+
);
|
|
420
|
+
const resClick = runner.executeValue(inputClick);
|
|
421
|
+
assert.equal(resClick?.tag, "123");
|
|
422
|
+
|
|
423
|
+
const inputSensor = Value.variant(
|
|
424
|
+
"sensor",
|
|
425
|
+
Value.product({ id: Value.variant("sensor_456", Value.product({})) })
|
|
426
|
+
);
|
|
427
|
+
const resSensor = runner.executeValue(inputSensor);
|
|
428
|
+
assert.equal(resSensor?.tag, "sensor_456");
|
|
429
|
+
|
|
430
|
+
console.log(" Passed: PKIR lowered to Wasm and executed correctly.");
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// --------------------------------------------------------------------
|
|
434
|
+
// Test 10: LLVM IR compilation via compileLLVMArtifactFromPKIR
|
|
435
|
+
// --------------------------------------------------------------------
|
|
436
|
+
{
|
|
437
|
+
console.log("--> Test 10: LLVM compilation from PKIR");
|
|
438
|
+
const script = "extract_id = </click.id, /sensor.id, /ping.id>;";
|
|
439
|
+
const { relDef } = await compileKRel(script, "extract_id");
|
|
440
|
+
const pkir = compileRelationToPKIR(relDef, "extract_id");
|
|
441
|
+
|
|
442
|
+
const llvmText = compileLLVMArtifactFromPKIR(pkir, {
|
|
443
|
+
entry: "extract_id"
|
|
444
|
+
});
|
|
445
|
+
assert.ok(typeof llvmText === "string" && llvmText.includes("@k_main"));
|
|
446
|
+
assert.ok(llvmText.includes("@k_union_arm_0"));
|
|
447
|
+
|
|
448
|
+
const inputClick = Value.variant(
|
|
449
|
+
"click",
|
|
450
|
+
Value.product({ id: Value.variant("llvm_click_789", Value.product({})) })
|
|
451
|
+
);
|
|
452
|
+
const resClick = compilePKIRAndRun(pkir, { input: inputClick });
|
|
453
|
+
assert.equal(resClick.stdout.trim(), '"llvm_click_789"');
|
|
454
|
+
|
|
455
|
+
const inputSensor = Value.variant(
|
|
456
|
+
"sensor",
|
|
457
|
+
Value.product({ id: Value.variant("llvm_sensor_101", Value.product({})) })
|
|
458
|
+
);
|
|
459
|
+
const resSensor = compilePKIRAndRun(pkir, { input: inputSensor });
|
|
460
|
+
assert.equal(resSensor.stdout.trim(), '"llvm_sensor_101"');
|
|
461
|
+
|
|
462
|
+
console.log(" Passed: PKIR lowered to LLVM and executed correctly.");
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// --------------------------------------------------------------------
|
|
466
|
+
// Test 11: LLVM executable compilation via compilePKIRToExecutable
|
|
467
|
+
// --------------------------------------------------------------------
|
|
468
|
+
{
|
|
469
|
+
console.log("--> Test 11: LLVM executable compilation from PKIR");
|
|
470
|
+
const script = "extract_id = </click.id, /sensor.id, /ping.id>;";
|
|
471
|
+
const { relDef } = await compileKRel(script, "extract_id");
|
|
472
|
+
const pkir = compileRelationToPKIR(relDef, "extract_id");
|
|
473
|
+
|
|
474
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "k-test-pkir-llvm-"));
|
|
475
|
+
const exePath = path.join(tmpDir, "extract_id_test");
|
|
476
|
+
try {
|
|
477
|
+
compilePKIRToExecutable(pkir, exePath);
|
|
478
|
+
assert.ok(fs.existsSync(exePath));
|
|
479
|
+
|
|
480
|
+
const inputPing = Value.variant(
|
|
481
|
+
"ping",
|
|
482
|
+
Value.product({ id: Value.variant("llvm_ping_42", Value.product({})) })
|
|
483
|
+
);
|
|
484
|
+
const res = compilePKIRAndRun(pkir, { input: inputPing });
|
|
485
|
+
assert.equal(res.stdout.trim(), '"llvm_ping_42"');
|
|
486
|
+
} finally {
|
|
487
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
console.log(" Passed: PKIR compiled to standalone LLVM executable.");
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// --------------------------------------------------------------------
|
|
494
|
+
// Test 12: Recursive polymorphic relation via PKIR on LLVM
|
|
495
|
+
// --------------------------------------------------------------------
|
|
496
|
+
{
|
|
497
|
+
console.log("--> Test 12: Recursive polymorphic relation on LLVM");
|
|
498
|
+
const script = `
|
|
499
|
+
list? = ?< {} nil, { {} car, list? cdr } cons >;
|
|
500
|
+
rec_copy = list? <
|
|
501
|
+
/nil |nil,
|
|
502
|
+
/cons { .car car, .cdr rec_copy cdr } |cons
|
|
503
|
+
> list?;
|
|
504
|
+
`;
|
|
505
|
+
const { relDef } = await compileKRel(script, "rec_copy");
|
|
506
|
+
const pkirRec = compileRelationToPKIR(relDef, "rec_copy");
|
|
507
|
+
|
|
508
|
+
const inputList = Value.variant(
|
|
509
|
+
"cons",
|
|
510
|
+
Value.product({
|
|
511
|
+
car: Value.variant("elem1", Value.product({})),
|
|
512
|
+
cdr: Value.variant(
|
|
513
|
+
"cons",
|
|
514
|
+
Value.product({
|
|
515
|
+
car: Value.variant("elem2", Value.product({})),
|
|
516
|
+
cdr: Value.variant("nil", Value.product({}))
|
|
517
|
+
})
|
|
518
|
+
)
|
|
519
|
+
})
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
const res = compilePKIRAndRun(pkirRec, { input: inputList });
|
|
523
|
+
assert.equal(
|
|
524
|
+
res.stdout.trim(),
|
|
525
|
+
'{"cons":{"car":"elem1","cdr":{"cons":{"car":"elem2","cdr":"nil"}}}}'
|
|
526
|
+
);
|
|
527
|
+
console.log(" Passed: Recursive polymorphic relation executed on LLVM.");
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
console.log("\n==> All PKIR Tests Passed Successfully!");
|