@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.
Files changed (71) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/DOCS/CODECS.md +37 -2
  3. package/DOCS/CODEC_ARCHITECTURE.md +12 -5
  4. package/DOCS/FILE_FORMATS.md +238 -15
  5. package/DOCS/POLYMORPHIC_IR.md +104 -0
  6. package/DOCS/REPL.md +11 -3
  7. package/DOCS/WEB_REPL_REQUIREMENTS.md +1 -1
  8. package/JOURNAL.md +288 -0
  9. package/README.md +12 -3
  10. package/Value.mjs +28 -3
  11. package/access-table.mjs +343 -0
  12. package/backend-api.mjs +23 -1
  13. package/backends/llvm/README.md +20 -21
  14. package/backends/llvm/bin/k-llvm-build.mjs +105 -32
  15. package/backends/llvm/bin/k-llvm-compile.mjs +63 -24
  16. package/backends/llvm/bin/k-llvm.mjs +292 -0
  17. package/backends/llvm/runtime/krt.c +8 -0
  18. package/backends/llvm/runtime/krt.h +1 -0
  19. package/backends/llvm/src/cli.mjs +95 -17
  20. package/backends/llvm/src/executable.mjs +128 -11
  21. package/backends/llvm/src/kvm2llvm.mjs +10 -5
  22. package/backends/llvm/src/llvm.mjs +121 -9
  23. package/backends/llvm/tests/integration.sh +11 -11
  24. package/backends/llvm/{bin → tests}/k-llvm-run.mjs +48 -22
  25. package/backends/llvm/tests/perf-support.mjs +24 -3
  26. package/backends/llvm/tests/test-llvm.mjs +22 -1
  27. package/backends/wasm/bin/k-wasm-compile.mjs +46 -20
  28. package/backends/wasm/bin/k-wasm-run.mjs +61 -20
  29. package/backends/wasm/bin/k-wasm.mjs +47 -13
  30. package/backends/wasm/src/cli.mjs +141 -19
  31. package/backends/wasm/src/wasm.mjs +130 -23
  32. package/browser/repl-browser.mjs +16 -5
  33. package/browser/tree-view.mjs +47 -8
  34. package/browser/vfs-data.mjs +6 -5
  35. package/codecs/README.md +1 -0
  36. package/codecs/djson.mjs +270 -0
  37. package/codecs/int.mjs +2 -1
  38. package/codecs/json.mjs +7 -2
  39. package/codecs/k-parse.mjs +36 -9
  40. package/codecs/k-print.mjs +26 -6
  41. package/codecs/runtime/codec-sdk.mjs +24 -6
  42. package/codecs/runtime/pattern-json.mjs +80 -1
  43. package/codecs/runtime/prefix-codec.mjs +629 -67
  44. package/codecs/runtime/show-value.mjs +93 -51
  45. package/codecs/runtime/unicode-string.mjs +29 -6
  46. package/codecs/show.mjs +24 -6
  47. package/codecs/utf16.mjs +2 -1
  48. package/k.mjs +56 -16
  49. package/kir.mjs +58 -19
  50. package/kvm.mjs +49 -12
  51. package/objects/compile.mjs +37 -23
  52. package/objects/decompile.mjs +40 -10
  53. package/objects/extract-aliases.mjs +44 -14
  54. package/objects/inspect.mjs +19 -14
  55. package/objects/validate.mjs +18 -11
  56. package/package.json +11 -3
  57. package/pkir.mjs +772 -0
  58. package/repl.mjs +92 -23
  59. package/scripts/build-repl-html.mjs +22 -3
  60. package/scripts/perf-ieee.mjs +264 -13
  61. package/scripts/perf-int.mjs +315 -22
  62. package/scripts/perf-multiplication.mjs +58 -7
  63. package/scripts/perf-poly.mjs +306 -24
  64. package/scripts/run-tests.mjs +3 -0
  65. package/tests/test-access-table.mjs +213 -0
  66. package/tests/test-codecs.mjs +168 -0
  67. package/tests/test-pkir.mjs +530 -0
  68. package/tests/test-polymorphic-tdd.mjs +196 -0
  69. package/tests/test-repl-html.mjs +16 -2
  70. package/tests/test-repl.mjs +63 -1
  71. 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!");