@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
package/core.k CHANGED
@@ -1,17 +1,17 @@
1
1
  -- core.k — the k standard core library
2
2
  --
3
3
  -- Defines:
4
- -- 1. bits — canonical binary number / bit-path relation
5
- -- 2. string — unicode strings relation (used for labels)
6
- -- 3. pattern — pattern graph relation
4
+ -- 1. bits? — canonical binary number / bit-path relation
5
+ -- 2. string? — unicode strings relation (used for labels)
6
+ -- 3. pattern? — pattern graph relation
7
7
 
8
8
  ---------------------------------------------------------------
9
9
  -- §1. Bits
10
10
  ---------------------------------------------------------------
11
11
 
12
- bit = ?< {} 0, {} 1 >;
12
+ bit? = ?< {} 0, {} 1 >;
13
13
 
14
- bits = ?< {} _, bits 0, bits 1 > = bits;
14
+ bits? = ?< {} _, bits? 0, bits? 1 > = bits?;
15
15
 
16
16
  _ = {}|_;
17
17
 
@@ -22,7 +22,7 @@ _ = {}|_;
22
22
  -- §2. Unicode and String
23
23
  ---------------------------------------------------------------
24
24
 
25
- string = ? <
25
+ string? = ? <
26
26
  {} nil,
27
27
  {
28
28
  <
@@ -82,7 +82,7 @@ string = ? <
82
82
  -- to decode any value, first decode a pattern under that constant,
83
83
  -- then decode the value under the pattern just obtained.
84
84
 
85
- pattern = ? <
85
+ pattern? = ? <
86
86
  {} nil,
87
87
  {
88
88
  <
@@ -150,4 +150,4 @@ pattern = ? <
150
150
  } cons
151
151
  > = Pattern;
152
152
 
153
- pattern
153
+ pattern?
@@ -1,6 +1,6 @@
1
1
  import { PHASES, formatUs } from "./trace.mjs";
2
2
 
3
- export function formatPhaseTable(phaseResults, backendIds = ["arm64", "llvm", "wasm", "kvm"]) {
3
+ export function formatPhaseTable(phaseResults, backendIds = ["llvm", "wasm", "kvm"]) {
4
4
  const lines = [];
5
5
 
6
6
  for (const item of phaseResults) {
@@ -25,7 +25,7 @@ export function formatPhaseTable(phaseResults, backendIds = ["arm64", "llvm", "w
25
25
  return lines.join("\n");
26
26
  }
27
27
 
28
- export function formatProfileTable(profileResults, backendIds = ["arm64", "wasm", "kvm"]) {
28
+ export function formatProfileTable(profileResults, backendIds = ["wasm", "kvm"]) {
29
29
  const lines = [];
30
30
 
31
31
  for (const item of profileResults) {
@@ -1,7 +1,6 @@
1
1
  import { NativeAdapter } from "./adapters/native.mjs";
2
2
  import { KVMAdapter } from "./adapters/kvm.mjs";
3
3
  import { WasmAdapter } from "./adapters/wasm.mjs";
4
- import { ARM64Adapter } from "./adapters/arm64.mjs";
5
4
  import { LLVMAdapter } from "./adapters/llvm.mjs";
6
5
 
7
6
  export function createRegistry(config = {}) {
@@ -16,7 +15,6 @@ export function createRegistry(config = {}) {
16
15
  register("kvm", () => new KVMAdapter(config.state));
17
16
  register("wasm", () => new WasmAdapter(config.wasm || {}));
18
17
  register("wasm-in-process", () => new WasmAdapter({ id: "wasm-in-process", mode: "in-process", ...(config.wasm || {}) }));
19
- register("arm64", () => new ARM64Adapter(config.arm64 || {}));
20
18
  register("llvm", () => new LLVMAdapter(config.llvm || {}));
21
19
 
22
20
  return {
package/kir.mjs CHANGED
@@ -337,6 +337,64 @@ function findRelation(rels, relAlias, name) {
337
337
  return null;
338
338
  }
339
339
 
340
+ function findDots(exp, res = []) {
341
+ if (!exp || typeof exp !== "object") return res;
342
+ if (exp.op === "dot") res.push(exp);
343
+ if (Array.isArray(exp.comp)) exp.comp.forEach((c) => findDots(c, res));
344
+ if (Array.isArray(exp.items)) exp.items.forEach((c) => findDots(c, res));
345
+ if (Array.isArray(exp.union)) exp.union.forEach((c) => findDots(c, res));
346
+ if (Array.isArray(exp.product)) {
347
+ exp.product.forEach((c) => findDots(c?.exp || c?.expr, res));
348
+ }
349
+ if (Array.isArray(exp.fields)) {
350
+ exp.fields.forEach((c) => findDots(c?.expr || c?.exp, res));
351
+ }
352
+ return res;
353
+ }
354
+
355
+ function getDotIndex(rel, dotExp) {
356
+ const label = dotExp.dot || dotExp.label;
357
+ if (!label) return -1;
358
+ const propList = expPatternPropertyList(rel, dotExp, 0);
359
+ if (Array.isArray(propList?.[0]?.[1])) {
360
+ return propList[0][1].findIndex(([l]) => l === label);
361
+ }
362
+ return -1;
363
+ }
364
+
365
+ function relationLayoutSignature(rel) {
366
+ const inPropList = relationPatternPropertyList(rel, 0);
367
+ if (!Array.isArray(inPropList)) return "";
368
+
369
+ const dots = findDots(rel.def);
370
+ const dotIndices = dots.map((d) => {
371
+ const lbl = d.dot || d.label || "";
372
+ return `${lbl}:${getDotIndex(rel, d)}`;
373
+ });
374
+
375
+ const productShapes = [];
376
+ for (const [kind, edges] of inPropList) {
377
+ if (kind === "open-product" || kind === "closed-product") {
378
+ const fieldNames = edges.map(([l]) => l).sort().join(",");
379
+ if (fieldNames.length > 0) productShapes.push(fieldNames);
380
+ }
381
+ }
382
+
383
+ return dotIndices.join(",") + "|" + productShapes.sort().join(";");
384
+ }
385
+
386
+ function productShapeSignature(propList) {
387
+ if (!Array.isArray(propList)) return "";
388
+ const shapes = [];
389
+ for (const [kind, edges] of propList) {
390
+ if (kind === "open-product" || kind === "closed-product") {
391
+ const fieldNames = edges.map(([l]) => l).sort().join(",");
392
+ if (fieldNames.length > 0) shapes.push(fieldNames);
393
+ }
394
+ }
395
+ return shapes.sort().join(";");
396
+ }
397
+
340
398
  export function specializeObjectRelations(object, entryRelationName = null, inputPattern = null) {
341
399
  if (object?.format !== "k-object") {
342
400
  throw new Error("specializeObjectRelations requires a k object");
@@ -362,77 +420,105 @@ export function specializeObjectRelations(object, entryRelationName = null, inpu
362
420
  const specializedRels = new Map();
363
421
  const specializedCounts = new Map();
364
422
  const newRels = {};
423
+ const inProgress = new Map();
424
+ let entryCandidate = null;
365
425
 
366
- const entryRel = cloneRelation(entry.rel);
367
- newRels[entry.name] = entryRel;
426
+ function specializeRelation(relName, argPropList) {
427
+ const target = findRelation(baseRels, object.relAlias, relName);
428
+ if (!target) return relName;
368
429
 
369
- if (Array.isArray(inputPattern) && inputPattern.length > 0) {
370
- const inRoot = addPropertyListToPatternGraph(entryRel.typePatternGraph, inputPattern);
371
- try {
372
- entryRel.typePatternGraph.unify("specialize", entryRel.def.patterns[0], inRoot);
373
- } catch {
374
- // Best-effort entry unification
430
+ const baseInSig = relationLayoutSignature(target.rel);
431
+ const shapeSig = productShapeSignature(argPropList);
432
+ const specKey = target.name + "::" + shapeSig;
433
+
434
+ if (specializedRels.has(specKey)) {
435
+ return specializedRels.get(specKey);
436
+ }
437
+ if (inProgress.has(specKey)) {
438
+ return inProgress.get(specKey);
375
439
  }
376
- specializedRels.set(entry.name + "::" + JSON.stringify(inputPattern), entry.name);
377
- }
378
440
 
379
- const worklist = [entry.name];
380
- while (worklist.length > 0) {
381
- const currentName = worklist.shift();
382
- const currentRel = newRels[currentName];
383
- if (!currentRel) continue;
441
+ const count = (specializedCounts.get(target.name) || 0) + 1;
442
+ const specName = `${target.name}$${count}`;
443
+ inProgress.set(specKey, specName);
384
444
 
385
- const calls = findCallSites(currentRel.def);
386
- for (const call of calls) {
387
- const target = findRelation(baseRels, object.relAlias, call.ref);
388
- if (!target) continue;
445
+ const candidateRel = cloneRelation(target.rel);
446
+ if (!candidateRel.typeDerivation) candidateRel.typeDerivation = {};
447
+ if (!candidateRel.typeDerivation.status) {
448
+ candidateRel.typeDerivation.status = target.rel?.typeDerivation?.status || "converged";
449
+ }
450
+
451
+ if (Array.isArray(argPropList) && argPropList.length > 0) {
452
+ const tInRoot = addPropertyListToPatternGraph(candidateRel.typePatternGraph, argPropList);
453
+ try {
454
+ candidateRel.typePatternGraph.unify("specialize", candidateRel.def.patterns[0], tInRoot);
455
+ } catch {
456
+ // Unification failure: keep target unspecialized
457
+ }
458
+ }
459
+
460
+ if (relName === entry.name && (!entryCandidate || Array.isArray(argPropList))) {
461
+ entryCandidate = candidateRel;
462
+ }
389
463
 
464
+ let anyCallChanged = false;
465
+ const calls = findCallSites(candidateRel.def);
466
+ for (const call of calls) {
390
467
  const argPatternId = call.patterns?.[0];
391
468
  if (argPatternId != null) {
392
- const argRoot = currentRel.typePatternGraph.find(argPatternId);
393
- const argPropList = patternToPropertyList(
394
- exportPatternGraph(currentRel.typePatternGraph, argRoot)
469
+ const argRoot = candidateRel.typePatternGraph.find(argPatternId);
470
+ const childArgPropList = patternToPropertyList(
471
+ exportPatternGraph(candidateRel.typePatternGraph, argRoot)
395
472
  );
396
- const argSig = JSON.stringify(argPropList);
397
- const specKey = target.name + "::" + argSig;
398
-
399
- let specName = specializedRels.get(specKey);
400
- if (!specName) {
401
- const count = (specializedCounts.get(target.name) || 0) + 1;
402
- specializedCounts.set(target.name, count);
403
- specName = count === 1 ? target.name : `${target.name}$${count}`;
404
- specializedRels.set(specKey, specName);
405
-
406
- const targetRel = cloneRelation(target.rel);
407
- const tInRoot = addPropertyListToPatternGraph(targetRel.typePatternGraph, argPropList);
408
- try {
409
- targetRel.typePatternGraph.unify("specialize", targetRel.def.patterns[0], tInRoot);
410
- } catch {
411
- // Unification failure: keep target unspecialized
412
- }
413
- newRels[specName] = targetRel;
414
- worklist.push(specName);
473
+ const childSpecName = specializeRelation(call.ref, childArgPropList);
474
+ if (childSpecName !== call.ref) {
475
+ call.ref = childSpecName;
476
+ anyCallChanged = true;
415
477
  }
416
478
 
417
- call.ref = specName;
418
-
419
- const targetRel = newRels[specName];
420
- const outPatternId = targetRel.def.patterns?.[1];
421
- const retPatternId = call.patterns?.[1];
422
- if (outPatternId != null && retPatternId != null) {
423
- const outRoot = targetRel.typePatternGraph.find(outPatternId);
424
- const retPropList = patternToPropertyList(
425
- exportPatternGraph(targetRel.typePatternGraph, outRoot)
426
- );
427
- const rRetRoot = addPropertyListToPatternGraph(currentRel.typePatternGraph, retPropList);
428
- try {
429
- currentRel.typePatternGraph.unify("specialize", retPatternId, rRetRoot);
430
- } catch {
431
- // Keep existing call return pattern on unification error
479
+ const childRel = newRels[childSpecName] || baseRels[childSpecName];
480
+ if (childRel) {
481
+ const outPatternId = childRel.def.patterns?.[1];
482
+ const retPatternId = call.patterns?.[1];
483
+ if (outPatternId != null && retPatternId != null) {
484
+ const outRoot = childRel.typePatternGraph.find(outPatternId);
485
+ const retPropList = patternToPropertyList(
486
+ exportPatternGraph(childRel.typePatternGraph, outRoot)
487
+ );
488
+ const rRetRoot = addPropertyListToPatternGraph(candidateRel.typePatternGraph, retPropList);
489
+ try {
490
+ candidateRel.typePatternGraph.unify("specialize", retPatternId, rRetRoot);
491
+ } catch {
492
+ // Keep existing call return pattern on unification error
493
+ }
432
494
  }
433
495
  }
434
496
  }
435
497
  }
498
+
499
+ inProgress.delete(specKey);
500
+
501
+ const newInSig = relationLayoutSignature(candidateRel);
502
+ const isDifferent = (newInSig !== baseInSig) || anyCallChanged;
503
+
504
+ if (!isDifferent) {
505
+ specializedRels.set(specKey, target.name);
506
+ return target.name;
507
+ }
508
+
509
+ specializedCounts.set(target.name, count);
510
+ specializedRels.set(specKey, specName);
511
+ newRels[specName] = candidateRel;
512
+ return specName;
513
+ }
514
+
515
+ const entrySpecName = specializeRelation(entry.name, inputPattern);
516
+ if (entrySpecName !== entry.name && newRels[entrySpecName]) {
517
+ newRels[entry.name] = newRels[entrySpecName];
518
+ } else if (entryCandidate) {
519
+ newRels[entry.name] = entryCandidate;
520
+ } else if (!newRels[entry.name]) {
521
+ newRels[entry.name] = baseRels[entry.name];
436
522
  }
437
523
 
438
524
  const resultRels = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fraczak/k",
3
- "version": "7.0.1",
3
+ "version": "7.0.2",
4
4
  "description": "k — a language for content-addressable schemas and data transformations over algebraic data types (products and tagged unions); includes runtime, contract derivation, REPL, and codec toolchain",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -16,7 +16,6 @@
16
16
  "test:backends": "node backends/llvm/scripts/run-tests.mjs && node backends/wasm/scripts/run-tests.mjs",
17
17
  "test:llvm": "node backends/llvm/scripts/run-tests.mjs",
18
18
  "test:wasm": "node backends/wasm/scripts/run-tests.mjs",
19
- "test:arm64": "node backends/arm64/scripts/run-tests.mjs",
20
19
  "conformance": "node conformance/run.mjs",
21
20
  "benchmark": "node scripts/benchmark.mjs",
22
21
  "benchmark:html": "node scripts/render-benchmark.mjs",
@@ -49,9 +48,6 @@
49
48
  "k-llvm-compile": "backends/llvm/bin/k-llvm-compile.mjs",
50
49
  "k-llvm-jit": "backends/llvm/bin/k-llvm-jit.mjs",
51
50
  "k-llvm-run": "backends/llvm/bin/k-llvm-run.mjs",
52
- "k-arm64": "backends/arm64/bin/k-arm64.mjs",
53
- "k-arm64-compile": "backends/arm64/bin/k-arm64-compile.mjs",
54
- "k-arm64-run": "backends/arm64/bin/k-arm64-run.mjs",
55
51
  "k-wasm": "backends/wasm/bin/k-wasm.mjs",
56
52
  "k-wasm-compile": "backends/wasm/bin/k-wasm-compile.mjs",
57
53
  "k-wasm-run": "backends/wasm/bin/k-wasm-run.mjs",
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { spawnSync } from "node:child_process";
4
- import { mkdtempSync, statSync } from "node:fs";
4
+ import { mkdtempSync, rmSync, statSync } from "node:fs";
5
5
  import { tmpdir } from "node:os";
6
6
  import { join } from "node:path";
7
7
  import { performance } from "node:perf_hooks";
@@ -80,13 +80,17 @@ for (const example of benchmarkExamples) {
80
80
 
81
81
  for (let i = 0; i < iterations; i++) {
82
82
  const out = mkdtempSync(join(tmpdir(), `k-idempotency-bench-${example.replaceAll("/", "_")}-`));
83
- const t0 = performance.now();
84
- run(["objects/compile.mjs", example, join(out, "1.klib")]);
85
- run(["objects/decompile.mjs", join(out, "1.klib"), join(out, "1.k")]);
86
- run(["objects/compile.mjs", join(out, "1.k"), join(out, "2.klib")]);
87
- run(["objects/decompile.mjs", join(out, "2.klib"), join(out, "2.k")]);
88
- times.push(performance.now() - t0);
89
- size = statSync(join(out, "1.klib")).size;
83
+ try {
84
+ const t0 = performance.now();
85
+ run(["objects/compile.mjs", example, join(out, "1.klib")]);
86
+ run(["objects/decompile.mjs", join(out, "1.klib"), join(out, "1.k")]);
87
+ run(["objects/compile.mjs", join(out, "1.k"), join(out, "2.klib")]);
88
+ run(["objects/decompile.mjs", join(out, "2.klib"), join(out, "2.k")]);
89
+ times.push(performance.now() - t0);
90
+ size = statSync(join(out, "1.klib")).size;
91
+ } finally {
92
+ rmSync(out, { recursive: true, force: true });
93
+ }
90
94
  }
91
95
 
92
96
  console.log([
@@ -21,13 +21,12 @@ import {
21
21
  retypeObjectRelationForBackend,
22
22
  patternToPropertyList,
23
23
  propertyListToPattern,
24
- parseFloat64,
25
24
  run,
26
25
  run_converged,
27
- valueForCode,
28
26
  Value
29
27
  } from "../backend-api.mjs";
30
28
  import { parse as parseIntValue } from "../codecs/int.mjs";
29
+ import { parse as parseFloatValue } from "../codecs/ieee.mjs";
31
30
  import {
32
31
  compileObjectBuffer as compileBackendObjectBuffer,
33
32
  decodeObject as decodeBackendObject
@@ -460,13 +459,10 @@ async function prepareState(suite) {
460
459
  }
461
460
 
462
461
  function ieeeInput(testCase, state) {
463
- const float64Hash = state.typeAliases.float64;
464
- const floatPairHash = state.typeAliases.float_pair;
465
- const float64 = text => valueForCode(parseFloat64(text), float64Hash, codes.find);
466
- return valueForCode(Value.product({
467
- x: float64(testCase.input.x),
468
- y: float64(testCase.input.y)
469
- }), floatPairHash, codes.find);
462
+ return Value.product({
463
+ x: parseFloatValue(testCase.input.x),
464
+ y: parseFloatValue(testCase.input.y)
465
+ });
470
466
  }
471
467
 
472
468
  function arithmeticInput(testCase) {
@@ -1888,8 +1888,8 @@ const htmlContent = `<!DOCTYPE html>
1888
1888
  <li><code>{} | ok</code> &mdash; Constant relation producing variant <code>ok</code> with empty document payload <code>{}</code></li>
1889
1889
  <li><code>not = &lt; / true | false, / false | true &gt;;</code> &mdash; Polymorphic negation via branch projections and ordered choice</li>
1890
1890
  <li><code>{} | true not</code> &mdash; Compose constant relation <code>{} | true</code> with <code>not</code> (evaluates to <code>{} | false</code>)</li>
1891
- <li><code>bool = ?&lt; {} true, {} false &gt;;</code> &mdash; Define a boolean pattern filter relation</li>
1892
- <li><code>not = bool ?X &lt; / true | false, {} | true &gt; ?X;</code> &mdash; Filtered boolean negation: guarded by <code>bool</code>, defaulting to <code>{} | true</code></li>
1891
+ <li><code>bool? = ?&lt; {} true, {} false &gt;;</code> &mdash; Define a boolean pattern filter relation</li>
1892
+ <li><code>not = bool? ?X &lt; / true | false, {} | true &gt; ?X;</code> &mdash; Filtered boolean negation: guarded by <code>bool?</code>, defaulting to <code>{} | true</code></li>
1893
1893
  <li><code>swap = { . y x, . x y };</code> &mdash; Define a product field-swapping relation</li>
1894
1894
  <li><code>{ {} | ok x, {} | nil y } swap</code> &mdash; Construct a product and pass it through <code>swap</code></li>
1895
1895
  </ul>