@fraczak/k 7.0.1 → 7.0.2

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 (53) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/DOCS/BIG_PICTURE.md +5 -5
  3. package/DOCS/FILE_FORMATS.md +5 -5
  4. package/DOCS/OBJECT_FILE_AND_PATTERN.md +9 -9
  5. package/DOCS/PATTERNS.md +3 -3
  6. package/DOCS/PROFILING_AND_TRACING.md +60 -72
  7. package/DOCS/REPL.md +3 -3
  8. package/DOCS/book/03-types-as-finite-automata.md +4 -4
  9. package/DOCS/book/06-values-in-memory.md +9 -9
  10. package/DOCS/book/08-operational-semantics-and-execution.md +1 -1
  11. package/DOCS/book/09-compiler-architecture.md +2 -2
  12. package/DOCS/book/10-from-ast-to-intermediate-representation.md +2 -2
  13. package/DOCS/book/14-canonical-serialization.md +1 -1
  14. package/Examples/arithmetics.k +2 -2
  15. package/Examples/bnat.k +1 -1
  16. package/Examples/karatsuba-mult.k +2 -2
  17. package/README.md +3 -8
  18. package/backends/llvm/runtime/krt.c +33 -0
  19. package/backends/llvm/runtime/krt.h +1 -0
  20. package/backends/llvm/src/executable.mjs +4 -4
  21. package/backends/llvm/src/kvm2llvm.mjs +40 -18
  22. package/backends/llvm/src/llvm.mjs +12 -11
  23. package/backends/llvm/tests/perf-support.mjs +1 -55
  24. package/backends/llvm/tests/test-llvm.mjs +3 -3
  25. package/backends/wasm/src/wasm.mjs +2 -1
  26. package/backends/wasm/tests/test-wasm.mjs +5 -5
  27. package/browser/vfs-data.mjs +5 -5
  28. package/core.k +8 -8
  29. package/harness/format.mjs +2 -2
  30. package/harness/registry.mjs +0 -2
  31. package/kir.mjs +142 -56
  32. package/package.json +1 -5
  33. package/scripts/benchmark-idempotency.mjs +12 -8
  34. package/scripts/benchmark.mjs +5 -9
  35. package/scripts/build-repl-html.mjs +2 -2
  36. package/scripts/perf-ieee.mjs +17 -118
  37. package/scripts/perf-int.mjs +313 -318
  38. package/scripts/perf-multiplication.mjs +10 -20
  39. package/scripts/perf-poly.mjs +29 -183
  40. package/tests/code-derivation/pattern-envelope.mjs +4 -4
  41. package/tests/test-kvm-polymorphic.mjs +2 -2
  42. package/backends/arm64/README.md +0 -103
  43. package/backends/arm64/bin/k-arm64-compile.mjs +0 -93
  44. package/backends/arm64/bin/k-arm64-run.mjs +0 -58
  45. package/backends/arm64/bin/k-arm64.mjs +0 -88
  46. package/backends/arm64/scripts/run-tests.mjs +0 -57
  47. package/backends/arm64/src/arm64.mjs +0 -229
  48. package/backends/arm64/src/cli.mjs +0 -155
  49. package/backends/arm64/src/kvm2arm64.mjs +0 -906
  50. package/backends/arm64/src/runtime.c +0 -744
  51. package/backends/arm64/tests/integration.sh +0 -112
  52. package/backends/arm64/tests/test-arm64.mjs +0 -240
  53. package/harness/adapters/arm64.mjs +0 -105
@@ -292,7 +292,7 @@ export function stdioDriverSource({ inputPattern = null, outputPattern = null }
292
292
  " k_wire_input_free(input);",
293
293
  " return 2;",
294
294
  " }",
295
- " if (!k_pattern_equal(input.pattern, &compiled_input_pattern)) {",
295
+ " if (!k_pattern_compatible(input.pattern, &compiled_input_pattern)) {",
296
296
  " k_wire_input_free(input);",
297
297
  " return 5;",
298
298
  " }",
@@ -350,7 +350,7 @@ export function stdioDriverSource({ inputPattern = null, outputPattern = null }
350
350
  " k_value *in_val = k_decode_wire_value_with_prefix(payload, length, &input_prefix, &compiled_input_pattern, rt);",
351
351
  " if (in_val == 0) {",
352
352
  " k_wire_input envelope = k_decode_wire_envelope(payload, length, rt);",
353
- " if (envelope.value != 0 && envelope.pattern != 0 && k_pattern_equal(envelope.pattern, &compiled_input_pattern)) {",
353
+ " if (envelope.value != 0 && envelope.pattern != 0 && k_pattern_compatible(envelope.pattern, &compiled_input_pattern)) {",
354
354
  " in_val = envelope.value;",
355
355
  " } else {",
356
356
  " k_wire_input_free(envelope);",
@@ -437,7 +437,7 @@ export function stdioDriverSource({ inputPattern = null, outputPattern = null }
437
437
  " k_rt_free(input_rt);",
438
438
  " return 2;",
439
439
  " }",
440
- " if (!k_pattern_equal(input.pattern, &compiled_input_pattern)) {",
440
+ " if (!k_pattern_compatible(input.pattern, &compiled_input_pattern)) {",
441
441
  " k_wire_input_free(input);",
442
442
  " k_rt_free(run_rt);",
443
443
  " k_rt_free(input_rt);",
@@ -478,7 +478,7 @@ export function stdioDriverSource({ inputPattern = null, outputPattern = null }
478
478
  " k_rt_free(rt);",
479
479
  " return 2;",
480
480
  " }",
481
- " if (!k_pattern_equal(input.pattern, &compiled_input_pattern)) {",
481
+ " if (!k_pattern_compatible(input.pattern, &compiled_input_pattern)) {",
482
482
  " k_wire_input_free(input);",
483
483
  " k_wire_prefix_free(output_prefix);",
484
484
  " k_rt_free(rt);",
@@ -35,15 +35,17 @@ function alignArenaSize(size) {
35
35
  }
36
36
 
37
37
  function cStringBytes(text) {
38
- return [...Buffer.from(text, "utf8"), 0]
39
- .map((byte) => {
40
- if (byte === 10) return "\\0A";
41
- if (byte === 34) return "\\22";
42
- if (byte === 92) return "\\5C";
43
- if (byte >= 32 && byte <= 126) return String.fromCharCode(byte);
44
- return `\\${byte.toString(16).padStart(2, "0").toUpperCase()}`;
45
- })
46
- .join("");
38
+ const buf = Buffer.from(text, "utf8");
39
+ let out = "";
40
+ for (let i = 0; i < buf.length; i++) {
41
+ const byte = buf[i];
42
+ if (byte === 10) out += "\\0A";
43
+ else if (byte === 34) out += "\\22";
44
+ else if (byte === 92) out += "\\5C";
45
+ else if (byte >= 32 && byte <= 126) out += String.fromCharCode(byte);
46
+ else out += `\\${byte.toString(16).padStart(2, "0").toUpperCase()}`;
47
+ }
48
+ return out + "\\00";
47
49
  }
48
50
 
49
51
  export function runtimeDeclarations() {
@@ -551,8 +553,7 @@ export function compileKVMModuleToLLVM(entryName, kvmProgram, options = {}) {
551
553
  const payload = JSON.stringify({
552
554
  format: ARTIFACT_FORMAT,
553
555
  version: ARTIFACT_VERSION,
554
- relation,
555
- kvm: kvmProgram
556
+ relation
556
557
  });
557
558
  const payloadBytes = Buffer.byteLength(payload, "utf8") + 1;
558
559
  const symbol = llvmIdentifier(options.symbol || relation);
@@ -815,11 +816,32 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
815
816
  storeI64At(ctx, product, K_VALUE_PRODUCT_CAPACITY_OFFSET, N);
816
817
  storePtrAt(ctx, product, K_VALUE_PRODUCT_FIELDS_OFFSET, fields);
817
818
 
818
- const sortedFields = [...fieldValues].sort((a, b) => {
819
- if (a.label < b.label) return -1;
820
- if (a.label > b.label) return 1;
821
- return 0;
822
- });
819
+ let sortedFields;
820
+ if (Array.isArray(inst.pattern) && inst.pattern.length > 0) {
821
+ const root = inst.pattern[0];
822
+ if (
823
+ (root[0] === "open-product" ||
824
+ root[0] === "closed-product") &&
825
+ Array.isArray(root[1])
826
+ ) {
827
+ const order = new Map(root[1].map(([l], i) => [l, i]));
828
+ sortedFields = [...fieldValues].sort((a, b) => {
829
+ const aI = order.has(a.label)
830
+ ? order.get(a.label)
831
+ : 999999;
832
+ const bI = order.has(b.label)
833
+ ? order.get(b.label)
834
+ : 999999;
835
+ if (aI !== bI) return aI - bI;
836
+ return a.label.localeCompare(b.label);
837
+ });
838
+ }
839
+ }
840
+ if (!sortedFields) {
841
+ sortedFields = [...fieldValues].sort((a, b) =>
842
+ a.label.localeCompare(b.label)
843
+ );
844
+ }
823
845
 
824
846
  for (let sIdx = 0; sIdx < N; sIdx++) {
825
847
  const { label: fLabel, val: fVal } = sortedFields[sIdx];
@@ -838,7 +860,7 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
838
860
  const uInput = getReg(inst.src);
839
861
 
840
862
  if (!isTopLevel) {
841
- // Nested union: synthesize a helper function @k_union_expr_${index}
863
+ // Nested union: synthesize helper @k_union_expr_${index}
842
864
  const exprIndex = moduleCtx.unionExprIndex++;
843
865
  const exprName = `@k_union_expr_${exprIndex}`;
844
866
  const exprFunc = {
@@ -863,7 +885,7 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
863
885
  break;
864
886
  }
865
887
 
866
- // Top-level union: synthesize arm functions @k_union_arm_${index}
888
+ // Top-level union: synthesize arms @k_union_arm_${index}
867
889
  const mark = lowerRtMark(ctx);
868
890
  const unionDone = ctx.blockName("union_done");
869
891
  const N = inst.branches.length;
@@ -45,15 +45,17 @@ function alignArenaSize(size) {
45
45
  }
46
46
 
47
47
  function cStringBytes(text) {
48
- return [...Buffer.from(text, "utf8"), 0]
49
- .map((byte) => {
50
- if (byte === 10) return "\\0A";
51
- if (byte === 34) return "\\22";
52
- if (byte === 92) return "\\5C";
53
- if (byte >= 32 && byte <= 126) return String.fromCharCode(byte);
54
- return `\\${byte.toString(16).padStart(2, "0").toUpperCase()}`;
55
- })
56
- .join("");
48
+ const buf = Buffer.from(text, "utf8");
49
+ let out = "";
50
+ for (let i = 0; i < buf.length; i++) {
51
+ const byte = buf[i];
52
+ if (byte === 10) out += "\\0A";
53
+ else if (byte === 34) out += "\\22";
54
+ else if (byte === 92) out += "\\5C";
55
+ else if (byte >= 32 && byte <= 126) out += String.fromCharCode(byte);
56
+ else out += `\\${byte.toString(16).padStart(2, "0").toUpperCase()}`;
57
+ }
58
+ return out + "\\00";
57
59
  }
58
60
 
59
61
  function readPattern(inputPattern) {
@@ -986,8 +988,7 @@ export function emitLLVMModule(input, options = {}) {
986
988
  const payload = JSON.stringify({
987
989
  format: ARTIFACT_FORMAT,
988
990
  version: ARTIFACT_VERSION,
989
- relation,
990
- kir
991
+ relation
991
992
  });
992
993
  const payloadBytes = Buffer.byteLength(payload, "utf8") + 1;
993
994
  const symbol = llvmIdentifier(options.symbol || relation);
@@ -216,7 +216,7 @@ export function runExecutableMainBench(exePath, inputWire, calls) {
216
216
  reject(new Error(`${exePath} --bench-main failed with status ${status}\n${text}`.trim()));
217
217
  return;
218
218
  }
219
- const match = text.match(/K_(?:LLVM|ARM64)_BENCH_MAIN calls=(\d+) total_ns=(\d+) per_call_ns=([0-9.]+)/);
219
+ const match = text.match(/K_LLVM_BENCH_MAIN calls=(\d+) total_ns=(\d+) per_call_ns=([0-9.]+)/);
220
220
  if (!match) {
221
221
  reject(new Error(`${exePath} --bench-main did not report timing\n${text}`.trim()));
222
222
  return;
@@ -599,61 +599,7 @@ export function llvmLaneName() {
599
599
  : "LLVM Executable (persistent)";
600
600
  }
601
601
 
602
- export function arm64LaneName(optLevel = "-O2") {
603
- const mode = process.env.ARM64_SPAWN_PER_CALL === "1"
604
- ? "spawn/call"
605
- : (process.env.ARM64_PIPELINE === "1" ? "persistent, pipelined" : "persistent");
606
- return `Linux ARM64 ${optLevel} (${mode})`;
607
- }
608
-
609
- export function createARM64Runner(testSuite) {
610
- const arm64Cases = testSuite.filter(tc => tc.arm64?.status === "ok");
611
- if (process.env.ARM64_SPAWN_PER_CALL === "1") {
612
- return {
613
- run(iterations) {
614
- if (arm64Cases.length === 0) return null;
615
- return runTimedIterationsAsync(iterations, async () => {
616
- for (const tc of arm64Cases) {
617
- await runExecutable(tc.arm64.exePath, tc.inputWire);
618
- }
619
- });
620
- },
621
- close() {}
622
- };
623
- }
624
602
 
625
- const servers = new Map();
626
- function serverFor(exePath) {
627
- let server = servers.get(exePath);
628
- if (server == null) {
629
- server = new PersistentExecutable(exePath);
630
- servers.set(exePath, server);
631
- }
632
- return server;
633
- }
634
-
635
- return {
636
- async run(iterations) {
637
- if (arm64Cases.length === 0) return null;
638
- return runTimedIterationsAsync(iterations, async () => {
639
- if (process.env.ARM64_PIPELINE === "1") {
640
- const pending = [];
641
- for (const tc of arm64Cases) {
642
- pending.push(serverFor(tc.arm64.exePath).request(tc.inputWire));
643
- }
644
- await Promise.all(pending);
645
- return;
646
- }
647
- for (const tc of arm64Cases) {
648
- await serverFor(tc.arm64.exePath).request(tc.inputWire);
649
- }
650
- });
651
- },
652
- close() {
653
- for (const server of servers.values()) server.close();
654
- }
655
- };
656
- }
657
603
 
658
604
  export function average(times) {
659
605
  return times.reduce((sum, time) => sum + time, 0) / times.length;
@@ -239,11 +239,11 @@ assert.doesNotMatch(nestedUnionLLVM, /call void @k_product_set_at\(ptr %product\
239
239
  assert.doesNotMatch(nestedUnionLLVM, /ptr false/);
240
240
 
241
241
  const productRecurseObject = decodeObject(compileObjectBuffer(`
242
- list = ?< {} nil, { {} car, list cdr } cons >;
243
- foo = list <
242
+ list? = ?< {} nil, { {} car, list? cdr } cons >;
243
+ foo = list? <
244
244
  /nil |nil,
245
245
  /cons { .car car, .cdr foo cdr } |cons
246
- > list;
246
+ > list?;
247
247
  foo
248
248
  `, { source: "llvm-product-recurse.k" }));
249
249
  const { llvm: productRecurseLLVM } = compileObjectToLLVM(productRecurseObject, {
@@ -439,7 +439,8 @@ function relTypeStatus(defs, name) {
439
439
  const rel = defs.rels?.[name];
440
440
  const explicit = rel?.typeDerivation?.status;
441
441
  if (explicit) return explicit;
442
- const scc = compileStatsByRelName(defs.compileStats).get(name);
442
+ const stats = compileStatsByRelName(defs.compileStats);
443
+ const scc = stats.get(name) || (name.includes("$") ? stats.get(name.split("$")[0]) : null);
443
444
  if (scc) return scc.converged ? "converged" : "not-converged";
444
445
  return "unknown";
445
446
  }
@@ -443,11 +443,11 @@ console.log("==> Running End-to-End Peano Addition & Serialization Tests");
443
443
  const runtimeWat = fs.readFileSync("runtime.wat", "utf8");
444
444
 
445
445
  const script = `
446
- nat = ?< {} 0, nat +1 >;
447
- 0 = {} | 0 nat;
448
- inc = | +1 nat;
449
- dec = nat / +1;
450
- add = ?{ nat x, nat y } = X <
446
+ nat? = ?< {} 0, nat? +1 >;
447
+ 0 = {} | 0 nat?;
448
+ inc = | +1 nat?;
449
+ dec = nat? / +1;
450
+ add = ?{ nat? x, nat? y } = X <
451
451
  { . x dec x, . y inc y } ?X add,
452
452
  . y
453
453
  >;