@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
@@ -3,24 +3,18 @@ import { hash } from '../../hash.mjs';
3
3
  import assert from 'assert';
4
4
 
5
5
  t(`
6
- $b = < {} true, {} false > ;
7
- $pair = { b one, b two } ;
8
- $bit = <{} 0, {} 1> ;
9
- 1 = {} |1 $bit;
10
- $b {1 one, () two, () c} .one
6
+ 1 = {} |1 ?< {} 0, {} 1 >;
7
+ ?< {} true, {} false > {1 one, () two, () c} .one
11
8
 
12
9
  `, (annotated) => {
13
10
  const {input,output} = in_out(annotated);
14
- // console.log({input,output});
15
- assert.equal(input.type, annotated.representatives["b"]);
16
- assert.equal(output.type, annotated.representatives["bit"]);
11
+ assert.equal(input.type, "@GWnxJCupZr96BZfdpDsfQQKxKjCbjyDh7Qaur7y9enCY");
12
+ assert.equal(output.type, "@MjusyRWZnVj8TR4BhFCCcMRrQbdKp9gPtC29LT9nZvjg");
17
13
  console.log("OK");
18
14
  });
19
15
 
20
16
  t(`
21
- $bit = <{} 0, {} 1> ;
22
- $a = < bit true, bit false > ;
23
- $a /true
17
+ ?< <{} 0, {} 1> true, <{} 0, {} 1> false > /true
24
18
  `, (annotated) => {
25
19
  const {input,output} = in_out(annotated);
26
20
  console.log({input,output});
@@ -4,7 +4,7 @@ import assert from 'assert';
4
4
 
5
5
  t(fs.readFileSync("./Examples/nat.k", "utf8"), (annotated) => {
6
6
  const {input,output} = in_out(annotated);
7
- assert.equal(output.type, annotated.representatives["nat"]);
8
- assert.equal(input.type, annotated.representatives["nat"]);
7
+ assert.equal(output.type, input.type);
8
+ assert.equal(output.type, "@e9WP6QX6URfgnd9hHYrrYUBhiL7UcvbWErVmyQJfFcr8");
9
9
  console.log("OK");
10
10
  });
@@ -1,14 +1,14 @@
1
1
  import { t, in_out } from './index.mjs';
2
2
  import assert from 'assert';
3
3
 
4
- t(`$b = < {} true, {} false > ;
5
- true = {} |true $b;
6
- false = {} |false $b;
7
- not = $b < /true false, /false true >;
4
+ t(`
5
+ true = {} |true;
6
+ false = {} |false;
7
+ not = ?< {} true, {} false > < /true false, /false true > ?< {} true, {} false >;
8
8
  not not
9
9
  `, (annotated) => {
10
10
  const {input,output} = in_out(annotated);
11
- assert.equal(input.type, annotated.representatives["b"]);
12
- assert.equal(output.type, annotated.representatives["b"]);
11
+ assert.equal(input.type, output.type);
12
+ assert.equal(input.type, "@GWnxJCupZr96BZfdpDsfQQKxKjCbjyDh7Qaur7y9enCY");
13
13
  console.log("OK");
14
14
  });
@@ -12,9 +12,8 @@ const INT_PATTERN = [
12
12
  ];
13
13
 
14
14
  const script = `
15
- $ bits = < {} _, bits 0, bits 1 >;
16
- $ int = < bits +, bits - >;
17
- {}|_|0|1|+ $int
15
+ int = ?< <bits 0, bits 1, {} _>=bits "+", bits "-" >;
16
+ {}|_|0|1|+ int
18
17
  `;
19
18
 
20
19
  const result = k.compile(script)(Value.product({}));
@@ -76,9 +75,8 @@ assert.throws(
76
75
  );
77
76
 
78
77
  const projectionScript = `
79
- $ bits = < {} _, bits 0, bits 1 >;
80
- $ int = < bits +, bits - >;
81
- $int /+
78
+ int = ?< <bits 0, bits 1, {} _>=bits "+", bits "-" >;
79
+ int /+
82
80
  `;
83
81
  const annotated = k.annotate(projectionScript);
84
82
  run.defs = annotated;
@@ -12,14 +12,11 @@ t('{}', (annotated) => {
12
12
  });
13
13
 
14
14
  t(`
15
- $b = < {} true, {} false > ;
16
- $pair = { b one, b two } ;
17
-
18
- {() one, () two} $pair
15
+ ?< {} true, {} false > {() one, () two} ?{ < {} true, {} false > one, < {} true, {} false > two }
19
16
  `, (annotated) => {
20
17
  const {input,output} = in_out(annotated);
21
18
 
22
- assert.equal(input.type, annotated.representatives["b"]);
23
- assert.equal(output.type, annotated.representatives["pair"]);
19
+ assert.equal(input.type, "@GWnxJCupZr96BZfdpDsfQQKxKjCbjyDh7Qaur7y9enCY");
20
+ assert.equal(output.type, "@ZR2yff4pdXTVqZdMu9x3t9GG5rwmhEfQuenbAwFnD2Nk");
24
21
  console.log("OK");
25
22
  });
@@ -2,13 +2,12 @@ import { t, in_out } from './index.mjs';
2
2
  import assert from 'assert';
3
3
 
4
4
  t(`
5
- $nat = < {} _, nat 0, nat 1>;
6
- zero = {}|_|0 $nat;
7
- rlz = </0/_ zero, /0 rlz, ()>;
5
+ zero = {}|_|0;
6
+ rlz = ?<X 0, X 1, {} _>=X </0/_ zero, /0 rlz, ()> ?X;
8
7
  rlz
9
8
  `, (annotated) => {
10
9
  const {input,output} = in_out(annotated);
11
- assert.equal(output.type, annotated.representatives["nat"]);
12
- assert.equal(input.type, annotated.representatives["nat"]);
10
+ assert.equal(output.type, input.type);
11
+ assert.equal(output.type, "@VtPHxGf5GNMzzyVFxtv7gegFfJRYapBGtCeyV56bs5Zb");
13
12
  console.log("OK");
14
13
  });
@@ -171,7 +171,7 @@ console.log("6. Verifying pattern derivation via k type system (patternFromFilte
171
171
  assert.deepEqual(UnitCodec.UNIT_PATTERN, unitPat);
172
172
 
173
173
  const listPat = SDK.patternFromFilter(
174
- '$ bits = < bits 0, bits 1, {} _ >; $ int = < bits "+", bits "-" >; ?< {} nil, { $int car, list cdr } cons > = list'
174
+ '?< {} nil, { < <bits 0, bits 1, {} _>=bits "+", bits "-" > car, list cdr } cons > = list'
175
175
  );
176
176
  assert.deepEqual(IntCodec.INT_LIST_PATTERN, listPat);
177
177
 
@@ -1,43 +1,38 @@
1
- import k from '../index.mjs';
2
- import { encodeCodeToString, find } from '../codes.mjs';
1
+ import codes, { encodeCodeToString } from '../codes.mjs';
3
2
  import hash from '../hash.mjs';
4
- [
5
- `
6
- $bits = < bits 0, bits 1, {} _ >;
7
- $nat = < {} zero, nat succ>;
8
- $pair = {nat x, nat y};
9
- $b = { bits"x", bits y};
10
- $tree = < {nat value, tree left, tree right} binary, nat leaf, {nat value, tree tree} unary >;
11
-
12
- succ = | succ $nat;
13
- plus = $pair <
14
- {.x/zero stop, .y result} .result,
15
- {.x/succ x, .y succ y } plus
16
- > $nat;
17
- {}|zero succ succ {() x, () y} plus
18
- `
19
- ].map(function (script) {
20
- console.log("test-fingerprint:");
21
- // console.log(`k_expression = '${script}';`);
22
- const annotated = k.annotate(script);
23
- // console.log(annotated);
24
- let ERRORS = 0;
25
- for (const code in annotated.representatives) {
26
- // console.log(`CODE: ${code}`);
27
- const s = encodeCodeToString(annotated.representatives[code]);
28
- // console.log(` - DEFS: ${s}`);;
29
- const annotated2 = k.annotate(s+" {}");;
30
- const s2 = encodeCodeToString(annotated2.representatives["C0"]);
31
- // console.log(` - reparsed FINGERPRINT: ${hash(s2)}`);
32
- if (!((s === s2) && (hash(s) === hash(s2)))) {
33
- ERRORS++;
34
- console.log(` ERROR - reparsed FINGERPRINT for ${code} is different`);
35
- }
36
- }
37
- if (ERRORS === 0) {
38
- console.log("OK");
39
- } else {
40
- console.log(" ----- ERRORS");
41
- }
42
- });
3
+ import assert from 'assert';
4
+
5
+ console.log("test-fingerprint:");
6
+ const codeDefs = {
7
+ bits: { code: "union", union: { "0": "bits", "1": "bits", "_": "{}" } },
8
+ nat: { code: "union", union: { zero: "{}", succ: "nat" } },
9
+ pair: { code: "product", product: { x: "nat", y: "nat" } },
10
+ b: { code: "product", product: { x: "bits", y: "bits" } },
11
+ tree: { code: "union", union: {
12
+ binary: "binNode",
13
+ leaf: "nat",
14
+ unary: "unNode"
15
+ } },
16
+ binNode: { code: "product", product: { value: "nat", left: "tree", right: "tree" } },
17
+ unNode: { code: "product", product: { value: "nat", tree: "tree" } },
18
+ "{}": { code: "product", product: {} }
19
+ };
20
+
21
+ const reps = codes.register(codeDefs);
22
+ let errors = 0;
23
+ for (const code in reps) {
24
+ const rep = reps[code];
25
+ const s = encodeCodeToString(rep);
26
+ const h = hash(s);
27
+ if (rep !== h) {
28
+ errors++;
29
+ console.log(` ERROR - fingerprint mismatch for ${code}: ${rep} !== ${h}`);
30
+ }
31
+ }
32
+
33
+ if (errors === 0) {
34
+ console.log("OK");
35
+ } else {
36
+ console.log(" ----- ERRORS");
37
+ }
43
38
 
@@ -67,16 +67,14 @@ f
67
67
  // SCC order should not change hash
68
68
  {
69
69
  const scriptA = `
70
- $bit = < {} 0, {} 1 >;
71
- f = $bit < /0 |0 g, /1 >;
72
- g = $bit < /0 |0 f, /1 >;
70
+ f = ?< {} 0, {} 1 > < /0 |0 g, /1 >;
71
+ g = ?< {} 0, {} 1 > < /0 |0 f, /1 >;
73
72
  f
74
73
  `;
75
74
 
76
75
  const scriptB = `
77
- $bit = < {} 0, {} 1 >;
78
- g = $bit < /0 |0 f, /1 >;
79
- f = $bit < /0 |0 g, /1 >;
76
+ g = ?< {} 0, {} 1 > < /0 |0 f, /1 >;
77
+ f = ?< {} 0, {} 1 > < /0 |0 g, /1 >;
80
78
  f
81
79
  `;
82
80
 
@@ -6,25 +6,25 @@ import codes from "../codes.mjs";
6
6
  import { parse as parseFloat64, print as printFloat64 } from "../codecs/ieee.mjs";
7
7
  import { closedPatternToCodeHash, valueForCode } from "../repl-codecs.mjs";
8
8
 
9
- const state = createState();
9
+ const state = createState({ engine: "js" });
10
10
  await evaluateInput(":load Examples/ieee.k", state);
11
11
 
12
12
  for (const name of ["add", "sub", "mul", "div"]) {
13
13
  assert.ok(state.relAliases[name], `Expected public IEEE relation '${name}'`);
14
14
  }
15
15
 
16
- const float64Hash = state.typeAliases.float64;
17
- const floatPairHash = state.typeAliases.float_pair;
16
+ const sampleFloat = parseFloat64("0");
17
+ const float64Hash = closedPatternToCodeHash(sampleFloat.pattern);
18
18
 
19
19
  function float64(text) {
20
- return valueForCode(parseFloat64(text), float64Hash, codes.find);
20
+ return parseFloat64(text);
21
21
  }
22
22
 
23
23
  function floatPair(x, y) {
24
- return valueForCode(Value.product({
24
+ return Value.product({
25
25
  x: float64(x),
26
26
  y: float64(y)
27
- }), floatPairHash, codes.find);
27
+ });
28
28
  }
29
29
 
30
30
  async function runOperation(op, x, y) {
@@ -40,7 +40,6 @@ async function runProjectedResult(op, x, y) {
40
40
  }
41
41
 
42
42
  function assertFloatResult(value, expected, label) {
43
- assert.equal(closedPatternToCodeHash(value.pattern), float64Hash, `${label}: result should keep float64 envelope`);
44
43
  assert.equal(printFloat64(value), expected, label);
45
44
  }
46
45
 
@@ -51,9 +51,7 @@ const INT_PATTERN = [
51
51
  ];
52
52
 
53
53
  const objectBuffer = compileObjectBuffer(`
54
- $ bits = < {} _, bits 0, bits 1 >;
55
- $ int = < bits +, bits - >;
56
- {}|_|0|1|+ $int
54
+ {}|_|0|1|+ ?< <bits 0, bits 1, {} _>=bits "+", bits "-">
57
55
  `);
58
56
  assert.equal(objectBuffer.subarray(0, 5).toString("utf8"), "KOBJ\n");
59
57
  const object = decodeObject(objectBuffer);
@@ -84,19 +82,17 @@ const decompiledSource = decompileObjectBuffer(objectBuffer);
84
82
  const decompiledResult = k.compile(decompiledSource)(Value.product({}));
85
83
  assert.deepEqual(decompiledResult.pattern, INT_PATTERN);
86
84
  assert.deepEqual(decompiledResult.toJSON(), objectResult.toJSON());
87
- assert.match(decompiledSource, /^----- codes -----$/m);
88
85
  assert.match(decompiledSource, /^----- rels -----$/m);
89
86
  assert.match(decompiledSource, /^----- main -----$/m);
90
- assert.match(decompiledSource, /\$ Nws3 =/);
91
- assert.match(decompiledSource, /^7jfi = /m);
92
- assert.match(decompiledSource, /^----- main -----\n\?\(\.\.\.\) 7jfi \$Nws3$/m);
87
+ assert.match(decompiledSource, /^[A-Za-z0-9_]+ = /m);
88
+ assert.match(decompiledSource, /^----- main -----\n\?\(\.\.\.\) [A-Za-z0-9_]+ \?<<X0 0, X0 1, {} _>=X0 \+, X0 ->$/m);
93
89
 
94
90
  const natLibraryBuffer = compileLibraryBuffer(fs.readFileSync("Examples/nat.k", "utf8"), { source: "Examples/nat.k" });
95
91
  const natDecompiledSource = decompileObjectBuffer(natLibraryBuffer);
96
92
  const natRoundTripSource = decompileObjectBuffer(
97
93
  compileLibraryBuffer(natDecompiledSource, { source: "Examples/nat.decompiled.k" })
98
94
  );
99
- const recursiveNatPattern = /\$dTww <\{\.x PgmQ x, \.y h4Wg y\} re64, \.y> \$e9WP;/;
95
+ const recursiveNatPattern = /\?\{<\{\} 0, X0 \+1>=X0 x, <X1 \+1, \.\.\.>=X1 y\} <\{\.x [A-Za-z0-9_]+ x, \.y [A-Za-z0-9_]+ y\} [A-Za-z0-9_]+, \.y> \?X1;/;
100
96
  assert.equal(natRoundTripSource, natDecompiledSource);
101
97
  assert.match(natDecompiledSource, recursiveNatPattern);
102
98
 
@@ -111,14 +107,14 @@ const arithmeticsRoundTripSource = decompileObjectBuffer(
111
107
  assert.equal(arithmeticsRoundTripSource, arithmeticsDecompiledSource);
112
108
 
113
109
  assert.throws(() => k.compile("@A = (); @A"), /Parse error/);
114
- assert.throws(() => k.compile("$ @A = {}; $@A"), /Parse error/);
110
+ assert.throws(() => k.compile("$ @A = {}; $@A"), /Lexical error/);
115
111
  assert.deepEqual(k.compile("7jfi = ?X0; 7jfi")(Value.product({})).toJSON(), {});
116
112
 
117
113
  const sccSource = decompileObjectBuffer(compileObjectBuffer("c = {}; b = c |x; a = b |y; a"));
118
- assert.match(sccSource, /----- rels -----\nPQgV = .+\n\naQAD = .+\n\nN9UH = /s);
114
+ assert.match(sccSource, /----- rels -----\n[A-Za-z0-9_]+ = .+\n\n[A-Za-z0-9_]+ = .+\n\n[A-Za-z0-9_]+ = /s);
119
115
  assert.deepEqual(k.compile(sccSource)(Value.product({})).toJSON(), { y: "x" });
120
116
 
121
- const libraryBuffer = compileLibraryBuffer("$ nat = <{} zero, nat succ>;\nsucc = |succ;\n", { source: "defs-only.k" });
117
+ const libraryBuffer = compileLibraryBuffer("zero = {}|zero;\nsucc = |succ;\n", { source: "defs-only.k" });
122
118
  assert.equal(libraryBuffer.subarray(0, 1).toString("utf8"), "{");
123
119
  const library = decodeObject(libraryBuffer);
124
120
  assert.equal("version" in library, false);
@@ -133,10 +129,10 @@ assert(Object.values(library.rels).every((rel) =>
133
129
  ));
134
130
  assert(Object.values(library.rels).every((rel) => rel.def.op !== "comp" || rel.def.comp[0]?.op !== "filter"));
135
131
  assert(Object.values(library.meta).some(({ type, origins }) =>
136
- type === "code" &&
132
+ type === "rel" &&
137
133
  origins.some((origin) =>
138
134
  origin.source === "defs-only.k" &&
139
- origin.name === "nat" &&
135
+ origin.name === "zero" &&
140
136
  typeof origin.compiledAt === "string" &&
141
137
  origin.start &&
142
138
  origin.end
@@ -158,11 +154,11 @@ const derivedLibrary = decodeObject(compileLibraryBuffer("other = |other;\n", {
158
154
  libraries: [library]
159
155
  }));
160
156
  const derivedAliases = extractAliasesFromObject(derivedLibrary);
161
- assert.match(derivedAliases, /^\$ nat = @/m);
157
+ assert.match(derivedAliases, /^zero = @/m);
162
158
  assert.match(derivedAliases, /^succ = @/m);
163
159
  assert.match(derivedAliases, /^other = @/m);
164
- assert(derivedAliases.indexOf("$ nat = @") < derivedAliases.indexOf("other = @"));
165
160
  assert(derivedAliases.indexOf("other = @") < derivedAliases.indexOf("succ = @"));
161
+ assert(derivedAliases.indexOf("succ = @") < derivedAliases.indexOf("zero = @"));
166
162
 
167
163
  {
168
164
  const warn = console.warn;
@@ -9,7 +9,6 @@ import {
9
9
  import { validateKIRP } from "../objects/validate.mjs";
10
10
 
11
11
  const object = decodeObject(compileObjectBuffer(`
12
- $ bit = < {} 0, {} 1 >;
13
12
  id = ();
14
13
  .x id
15
14
  `, { source: "kir-test.k" }));
@@ -91,8 +91,7 @@ console.log("==> Starting Polymorphic kVM & Specialization Tests");
91
91
  // Test 3: Type Error on Envelope Mismatch
92
92
  {
93
93
  const script = `
94
- $ bool = < {} true, {} false >;
95
- check = $bool;
94
+ check = ?< {} true, {} false >;
96
95
  check
97
96
  `;
98
97
  const obj = decodeObject(compileObjectBuffer(script));
@@ -84,8 +84,7 @@ console.log("==> Starting kVM Tests");
84
84
  // Test 7: Filters & Types
85
85
  {
86
86
  const script = `
87
- $ bool = < {} true, {} false >;
88
- $ bool
87
+ ?< {} true, {} false >
89
88
  `;
90
89
  const result1 = runKVM(script, { true: {} });
91
90
  assert.deepEqual(toJSON(result1), "true");
@@ -98,9 +97,8 @@ console.log("==> Starting kVM Tests");
98
97
  // Test 8: Recursive List traversal (Cons/Nil)
99
98
  {
100
99
  const script = `
101
- $ bool = < {} true, {} false >;
102
- true = {} | true $bool;
103
- false = {} | false $bool;
100
+ true = {} | true;
101
+ false = {} | false;
104
102
 
105
103
  list? = ?< {} nil, {X car, Y cdr} cons > = Y;
106
104
  nil = {}|nil list?;
@@ -130,12 +128,11 @@ console.log("==> Starting kVM Tests");
130
128
  // Test 9: Comparing KVM execution vs Native JS run (Envelope-aware and Envelope-free)
131
129
  {
132
130
  const script = `
133
- $ nat = < {} 0, nat +1 >;
134
- 0 = {} | 0 $ nat;
135
- inc = | +1 $ nat;
136
- dec = $ nat / +1;
137
- add = $ { nat x, nat y } <
138
- { . x dec x, . y inc y } add,
131
+ 0 = {} | 0;
132
+ inc = | +1;
133
+ dec = / +1;
134
+ add = ?{ < {} 0, N +1 > = N x, ... } = X <
135
+ { . x dec x, . y inc y } ?X add,
139
136
  . y
140
137
  >;
141
138
  `;
@@ -581,6 +581,7 @@ if (chromiumBin) {
581
581
  const hasTime = modalText.includes(":time");
582
582
  const hasT = modalText.includes(":t <name>");
583
583
  const hasCodecDefine = modalText.includes(":codec define");
584
+ const hasRels = modalText.includes(":rels");
584
585
  const hasType = modalText.includes(":type <name>");
585
586
  const hasTypes = modalText.includes(":types");
586
587
  const hasCodes = modalText.includes(":codes");
@@ -592,6 +593,7 @@ if (chromiumBin) {
592
593
  rect: { left: rect.left, right: rect.right, top: rect.top, bottom: rect.bottom },
593
594
  helpModalOpen,
594
595
  hasRel,
596
+ hasRels,
595
597
  hasVal,
596
598
  hasTiming,
597
599
  hasTime,
@@ -608,8 +610,9 @@ if (chromiumBin) {
608
610
  assert.strictEqual(narrowNavbarCheck.isVisible, true, "#btn-help should be visible within narrow viewport");
609
611
  assert.strictEqual(narrowNavbarCheck.helpModalOpen, true, "Clicking #btn-help in narrow viewport should open help modal");
610
612
  assert.strictEqual(narrowNavbarCheck.hasRel, true, "Help modal should contain :rel <name>");
611
- assert.strictEqual(narrowNavbarCheck.hasType, true, "Help modal should contain :type <name>");
612
- assert.strictEqual(narrowNavbarCheck.hasTypes, true, "Help modal should contain :types");
613
+ assert.strictEqual(narrowNavbarCheck.hasRels, true, "Help modal should contain :rels");
614
+ assert.strictEqual(narrowNavbarCheck.hasType, false, "Help modal should not contain :type <name>");
615
+ assert.strictEqual(narrowNavbarCheck.hasTypes, false, "Help modal should not contain :types");
613
616
  assert.strictEqual(narrowNavbarCheck.hasEngine, true, "Help modal should contain :engine");
614
617
  assert.strictEqual(narrowNavbarCheck.hasCodes, false, "Help modal should not contain :codes");
615
618
  assert.strictEqual(narrowNavbarCheck.hasTime, false, "Help modal should not contain :time");