@fraczak/k 6.1.3 → 6.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 (64) hide show
  1. package/AGENTS.md +4 -4
  2. package/CLAUDE.md +1 -1
  3. package/DOCS/OBJECT_FILE_AND_PATTERN.md +6 -0
  4. package/DOCS/REPL.md +22 -17
  5. package/README.md +6 -5
  6. package/export.mjs +10 -0
  7. package/k-vscode/README.md +10 -1
  8. package/k-vscode/extension.js +273 -0
  9. package/k-vscode/package.json +22 -0
  10. package/k-vscode/syntaxes/k.tmLanguage.json +493 -137
  11. package/k-vscode/test/background-ranges.test.js +50 -0
  12. package/k-vscode/themes/k-contrast-color-theme.json +104 -0
  13. package/package.json +2 -2
  14. package/repl.mjs +43 -2
  15. package/scripts/run-tests.mjs +54 -0
  16. package/{Code-derivation-tests → tests/code-derivation}/codec-witness-pattern.mjs +3 -3
  17. package/{Code-derivation-tests → tests/code-derivation}/convergence-strategy.mjs +1 -1
  18. package/{Code-derivation-tests → tests/code-derivation}/dot.mjs +1 -1
  19. package/{Code-derivation-tests → tests/code-derivation}/filter-syntax.mjs +1 -1
  20. package/{Code-derivation-tests → tests/code-derivation}/index.mjs +1 -1
  21. package/{Code-derivation-tests → tests/code-derivation}/pattern-envelope.mjs +5 -5
  22. package/{Code-derivation-tests → tests/code-derivation}/product.mjs +1 -1
  23. package/{tests.sh → tests/integration.sh} +3 -1
  24. package/{test-fingerprint.mjs → tests/test-fingerprint.mjs} +3 -3
  25. package/{test-hash-fuzz.mjs → tests/test-hash-fuzz.mjs} +1 -1
  26. package/{test-hash-normalization.mjs → tests/test-hash-normalization.mjs} +2 -2
  27. package/{test-ieee-arithmetic.mjs → tests/test-ieee-arithmetic.mjs} +14 -27
  28. package/{test-k-object.mjs → tests/test-k-object.mjs} +8 -8
  29. package/{test-repl.mjs → tests/test-repl.mjs} +22 -4
  30. package/{test.mjs → tests/test.mjs} +1 -1
  31. package/.codex +0 -0
  32. package/DOCS/a.html +0 -398
  33. package/DOCS/dependency-graph.html +0 -140
  34. package/DOCS/dependency-graph.md +0 -144
  35. package/NAT.k~ +0 -452
  36. package/UU/ta.k +0 -1
  37. package/UU/ta.k~ +0 -0
  38. package/UU/tb.k +0 -0
  39. package/UU/tc.k +0 -0
  40. package/a.k +0 -138
  41. package/a.klib +0 -1
  42. package/codecs/BINARY_FORMAT.html +0 -471
  43. package/codecs/POLYMORPHIC_BINARY_FORMAT.html +0 -355
  44. package/core.json +0 -1
  45. package/core.klib +0 -1
  46. package/core.klib~ +0 -0
  47. package/ieee.klib +0 -1
  48. package/k-vscode/package-lock.json +0 -4176
  49. package/kkk.k +0 -197
  50. package/kkk.klib +0 -0
  51. package/kkk.klib~ +0 -0
  52. package/nak.klib +0 -1
  53. package/nak2.klib +0 -1
  54. package/nat.k +0 -10
  55. package/nat2.k +0 -9
  56. package/p.json +0 -5475
  57. package/type_registry/registry.mjs~ +0 -105
  58. package/type_registry/typeParser.jison~ +0 -132
  59. /package/{Code-derivation-tests → tests/code-derivation}/blowup.mjs +0 -0
  60. /package/{Code-derivation-tests → tests/code-derivation}/bnat.mjs +0 -0
  61. /package/{Code-derivation-tests → tests/code-derivation}/loop.mjs +0 -0
  62. /package/{Code-derivation-tests → tests/code-derivation}/nat.mjs +0 -0
  63. /package/{Code-derivation-tests → tests/code-derivation}/not-not.mjs +0 -0
  64. /package/{Code-derivation-tests → tests/code-derivation}/rlz.mjs +0 -0
@@ -0,0 +1,50 @@
1
+ const assert = require("assert");
2
+ const Module = require("module");
3
+
4
+ const originalLoad = Module._load;
5
+ Module._load = function load(request, parent, isMain) {
6
+ if (request === "vscode") return {};
7
+ return originalLoad.call(this, request, parent, isMain);
8
+ };
9
+
10
+ const { collectBackgroundRanges } = require("../extension");
11
+
12
+ function slices(text, ranges) {
13
+ return ranges.map(({ start, end }) => text.slice(start, end));
14
+ }
15
+
16
+ const source = [
17
+ "$ pair = { leaf left, leaf right };",
18
+ "pick = $pair ?{<$leaf some, ...>=X branch, ...} .branch;",
19
+ "-- ?<ignored tag>",
20
+ "/* $ignored */",
21
+ "$pair pick"
22
+ ].join("\n");
23
+
24
+ const ranges = collectBackgroundRanges(source);
25
+ const type = slices(source, ranges.type);
26
+ const filter = slices(source, ranges.filter);
27
+
28
+ assert.deepStrictEqual(type, [
29
+ "$ pair = { leaf left, leaf right };",
30
+ "$pair",
31
+ "$leaf",
32
+ "$pair"
33
+ ]);
34
+ assert.deepStrictEqual(filter, ["?{<$leaf some, ...>=X branch, ...}"]);
35
+
36
+ const nested = "add = ?{ $nat x, ... } = X <{.x pred x, .y succ y} ? X add, .y> ;";
37
+ const nestedRanges = collectBackgroundRanges(nested);
38
+
39
+ assert.deepStrictEqual(slices(nested, nestedRanges.filter), [
40
+ "?{ $nat x, ... } = X",
41
+ "? X"
42
+ ]);
43
+ assert.deepStrictEqual(slices(nested, nestedRanges.type), ["$nat"]);
44
+ assert.deepStrictEqual(nestedRanges.filter, [
45
+ { start: 6, end: 26 },
46
+ { start: 51, end: 54 }
47
+ ]);
48
+ assert.deepStrictEqual(nestedRanges.type, [{ start: 9, end: 13 }]);
49
+
50
+ console.log("background range scanner tests passed");
@@ -0,0 +1,104 @@
1
+ {
2
+ "$schema": "vscode://schemas/color-theme",
3
+ "name": "k Contrast",
4
+ "type": "dark",
5
+ "colors": {
6
+ "editor.background": "#161B22",
7
+ "editor.foreground": "#C9D1D9",
8
+ "editorLineNumber.foreground": "#6E7681",
9
+ "editorLineNumber.activeForeground": "#C9D1D9",
10
+ "editor.selectionBackground": "#264F78",
11
+ "editor.inactiveSelectionBackground": "#264F7855"
12
+ },
13
+ "tokenColors": [
14
+ {
15
+ "scope": [
16
+ "comment.block.k",
17
+ "comment.line.k"
18
+ ],
19
+ "settings": {
20
+ "foreground": "#8B949E",
21
+ "fontStyle": "italic"
22
+ }
23
+ },
24
+ {
25
+ "scope": "entity.name.type.k",
26
+ "settings": {
27
+ "foreground": "#FF7B72",
28
+ "fontStyle": "bold"
29
+ }
30
+ },
31
+ {
32
+ "scope": "support.type.k",
33
+ "settings": {
34
+ "foreground": "#FFA657"
35
+ }
36
+ },
37
+ {
38
+ "scope": "support.function.identifier.k",
39
+ "settings": {
40
+ "foreground": "#79C0FF"
41
+ }
42
+ },
43
+ {
44
+ "scope": "support.type.canonical.k",
45
+ "settings": {
46
+ "foreground": "#F778BA"
47
+ }
48
+ },
49
+ {
50
+ "scope": "support.function.canonical.k",
51
+ "settings": {
52
+ "foreground": "#FF967D"
53
+ }
54
+ },
55
+ {
56
+ "scope": "entity.name.label.k",
57
+ "settings": {
58
+ "foreground": "#7EE787"
59
+ }
60
+ },
61
+ {
62
+ "scope": "entity.name.tag.k",
63
+ "settings": {
64
+ "foreground": "#F2CC60"
65
+ }
66
+ },
67
+ {
68
+ "scope": "variable.other.pattern.k",
69
+ "settings": {
70
+ "foreground": "#56D4DD"
71
+ }
72
+ },
73
+ {
74
+ "scope": [
75
+ "keyword.operator.assignment.k",
76
+ "keyword.operator.binding.k",
77
+ "keyword.operator.filter.k",
78
+ "keyword.operator.projection.product.k",
79
+ "keyword.operator.projection.union.k",
80
+ "keyword.operator.type.k",
81
+ "keyword.operator.variant.k"
82
+ ],
83
+ "settings": {
84
+ "foreground": "#FFDF5D"
85
+ }
86
+ },
87
+ {
88
+ "scope": "punctuation.definition.canonical.k",
89
+ "settings": {
90
+ "foreground": "#B392F0"
91
+ }
92
+ },
93
+ {
94
+ "scope": [
95
+ "constant.language.any.k",
96
+ "string.quoted.double.k",
97
+ "string.quoted.single.k"
98
+ ],
99
+ "settings": {
100
+ "foreground": "#A5D6FF"
101
+ }
102
+ }
103
+ ]
104
+ }
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@fraczak/k",
3
- "version": "6.1.3",
3
+ "version": "6.2.0",
4
4
  "description": "k — a language for composing first-order partial functions over algebraic data types (products and tagged unions); includes runtime, type derivation, REPL, and codec toolchain",
5
5
  "main": "index.mjs",
6
6
  "scripts": {
7
7
  "prepare": "jiwson -m es6 parser.jison -o parser.mjs; jiwson -m es6 valueParser.jison -o valueParser.mjs; ",
8
- "test": "node test.mjs; for f in Code-derivation-tests/*.mjs; do echo $f; node $f; done; node test-fingerprint.mjs; node test-hash-fuzz.mjs; node test-hash-normalization.mjs; node test-k-object.mjs; node test-repl.mjs; node test-ieee-arithmetic.mjs; ./tests.sh",
8
+ "test": "node scripts/run-tests.mjs",
9
9
  "perf:idempotency": "node scripts/benchmark-idempotency.mjs",
10
10
  "deps:graph": "node scripts/generate-dependency-graph.mjs"
11
11
  },
package/repl.mjs CHANGED
@@ -213,6 +213,40 @@ function mergeLibrary(state, lib, source = "<load>", options = {}) {
213
213
  restoreCodes(state);
214
214
  }
215
215
 
216
+ function reachableRelations(rels, roots) {
217
+ const reachable = new Set();
218
+ const queue = [...roots];
219
+
220
+ function walkExp(exp) {
221
+ if (!exp) return;
222
+ switch (exp.op) {
223
+ case "ref":
224
+ if (exp.ref in rels && !reachable.has(exp.ref)) queue.push(exp.ref);
225
+ break;
226
+ case "comp":
227
+ exp.comp.forEach(walkExp);
228
+ break;
229
+ case "union":
230
+ exp.union.forEach(walkExp);
231
+ break;
232
+ case "product":
233
+ exp.product.forEach(({ exp: child }) => walkExp(child));
234
+ break;
235
+ }
236
+ }
237
+
238
+ while (queue.length > 0) {
239
+ const hash = queue.shift();
240
+ if (reachable.has(hash) || !(hash in rels)) continue;
241
+ reachable.add(hash);
242
+ walkExp(rels[hash].def);
243
+ }
244
+
245
+ return Object.fromEntries(
246
+ Object.entries(rels).filter(([hash]) => reachable.has(hash))
247
+ );
248
+ }
249
+
216
250
  function savedLibrary(state) {
217
251
  const meta = cloneJSON(state.meta);
218
252
  const now = new Date().toISOString();
@@ -226,13 +260,20 @@ function savedLibrary(state) {
226
260
  if (meta[hash].type == null) meta[hash].type = "rel";
227
261
  meta[hash].origins.push({ source: "<repl>", name, compiledAt: now });
228
262
  }
263
+ const rels = reachableRelations(state.rels, Object.values(state.relAliases));
264
+ const storedHashes = new Set([
265
+ ...Object.keys(state.codes),
266
+ ...Object.keys(rels)
267
+ ]);
229
268
  return {
230
269
  format: "k-object",
231
270
  codes: state.codes,
232
- rels: state.rels,
271
+ rels,
233
272
  relAlias: state.relAliases,
234
273
  compileStats: { sccs: [], sccCount: 0 },
235
- meta,
274
+ meta: Object.fromEntries(
275
+ Object.entries(meta).filter(([hash]) => storedHashes.has(hash))
276
+ ),
236
277
  main: null
237
278
  };
238
279
  }
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import { spawnSync } from "node:child_process";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
9
+ const node = process.execPath;
10
+ const derivationTests = fs.readdirSync(path.join(root, "tests/code-derivation"))
11
+ .filter((name) => name.endsWith(".mjs"))
12
+ .sort()
13
+ .map((name) => [`tests/code-derivation/${name}`, node, [`tests/code-derivation/${name}`]]);
14
+
15
+ const tests = [
16
+ ["tests/test.mjs", node, ["tests/test.mjs"]],
17
+ ...derivationTests,
18
+ ["tests/test-fingerprint.mjs", node, ["tests/test-fingerprint.mjs"]],
19
+ ["tests/test-hash-fuzz.mjs", node, ["tests/test-hash-fuzz.mjs"]],
20
+ ["tests/test-hash-normalization.mjs", node, ["tests/test-hash-normalization.mjs"]],
21
+ ["tests/test-k-object.mjs", node, ["tests/test-k-object.mjs"]],
22
+ ["tests/test-repl.mjs", node, ["tests/test-repl.mjs"]],
23
+ ["tests/test-ieee-arithmetic.mjs", node, ["tests/test-ieee-arithmetic.mjs"]],
24
+ ["tests/integration.sh", path.join(root, "tests/integration.sh"), []]
25
+ ];
26
+
27
+ function formatDuration(milliseconds) {
28
+ if (milliseconds < 1000) return `${milliseconds.toFixed(0)} ms`;
29
+ return `${(milliseconds / 1000).toFixed(2)} s`;
30
+ }
31
+
32
+ const suiteStarted = performance.now();
33
+ for (const [name, command, args] of tests) {
34
+ console.log(`\n==> ${name}`);
35
+ const started = performance.now();
36
+ const result = spawnSync(command, args, {
37
+ cwd: root,
38
+ stdio: "inherit"
39
+ });
40
+ const duration = formatDuration(performance.now() - started);
41
+
42
+ if (result.error) {
43
+ console.error(`<== ${name} FAILED (${duration})`);
44
+ console.error(result.error.message);
45
+ process.exit(1);
46
+ }
47
+ if (result.status !== 0) {
48
+ console.error(`<== ${name} FAILED (${duration})`);
49
+ process.exit(result.status ?? 1);
50
+ }
51
+ console.log(`<== ${name} passed (${duration})`);
52
+ }
53
+
54
+ console.log(`\nAll tests passed (${formatDuration(performance.now() - suiteStarted)})`);
@@ -1,7 +1,7 @@
1
1
  import assert from 'assert';
2
- import { parseValue } from '../valueIO.mjs';
3
- import { encodeToWire, decodeWire } from '../codecs/runtime/prefix-codec.mjs';
4
- import { Product, Variant } from '../Value.mjs';
2
+ import { parseValue } from '../../valueIO.mjs';
3
+ import { encodeToWire, decodeWire } from '../../codecs/runtime/prefix-codec.mjs';
4
+ import { Product, Variant } from '../../Value.mjs';
5
5
 
6
6
  const value = parseValue('{a:{b:x,c:{}}}');
7
7
  const repeatedClosedValue = parseValue('{a:{m:{},n:{}},b:{m:{},n:{}}}');
@@ -1,5 +1,5 @@
1
1
  import assert from "assert";
2
- import { annotate } from "../index.mjs";
2
+ import { annotate } from "../../index.mjs";
3
3
 
4
4
  const script = `
5
5
  f = .x;
@@ -1,5 +1,5 @@
1
1
  import { t, in_out } from './index.mjs';
2
- import { hash } from '../hash.mjs';
2
+ import { hash } from '../../hash.mjs';
3
3
  import assert from 'assert';
4
4
 
5
5
  t(`
@@ -1,5 +1,5 @@
1
1
  import assert from 'assert';
2
- import { annotate } from '../index.mjs';
2
+ import { annotate } from '../../index.mjs';
3
3
 
4
4
  function succeeds(script) {
5
5
  assert.doesNotThrow(() => annotate(script));
@@ -1,4 +1,4 @@
1
- import { annotate } from "../index.mjs";
1
+ import { annotate } from "../../index.mjs";
2
2
 
3
3
  function in_out(annotated) {
4
4
  const [input,output] = annotated.rels.__main__.def.patterns.map( (pat) =>
@@ -1,9 +1,9 @@
1
1
  import assert from "node:assert/strict";
2
- import k from "../index.mjs";
3
- import { Product, Variant, mergePatterns, withPattern } from "../Value.mjs";
4
- import { decodeWire, encodeToWire } from "../codecs/runtime/prefix-codec.mjs";
5
- import run from "../run.mjs";
6
- import codes from "../codes.mjs";
2
+ import k from "../../index.mjs";
3
+ import { Product, Variant, mergePatterns, withPattern } from "../../Value.mjs";
4
+ import { decodeWire, encodeToWire } from "../../codecs/runtime/prefix-codec.mjs";
5
+ import run from "../../run.mjs";
6
+ import codes from "../../codes.mjs";
7
7
 
8
8
  const INT_PATTERN = [
9
9
  ["closed-union", [["+", 1], ["-", 1]]],
@@ -1,6 +1,6 @@
1
1
  import { t, in_out } from './index.mjs';
2
2
  import assert from 'assert';
3
- import hash from "../hash.mjs";
3
+ import hash from "../../hash.mjs";
4
4
 
5
5
  const unitCode = hash('$C0={};');
6
6
 
@@ -1,7 +1,9 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
1
3
 
2
4
  # This script is used to run the k.mjs interpreter with various test cases.
3
5
 
4
- echo "Running './tests.sh' ..."
6
+ echo "Running './tests/integration.sh' ..."
5
7
 
6
8
  echo '["zebara", "ela", "kupa", ala, owca]' | node ./codecs/k-parse.mjs | ./k.mjs '{.1 0,.3 1}' | node ./codecs/k-print.mjs
7
9
  echo
@@ -1,6 +1,6 @@
1
- import k from './index.mjs';
2
- import { encodeCodeToString, find } from './codes.mjs';
3
- import hash from './hash.mjs';
1
+ import k from '../index.mjs';
2
+ import { encodeCodeToString, find } from '../codes.mjs';
3
+ import hash from '../hash.mjs';
4
4
  [
5
5
  `
6
6
  $bits = < bits 0, bits 1, {} _ >;
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import assert from "node:assert/strict";
4
- import { annotate } from "./index.mjs";
4
+ import { annotate } from "../index.mjs";
5
5
 
6
6
  function mulberry32(seed) {
7
7
  let t = seed >>> 0;
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import assert from "node:assert/strict";
4
- import { annotate } from "./index.mjs";
5
- import { hash } from "./hash.mjs";
4
+ import { annotate } from "../index.mjs";
5
+ import { hash } from "../hash.mjs";
6
6
 
7
7
  const nameRegex = /^[a-zA-Z0-9_+][a-zA-Z0-9_?!+]*$/;
8
8
 
@@ -1,10 +1,10 @@
1
1
  import assert from "node:assert/strict";
2
2
 
3
- import { createState, evaluateInput } from "./repl.mjs";
4
- import { Product } from "./Value.mjs";
5
- import codes from "./codes.mjs";
6
- import { parse as parseFloat64, print as printFloat64 } from "./codecs/ieee.mjs";
7
- import { singletonPatternToCodeHash, valueForCode } from "./repl-codecs.mjs";
3
+ import { createState, evaluateInput } from "../repl.mjs";
4
+ import { Product } from "../Value.mjs";
5
+ import codes from "../codes.mjs";
6
+ import { parse as parseFloat64, print as printFloat64 } from "../codecs/ieee.mjs";
7
+ import { singletonPatternToCodeHash, valueForCode } from "../repl-codecs.mjs";
8
8
 
9
9
  const state = createState();
10
10
  await evaluateInput(":load Examples/ieee.k", state);
@@ -44,7 +44,7 @@ function assertFloatResult(value, expected, label) {
44
44
  assert.equal(printFloat64(value), expected, label);
45
45
  }
46
46
 
47
- async function assertOperation({ op, x, y, result, flags = null }) {
47
+ async function assertOperation({ op, x, y, result, flags = null, projection = false }) {
48
48
  const bundle = await runOperation(op, x, y);
49
49
  assert.ok(bundle instanceof Product, `${op} should return a result bundle`);
50
50
  assert.deepEqual(Object.keys(bundle.product).sort(), ["flags", "result"]);
@@ -53,37 +53,24 @@ async function assertOperation({ op, x, y, result, flags = null }) {
53
53
  assert.equal(bundle.product.flags.tag, flags, `${op}(${x}, ${y}).flags`);
54
54
  }
55
55
 
56
- const projected = await runProjectedResult(op, x, y);
57
- assertFloatResult(projected, result, `${op}(${x}, ${y}).result projection`);
56
+ if (projection) {
57
+ const projected = await runProjectedResult(op, x, y);
58
+ assertFloatResult(projected, result, `${op}(${x}, ${y}).result projection`);
59
+ }
58
60
  }
59
61
 
60
62
  const cases = [
61
- // Addition: same sign, cancellation, exact fractional add, and specials.
62
- { op: "add", x: "1", y: "1", result: "2", flags: "none" },
63
- { op: "add", x: "-1", y: "1", result: "0", flags: "none" },
64
- { op: "add", x: "0.5", y: "0.25", result: "0.75", flags: "none" },
63
+ // Keep this as a fast smoke matrix. Examples/ieee.k has detailed relation-level coverage.
64
+ { op: "add", x: "0.5", y: "0.25", result: "0.75", flags: "none", projection: true },
65
65
  { op: "add", x: "Infinity", y: "-Infinity", result: "NaN", flags: "invalid" },
66
- { op: "add", x: "NaN", y: "1", result: "NaN", flags: "none" },
67
66
 
68
- // Subtraction: positive result, negative result, signed-zero-equivalent, and invalid infinity subtraction.
69
- { op: "sub", x: "4", y: "2", result: "2", flags: "none" },
67
+ // Cover each finite arithmetic implementation, including sign and fractional results.
70
68
  { op: "sub", x: "2", y: "4", result: "-2", flags: "none" },
71
- { op: "sub", x: "0", y: "0", result: "0", flags: "none" },
72
- { op: "sub", x: "Infinity", y: "Infinity", result: "NaN", flags: "invalid" },
73
-
74
- // Multiplication: positive, signed, zero, and invalid infinity-by-zero.
75
- { op: "mul", x: "4", y: "2", result: "8", flags: "none" },
76
69
  { op: "mul", x: "-2", y: "4", result: "-8", flags: "none" },
77
- { op: "mul", x: "0", y: "5", result: "0", flags: "none" },
78
70
  { op: "mul", x: "Infinity", y: "0", result: "NaN", flags: "invalid" },
79
-
80
- // Division: normalized exact cases, fractional quotient, divide-by-zero, invalid zero-over-zero, and infinity quotient.
81
- { op: "div", x: "4", y: "2", result: "2" },
82
- { op: "div", x: "1", y: "1", result: "1" },
83
71
  { op: "div", x: "1", y: "2", result: "0.5" },
84
72
  { op: "div", x: "1", y: "0", result: "Infinity", flags: "div_by_zero" },
85
- { op: "div", x: "0", y: "0", result: "NaN", flags: "invalid" },
86
- { op: "div", x: "Infinity", y: "2", result: "Infinity", flags: "none" }
73
+ { op: "div", x: "0", y: "0", result: "NaN", flags: "invalid" }
87
74
  ];
88
75
 
89
76
  for (const testCase of cases) {
@@ -1,11 +1,11 @@
1
1
  import assert from "node:assert";
2
2
  import fs from "node:fs";
3
- import k from "./index.mjs";
4
- import { parseValue } from "./valueIO.mjs";
5
- import { decodeWire, encodeToWire, CORE_PATTERN_PROPERTY_LIST } from "./codecs/runtime/prefix-codec.mjs";
6
- import { Product, Variant } from "./Value.mjs";
7
- import { exportPatternGraph } from "./codecs/runtime/codec.mjs";
8
- import { patternToPropertyList } from "./codecs/runtime/pattern-json.mjs";
3
+ import k from "../index.mjs";
4
+ import { parseValue } from "../valueIO.mjs";
5
+ import { decodeWire, encodeToWire, CORE_PATTERN_PROPERTY_LIST } from "../codecs/runtime/prefix-codec.mjs";
6
+ import { Product, Variant } from "../Value.mjs";
7
+ import { exportPatternGraph } from "../codecs/runtime/codec.mjs";
8
+ import { patternToPropertyList } from "../codecs/runtime/pattern-json.mjs";
9
9
  import {
10
10
  compileObjectBuffer,
11
11
  compileLibraryBuffer,
@@ -14,7 +14,7 @@ import {
14
14
  runConvergedObject,
15
15
  decompileObjectBuffer,
16
16
  extractAliasesFromObject
17
- } from "./object.mjs";
17
+ } from "../object.mjs";
18
18
 
19
19
  const value = parseValue("{a:{b:x,c:{}}}");
20
20
  const wire = encodeToWire(value, null);
@@ -96,7 +96,7 @@ const natDecompiledSource = decompileObjectBuffer(natLibraryBuffer);
96
96
  const natRoundTripSource = decompileObjectBuffer(
97
97
  compileLibraryBuffer(natDecompiledSource, { source: "Examples/nat.decompiled.k" })
98
98
  );
99
- const recursiveNatPattern = /\?\{<X0 succ, \.\.\.>=X0 x, <X1 succ, \.\.\.>=X1 y\} .* \?X1;/;
99
+ const recursiveNatPattern = /\$dTww <\{\.x PgmQ x, \.y h4Wg y\} re64, \.y> \$e9WP;/;
100
100
  assert.equal(natRoundTripSource, natDecompiledSource);
101
101
  assert.match(natDecompiledSource, recursiveNatPattern);
102
102
 
@@ -16,9 +16,9 @@ import {
16
16
  isMainEntrypoint,
17
17
  lineHasExplicitContinuation,
18
18
  lineTerminatesSnippet
19
- } from "./repl.mjs";
20
- import { decodeObject, objectToFunction } from "./object.mjs";
21
- import { Product } from "./Value.mjs";
19
+ } from "../repl.mjs";
20
+ import { decodeObject, objectToFunction } from "../object.mjs";
21
+ import { Product } from "../Value.mjs";
22
22
 
23
23
  const state = createState();
24
24
 
@@ -90,6 +90,7 @@ await assert.rejects(
90
90
 
91
91
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "k-repl-"));
92
92
  const libPath = path.join(tmpDir, "session.klib");
93
+ const recursiveLibPath = path.join(tmpDir, "recursive.klib");
93
94
  const koPath = path.join(tmpDir, "succ.ko");
94
95
  const sourcePath = path.join(tmpDir, "session.k");
95
96
  const codecPath = path.join(tmpDir, "bool-codec.mjs");
@@ -97,6 +98,23 @@ const symlinkPath = path.resolve(".test-k-repl-link");
97
98
  output = await evaluateInput(`:klib ${libPath}`, state);
98
99
  assert.equal(output[0], `saved ${libPath}`);
99
100
 
101
+ const recursiveState = createState();
102
+ await evaluateInput(":type $ nat = < {}_, nat 0, nat 1 >;", recursiveState);
103
+ await evaluateInput(":rel 0? = $ nat < / _ {}|0, / 0 0? >;", recursiveState);
104
+ const staleZeroHash = recursiveState.relAliases["0?"];
105
+ await evaluateInput(":rel 0? = $ nat < / _ {}|_, / 0 0? >;", recursiveState);
106
+ const zeroHash = recursiveState.relAliases["0?"];
107
+ assert.notEqual(zeroHash, staleZeroHash);
108
+ await evaluateInput("{}|_|0|0 $nat", recursiveState);
109
+ assert.deepEqual(
110
+ Object.keys(recursiveState.rels).sort(),
111
+ [staleZeroHash, zeroHash].sort()
112
+ );
113
+ output = await evaluateInput(`:klib ${recursiveLibPath}`, recursiveState);
114
+ assert.equal(output[0], `saved ${recursiveLibPath}`);
115
+ const recursiveLibrary = JSON.parse(fs.readFileSync(recursiveLibPath, "utf8"));
116
+ assert.deepEqual(Object.keys(recursiveLibrary.rels), [zeroHash]);
117
+
100
118
  completions = completeInput(`:load ${tmpDir}/ses`, state)[0];
101
119
  assert(completions.includes(`:load ${libPath}`));
102
120
  completions = completeInput(`:load --no-alias ${tmpDir}/ses`, state)[0];
@@ -176,7 +194,7 @@ assert.equal(output[0], `input ${utf8State.typeAliases.string} using utf8: enter
176
194
  output = await evaluateInput("hello", utf8State);
177
195
  assert.match(output[0], /utf8: hello/);
178
196
 
179
- const replPath = fileURLToPath(new URL("./repl.mjs", import.meta.url));
197
+ const replPath = fileURLToPath(new URL("../repl.mjs", import.meta.url));
180
198
  try {
181
199
  fs.rmSync(symlinkPath, { force: true });
182
200
  } catch {}
@@ -1,4 +1,4 @@
1
- import k from "./index.mjs";
1
+ import k from "../index.mjs";
2
2
 
3
3
  [
4
4
  [{"unit": {}}, "()"],
package/.codex DELETED
File without changes