@fraczak/k 6.10.6 → 7.0.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 (69) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/CLAUDE.md +1 -1
  3. package/DOCS/BIG_PICTURE.md +156 -172
  4. package/DOCS/BINARY_CODEC_STATUS_AND_TODO.md +3 -3
  5. package/DOCS/CODEC_ARCHITECTURE.md +2 -2
  6. package/DOCS/DICTIONARY.md +243 -250
  7. package/DOCS/DIVERGENCE_DETECTION.md +0 -1
  8. package/DOCS/FILE_FORMATS.md +5 -5
  9. package/DOCS/KIR_SPECIALIZATION_DESIGN.md +1 -1
  10. package/DOCS/OBJECT_FILE_AND_PATTERN.md +12 -12
  11. package/DOCS/PATTERNS.md +17 -17
  12. package/DOCS/PATTERNS_AND_TYPED_VALUES.md +1 -1
  13. package/DOCS/REPL.md +9 -19
  14. package/DOCS/TYPE_DERIVATION.md +2 -8
  15. package/DOCS/WEB_REPL_REQUIREMENTS.md +8 -8
  16. package/DOCS/book/01-introduction.md +8 -11
  17. package/DOCS/book/02-syntax-and-values.md +19 -20
  18. package/DOCS/book/03-types-as-finite-automata.md +42 -43
  19. package/DOCS/book/04-partial-functions-and-composition.md +2 -3
  20. package/DOCS/book/05-typing-filters-and-normalization.md +44 -46
  21. package/DOCS/book/06-values-in-memory.md +10 -10
  22. package/DOCS/book/08-operational-semantics-and-execution.md +21 -26
  23. package/DOCS/book/09-compiler-architecture.md +11 -11
  24. package/DOCS/book/10-from-ast-to-intermediate-representation.md +6 -7
  25. package/DOCS/book/14-canonical-serialization.md +2 -2
  26. package/DOCS/book/appendix-b-incorporating-external-predefined-types-and-functions.md +17 -17
  27. package/DOCS/book.md +5 -5
  28. package/Examples/arithmetics.k +49 -153
  29. package/Examples/bnat.k +13 -13
  30. package/Examples/byte.k +2 -50
  31. package/Examples/ieee.k +408 -423
  32. package/Examples/karatsuba-mult.k +30 -34
  33. package/Examples/nat.k +5 -6
  34. package/README.md +54 -49
  35. package/TODO.md +13 -18
  36. package/browser/vfs-data.mjs +11 -11
  37. package/codecs/BINARY_FORMAT.md +4 -4
  38. package/codecs/POLYMORPHIC_BINARY_FORMAT.md +4 -4
  39. package/codecs/README.md +6 -6
  40. package/codecs/ieee.mjs +15 -11
  41. package/codecs/int.mjs +9 -5
  42. package/codecs/string-codec.mjs +46 -47
  43. package/core.k +123 -95
  44. package/object.mjs +0 -7
  45. package/package.json +5 -2
  46. package/parser.jison +2 -41
  47. package/parser.mjs +55 -95
  48. package/pretty.mjs +11 -4
  49. package/repl.mjs +8 -63
  50. package/scripts/build-repl-html.mjs +8 -38
  51. package/tests/code-derivation/blowup.mjs +2 -4
  52. package/tests/code-derivation/bnat.mjs +2 -3
  53. package/tests/code-derivation/dot.mjs +5 -11
  54. package/tests/code-derivation/nat.mjs +2 -2
  55. package/tests/code-derivation/not-not.mjs +6 -6
  56. package/tests/code-derivation/pattern-envelope.mjs +4 -6
  57. package/tests/code-derivation/product.mjs +3 -6
  58. package/tests/code-derivation/rlz.mjs +4 -5
  59. package/tests/test-codecs.mjs +1 -1
  60. package/tests/test-fingerprint.mjs +36 -41
  61. package/tests/test-hash-normalization.mjs +4 -6
  62. package/tests/test-ieee-arithmetic.mjs +6 -7
  63. package/tests/test-k-object.mjs +11 -15
  64. package/tests/test-kir.mjs +0 -1
  65. package/tests/test-kvm-polymorphic.mjs +1 -2
  66. package/tests/test-kvm.mjs +8 -11
  67. package/tests/test-repl-html.mjs +5 -2
  68. package/tests/test-repl.mjs +38 -53
  69. package/tests/test.mjs +2 -3
@@ -24,18 +24,16 @@ import { Value } from "../Value.mjs";
24
24
 
25
25
  const state = createState();
26
26
 
27
- let output = await evaluateInput("$ nat = < {} zero, nat succ >;", state);
28
- output = await evaluateInput(":type nat", state);
29
- assert.match(output[0], /^\$ nat = /);
27
+ let output = await evaluateInput("zero = {} | zero;", state);
28
+ output = await evaluateInput(":rel zero", state);
29
+ assert.match(output[0], /^zero = /);
30
30
 
31
31
  output = await evaluateInput("succ = | succ;", state);
32
32
  output = await evaluateInput(":rel succ", state);
33
33
  assert.match(output[0], /^succ = /);
34
34
 
35
- output = await evaluateInput(":types", state);
36
- assert.match(output[0], /^nat = @/m);
37
-
38
35
  output = await evaluateInput(":rels", state);
36
+ assert.match(output[0], /^zero = @/m);
39
37
  assert.match(output[0], /^succ = @/m);
40
38
 
41
39
  output = await evaluateInput("succ", state);
@@ -54,18 +52,18 @@ assert.match(output[0], /^succ = /);
54
52
  let completions = completeInput(":he", state)[0];
55
53
  assert.deepEqual(completions, [":help"]);
56
54
 
57
- const canonicalPartial = state.typeAliases.nat.slice(0, 8);
55
+ const canonicalPartial = state.relAliases.zero.slice(0, 8);
58
56
  completions = completeInput(`:rel ${canonicalPartial}`, state)[0];
59
- assert(completions.some((line) => line.endsWith(state.typeAliases.nat)));
57
+ assert(completions.some((line) => line.endsWith(state.relAliases.zero)));
60
58
 
61
59
  completions = completeInput(`(${canonicalPartial}`, state)[0];
62
- assert(completions.includes(`(${state.typeAliases.nat}`));
60
+ assert(completions.includes(`(${state.relAliases.zero}`));
63
61
 
64
62
  completions = completeInput(":rel su", state)[0];
65
63
  assert(completions.includes(":rel succ"));
66
- completions = completeInput(":ty", state)[0];
67
- assert(completions.includes(":types"));
68
- assert(completions.includes(":type"));
64
+ completions = completeInput(":re", state)[0];
65
+ assert(completions.includes(":rels"));
66
+ assert(completions.includes(":rel"));
69
67
 
70
68
  await assert.rejects(
71
69
  () => evaluateInput(":run succ", state),
@@ -83,27 +81,26 @@ await assert.rejects(
83
81
  completions = completeInput(":co", state)[0];
84
82
  assert(completions.includes(":codec"));
85
83
 
86
- completions = completeInput("$na", state)[0];
87
- assert(completions.includes("$nat"));
84
+ completions = completeInput("ze", state)[0];
85
+ assert(completions.includes("zero"));
88
86
 
89
- assert.deepEqual(aliasNames(state), ["nat", "succ"]);
87
+ assert.deepEqual(aliasNames(state), ["succ", "zero"]);
90
88
  assert.equal(lineTerminatesSnippet(";"), true);
91
89
  assert.equal(lineTerminatesSnippet(" ; "), true);
92
90
  assert.equal(lineTerminatesSnippet(" ; -- comment"), false);
93
91
  assert.equal(lineTerminatesSnippet("succ"), false);
94
- assert.equal(explicitSnippetTerminated("$ bool = <{} true, {} false>;"), true);
92
+ assert.equal(explicitSnippetTerminated("bool = <{} true, {} false>;"), true);
95
93
  assert.equal(lineHasExplicitContinuation("succ \\"), true);
96
- assert.equal(analyzeRawSnippet("$ bool = <{} true, {} false>").kind, "incomplete");
97
- assert.equal(analyzeAcceptedSnippet("$ bool = <{} true, {} false>;", true).kind, "definitionsOnly");
94
+ assert.equal(analyzeRawSnippet("bool = <{} true, {} false>").kind, "incomplete");
95
+ assert.equal(analyzeAcceptedSnippet("bool = <{} true, {} false>;", true).kind, "definitionsOnly");
98
96
  assert.equal(analyzeRawSnippet("a =").kind, "incomplete");
99
97
  assert.equal(analyzeRawSnippet("{} | succ").kind, "withMain");
100
98
 
101
99
  const offsetState = createState();
102
- await evaluateInput("$ ab = < {} 1, {} 2 >;", offsetState);
103
- await evaluateInput("$ bool = < {} true, {} false >;", offsetState);
100
+ await evaluateInput("zero = {} | zero;\nsucc = | succ;", offsetState);
104
101
  await assert.rejects(
105
- () => evaluateInput("$ab", offsetState),
106
- /Type Error in 'filter' \(lines 1:1\.\.\.1:4\)/
102
+ () => evaluateInput("{} .x", offsetState),
103
+ /Type Error in 'comp' \(lines 1:1\.\.\.1:6\)/
107
104
  );
108
105
 
109
106
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "k-repl-"));
@@ -117,13 +114,12 @@ output = await evaluateInput(`:klib ${libPath}`, state);
117
114
  assert.equal(output[0], `saved ${libPath}`);
118
115
 
119
116
  const recursiveState = createState();
120
- await evaluateInput("$ nat = < {} _, nat 0, nat 1 >;", recursiveState);
121
- await evaluateInput("0? = $ nat < / _ {} | 0, / 0 0? >;", recursiveState);
117
+ await evaluateInput("0? = ?< {} _, X 0, X 1 > = X < / _ {} | 0, / 0 0? >;", recursiveState);
122
118
  const staleZeroHash = recursiveState.relAliases["0?"];
123
- await evaluateInput("0? = $ nat < / _ {} | _, / 0 0? >;", recursiveState);
119
+ await evaluateInput("0? = ?< {} _, X 0, X 1 > = X < / _ {} | _, / 0 0? >;", recursiveState);
124
120
  const zeroHash = recursiveState.relAliases["0?"];
125
121
  assert.notEqual(zeroHash, staleZeroHash);
126
- await evaluateInput("{}|_|0|0 $nat", recursiveState);
122
+ await evaluateInput("{}|_|0|0 0?", recursiveState);
127
123
  assert.deepEqual(
128
124
  Object.keys(recursiveState.rels).sort(),
129
125
  [staleZeroHash, zeroHash].sort()
@@ -144,28 +140,21 @@ const objectFn = objectToFunction(decodeObject(fs.readFileSync(koPath)));
144
140
  const objectResult = objectFn(Value.product({}, [["closed-product", []]]));
145
141
  assert.equal(objectResult.toJSON(), "succ");
146
142
 
147
- fs.writeFileSync(sourcePath, "$ nat = <{} zero, nat succ>;\nsucc = $nat |succ $nat;\ntwice = succ succ;\n");
143
+ fs.writeFileSync(sourcePath, "succ = |succ;\ntwice = succ succ;\n");
148
144
  const loadedSource = createState();
149
145
  output = await evaluateInput(`:load ${sourcePath}`, loadedSource);
150
146
  assert.equal(output[0], `loaded ${sourcePath}`);
151
- output = await evaluateInput(":types", loadedSource);
152
- assert.match(output[0], /^nat = @/m);
153
147
  output = await evaluateInput(":rels", loadedSource);
154
148
  assert.match(output[0], /^succ = @/m);
155
149
  output = await evaluateInput(":rel twice", loadedSource);
156
- assert.match(output[0], /^twice = \$nat succ succ \$nat; -- @/);
157
- output = await evaluateInput(":C nat", loadedSource);
158
- assert.match(output[0], /^\$ nat = < nat succ, @[^ ]+ zero >; -- @/);
150
+ assert.match(output[0], /^twice = .*succ succ.*; -- @/);
159
151
 
160
152
  const codecState = createState();
161
- output = await evaluateInput("$ bool = < {} true, {} false >;", codecState);
162
- const boolHash = codecState.typeAliases.bool;
163
153
  const valueModuleUrl = pathToFileURL(path.resolve("Value.mjs")).href;
164
154
  fs.writeFileSync(codecPath, `
165
155
  import { Value } from ${JSON.stringify(valueModuleUrl)};
166
156
 
167
157
  export const name = "yn";
168
- export const codes = [${JSON.stringify(boolHash)}];
169
158
 
170
159
  export function parse(text) {
171
160
  const tag = text.trim();
@@ -249,11 +238,9 @@ const reloaded = createState();
249
238
  output = await evaluateInput(`:load ${libPath}`, reloaded);
250
239
  assert.equal(output[0], `loaded ${libPath}`);
251
240
 
252
- output = await evaluateInput(":types", reloaded);
253
- assert.match(output[0], /^nat = @/m);
254
-
255
241
  output = await evaluateInput(":rels", reloaded);
256
242
  assert.match(output[0], /^succ = @/m);
243
+ assert.match(output[0], /^zero = @/m);
257
244
 
258
245
  output = await evaluateInput("succ", reloaded);
259
246
  assert.equal(output[0], "{}|succ ?<{} succ, ...>");
@@ -261,25 +248,22 @@ assert.equal(output[0], "{}|succ ?<{} succ, ...>");
261
248
  const noAliasReloaded = createState();
262
249
  output = await evaluateInput(`:load --no-alias ${libPath}`, noAliasReloaded);
263
250
  assert.equal(output[0], `loaded ${libPath}`);
264
- output = await evaluateInput(":types", noAliasReloaded);
265
- assert.equal(output[0], "(none)");
266
251
  output = await evaluateInput(":rels", noAliasReloaded);
267
252
  assert.equal(output[0], "(none)");
268
253
 
269
254
  const shorthand = createState();
270
- output = await evaluateInput("$ nat = <{} zero, nat succ>\n; succ = |succ\n;", shorthand);
255
+ output = await evaluateInput("zero = {} | zero\n; succ = |succ\n;", shorthand);
271
256
  assert.match(output[0], /\/\* comp: .* \*\//);
272
- output = await evaluateInput(":types", shorthand);
273
- assert.match(output[0], /^nat = @/m);
274
257
  output = await evaluateInput(":rels", shorthand);
258
+ assert.match(output[0], /^zero = @/m);
275
259
  assert.match(output[0], /^succ = @/m);
276
- output = await evaluateInput("$ bool = <{} true, {} false>\n; not = $bool </true | false, {} | true >\n; {} | true not", shorthand);
260
+ output = await evaluateInput("not = </true | false, /false | true >\n; {} | true not", shorthand);
277
261
  assert.match(output[0], /^\{\}\|false \?</);
278
262
  assert.match(output[0], / false/);
279
263
  assert.match(output[0], / true/);
280
- output = await evaluateInput("$ maybe = <{} none, {} some>;", shorthand);
264
+ output = await evaluateInput("maybe = < /none {} | none, /some | some >;", shorthand);
281
265
  assert.match(output[0], /\/\* comp: .* \*\//);
282
- output = await evaluateInput(":types", shorthand);
266
+ output = await evaluateInput(":rels", shorthand);
283
267
  assert.match(output[0], /^maybe = @/m);
284
268
  output = await evaluateInput("{} | true not", shorthand);
285
269
  assert.match(output[0], /^\{\}\|false \?</);
@@ -291,8 +275,7 @@ await assert.rejects(
291
275
 
292
276
  // Verify WebAssembly in-process backend supports TCO / stack safety on deep recursion
293
277
  const tcoState = createState();
294
- await evaluateInput("$ nat = < {} zero, nat succ >;", tcoState);
295
- await evaluateInput("countdown = $ nat < / zero {} | zero, / succ countdown >;", tcoState);
278
+ await evaluateInput("countdown = ?< {} zero, X succ > = X < / zero {} | zero, / succ countdown >;", tcoState);
296
279
 
297
280
  let deepNat = Value.variant("zero", Value.product({}, [["closed-product", []]]), [["open-union", [["zero", 1]]], ["closed-product", []]]);
298
281
  for (let i = 0; i < 5000; i++) {
@@ -336,7 +319,7 @@ assert.equal(output[0], "unloaded codec int.mjs");
336
319
  output = await evaluateInput(":codecs", codecTestState);
337
320
  assert.equal(output[0], "(none)");
338
321
 
339
- output = await evaluateInput("$ bool = < {} true, {} false >;", codecTestState);
322
+ output = await evaluateInput("bool = < /true {} | true, /false {} | false >;", codecTestState);
340
323
  registerCodec(codecTestState, {
341
324
  name: "yn.mjs",
342
325
  parse: (text) => Value.variant(text.trim() === "yes" ? "true" : "false", Value.product({})),
@@ -390,7 +373,9 @@ const ieeeAutoState = createState();
390
373
  await evaluateInput(":load Examples/ieee.k", ieeeAutoState);
391
374
  output = await evaluateInput(":codec load ./codecs/ieee.mjs", ieeeAutoState);
392
375
  assert.match(output[0], /^loaded codec ieee\.mjs/);
393
- assert.ok(ieeeAutoState.typeAliases.ieee, "ieee type alias should be registered");
376
+ assert.ok(ieeeAutoState.codecs["ieee.mjs"], "ieee codec should be registered");
377
+ output = await evaluateInput(":input ieee.mjs 1.5", ieeeAutoState);
378
+ assert.match(output[0], /ieee\.mjs: 1\.5/);
394
379
 
395
380
  const jsonInputState = createState();
396
381
  await evaluateInput(":load core.k", jsonInputState);
@@ -453,7 +438,7 @@ const polyAutoState = createState();
453
438
  output = await evaluateInput(":load Examples/poly.k", polyAutoState);
454
439
  assert.equal(output[0], "loaded Examples/poly.k");
455
440
  assert.ok(polyAutoState.relAliases.reverse, "poly relations should be loaded");
456
- assert.ok(polyAutoState.typeAliases.int, "arithmetics int should be auto-loaded");
441
+ assert.ok(polyAutoState.relAliases.int, "arithmetics int should be auto-loaded");
457
442
 
458
443
  // Verify timing reporting is always on and reflects active engine
459
444
  const timingState = createState();
@@ -510,11 +495,11 @@ assert(completions.includes(":engine js"));
510
495
  const jsState = createState({ engine: "js" });
511
496
  assert.equal(jsState.engine, "js");
512
497
 
513
- output = await evaluateInput("$ nat = < {} zero, nat succ >;\nsucc = | succ;\n{} | zero succ succ", jsState);
498
+ output = await evaluateInput("succ = | succ;\n{} | zero succ succ", jsState);
514
499
  assert.match(output[0], /^\{\}\|zero\|succ\|succ/);
515
500
  assert.match(output[1], /\(js\)/);
516
501
 
517
- output = await evaluateInput("$ bool = < {} true, {} false >;\nnot = $bool </true | false, {} | true >;\n{} | true not", jsState);
502
+ output = await evaluateInput("not = </true | false, /false | true >;\n{} | true not", jsState);
518
503
  assert.match(output[0], /^\{\}\|false/);
519
504
  assert.match(output[1], /\(js\)/);
520
505
 
package/tests/test.mjs CHANGED
@@ -22,9 +22,8 @@ import k from "../index.mjs";
22
22
 
23
23
 
24
24
  let k_expression = `
25
- $ bool = < {} true, {} false >;
26
- true = {} | true $bool;
27
- false = {} | false $bool;
25
+ true = {} | true;
26
+ false = {} | false;
28
27
 
29
28
  list? = ?< {} nil, {X car, Y cdr} cons > = Y;
30
29
  nil = {}|nil list?;