@fraczak/k 7.1.0 → 8.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 (64) hide show
  1. package/CHANGELOG.md +99 -0
  2. package/DOCS/BIG_PICTURE.md +54 -7
  3. package/DOCS/CODECS.md +47 -2
  4. package/DOCS/CODEC_ARCHITECTURE.md +14 -5
  5. package/DOCS/DICTIONARY.md +13 -4
  6. package/DOCS/FILE_FORMATS.md +3 -2
  7. package/DOCS/JSON_APPROACHES_COMPARISON.md +306 -0
  8. package/DOCS/NAMED_PATTERNS.md +317 -0
  9. package/DOCS/PATTERNS.md +59 -11
  10. package/DOCS/REPL.md +24 -5
  11. package/DOCS/WEB_REPL_REQUIREMENTS.md +4 -2
  12. package/Examples/arithmetics.k +22 -17
  13. package/Examples/bnat.k +21 -11
  14. package/Examples/buda.k +37 -20
  15. package/Examples/byte.k +3 -1
  16. package/Examples/code.k +38 -39
  17. package/Examples/djson-btrie.k +414 -0
  18. package/Examples/djson-ptrie.k +663 -0
  19. package/Examples/djson.k +323 -0
  20. package/Examples/esc.k +1 -1
  21. package/Examples/karatsuba-mult.k +16 -13
  22. package/Examples/list.k +8 -4
  23. package/Examples/nat.k +17 -11
  24. package/Examples/poly.k +11 -3
  25. package/Examples/vhdl_to_k.k +43 -31
  26. package/README.md +42 -15
  27. package/Value.mjs +28 -3
  28. package/backend-api.mjs +5 -1
  29. package/browser/repl-browser.mjs +6 -0
  30. package/browser/tree-view.mjs +82 -24
  31. package/browser/vfs-data.mjs +21 -12
  32. package/codecs/README.md +3 -0
  33. package/codecs/djson-btrie.mjs +560 -0
  34. package/codecs/djson-ptrie.mjs +587 -0
  35. package/codecs/djson.mjs +270 -0
  36. package/codecs/int.mjs +2 -1
  37. package/codecs/json.mjs +7 -2
  38. package/codecs/k-parse.mjs +7 -1
  39. package/codecs/k-print.mjs +4 -0
  40. package/codecs/runtime/codec-sdk.mjs +16 -2
  41. package/codecs/runtime/pattern-json.mjs +80 -1
  42. package/codecs/runtime/prefix-codec.mjs +629 -67
  43. package/codecs/runtime/show-value.mjs +93 -51
  44. package/codecs/runtime/unicode-string.mjs +29 -6
  45. package/codecs/show.mjs +4 -0
  46. package/codecs/utf16.mjs +2 -1
  47. package/core.k +79 -115
  48. package/index.mjs +3 -0
  49. package/named-patterns.mjs +267 -0
  50. package/object.mjs +31 -3
  51. package/package.json +5 -1
  52. package/parser.jison +68 -5
  53. package/parser.mjs +111 -60
  54. package/pretty.mjs +5 -0
  55. package/repl.mjs +245 -28
  56. package/scripts/build-repl-html.mjs +76 -5
  57. package/scripts/perf-djson.mjs +1142 -0
  58. package/scripts/run-tests.mjs +5 -0
  59. package/symbol-table.mjs +20 -2
  60. package/tests/bench-djson-tries.mjs +340 -0
  61. package/tests/test-codecs.mjs +211 -0
  62. package/tests/test-named-patterns.mjs +189 -0
  63. package/tests/test-repl-html.mjs +52 -4
  64. package/tests/test-repl.mjs +223 -0
package/Value.mjs CHANGED
@@ -193,15 +193,40 @@ class Value {
193
193
 
194
194
  toJSON() {
195
195
  if (isVariant(this)) {
196
- if (isProduct(this.value) && Object.keys(this.value.product).length === 0) {
196
+ if (
197
+ isProduct(this.value) &&
198
+ Object.keys(this.value.product).length === 0
199
+ ) {
197
200
  return this.tag;
198
201
  }
199
- return {[this.tag]: this.value.toJSON()};
202
+ const tags = [];
203
+ let curr = this;
204
+ while (isVariant(curr)) {
205
+ if (
206
+ isProduct(curr.value) &&
207
+ Object.keys(curr.value.product).length === 0
208
+ ) {
209
+ let res = curr.tag;
210
+ for (let i = tags.length - 1; i >= 0; i--) {
211
+ res = { [tags[i]]: res };
212
+ }
213
+ return res;
214
+ }
215
+ tags.push(curr.tag);
216
+ curr = curr.value;
217
+ }
218
+ let res = curr
219
+ ? (typeof curr.toJSON === "function" ? curr.toJSON() : curr)
220
+ : null;
221
+ for (let i = tags.length - 1; i >= 0; i--) {
222
+ res = { [tags[i]]: res };
223
+ }
224
+ return res;
200
225
  }
201
226
  if (!isProduct(this)) return { type: this.type };
202
227
  let vector = toVector(this.product);
203
228
  if (vector.length > 0) return vector;
204
- return this.product;
229
+ return this.product;
205
230
  }
206
231
  }
207
232
  export { Value, fromObject, cloneSubpattern, edgeSubpattern, composePattern, mergePatterns, withPattern, isProduct, isVariant, isValue };
package/backend-api.mjs CHANGED
@@ -1,6 +1,10 @@
1
1
  export { annotate } from "./index.mjs";
2
2
  export { KVM_FORMAT, KVM_VERSION, lowerKIRRelationToKVM, lowerKIRToKVM, lowerToKVM, executeKVM, objectToKVMArtifact, specializeKVM } from "./kvm.mjs";
3
- export { decodeWire, encodeToWire } from "./codecs/runtime/prefix-codec.mjs";
3
+ export {
4
+ decodeWire,
5
+ decodeWireLazy,
6
+ encodeToWire
7
+ } from "./codecs/runtime/prefix-codec.mjs";
4
8
  export { exportPatternGraph, NODE_KIND } from "./codecs/runtime/codec.mjs";
5
9
  export { patternToPropertyList, propertyListToPattern } from "./codecs/runtime/pattern-json.mjs";
6
10
  export { Value, fromObject, isProduct, isVariant, isValue } from "./Value.mjs";
@@ -632,6 +632,12 @@ function renderCodecsModal() {
632
632
  targetDesc = "{}";
633
633
  } else if (entry.name === "json.mjs") {
634
634
  targetDesc = "Self-describing JSON";
635
+ } else if (entry.name === "djson.mjs") {
636
+ targetDesc = "$ json (cons-list)";
637
+ } else if (entry.name === "djson-btrie.mjs") {
638
+ targetDesc = "$ json (binary bit-trie)";
639
+ } else if (entry.name === "djson-ptrie.mjs") {
640
+ targetDesc = "$ json (radix/Patricia trie)";
635
641
  } else if (Array.isArray(entry.patterns) && entry.patterns.length > 0) {
636
642
  targetDesc = `Pattern Family (${entry.patterns.length})`;
637
643
  } else if (entry.pattern) {
@@ -101,7 +101,9 @@ export function renderValueNode(val, currentDepth = 1, depthLimit = 3) {
101
101
  const populateChildren = () => {
102
102
  if (populated) return;
103
103
  populated = true;
104
- for (const k of keys) {
104
+ const maxFields = 100;
105
+ const displayKeys = keys.slice(0, maxFields);
106
+ for (const k of displayKeys) {
105
107
  const row = document.createElement("div");
106
108
  row.className = "k-tree-row";
107
109
 
@@ -113,12 +115,25 @@ export function renderValueNode(val, currentDepth = 1, depthLimit = 3) {
113
115
  const childContainer = document.createElement("div");
114
116
  childContainer.className = "k-tree-child-val";
115
117
  childContainer.appendChild(
116
- renderValueNode(val.product[k], isOpen ? currentDepth + 1 : 1, depthLimit)
118
+ renderValueNode(
119
+ val.product[k],
120
+ isOpen ? currentDepth + 1 : 1,
121
+ depthLimit
122
+ )
117
123
  );
118
124
  row.appendChild(childContainer);
119
125
 
120
126
  childrenContainer.appendChild(row);
121
127
  }
128
+ if (keys.length > maxFields) {
129
+ const moreRow = document.createElement("div");
130
+ moreRow.className = "k-tree-row k-tree-more";
131
+ moreRow.style.color = "var(--color-muted)";
132
+ moreRow.style.paddingLeft = "1.2rem";
133
+ moreRow.textContent =
134
+ `... and ${keys.length - maxFields} more fields`;
135
+ childrenContainer.appendChild(moreRow);
136
+ }
122
137
  };
123
138
 
124
139
  if (isOpen) {
@@ -169,13 +184,15 @@ export function renderValueNode(val, currentDepth = 1, depthLimit = 3) {
169
184
  if (isVariant(val.value)) {
170
185
  let chainCount = 0;
171
186
  let curr = val.value;
172
- while (isVariant(curr)) {
187
+ while (isVariant(curr) && chainCount < 20) {
173
188
  chainCount++;
174
189
  curr = curr.value;
175
190
  }
176
191
  const badge = document.createElement("span");
177
192
  badge.className = "k-tree-badge";
178
- badge.textContent = `+${chainCount} tags`;
193
+ badge.textContent = isVariant(curr)
194
+ ? "+20+ tags"
195
+ : `+${chainCount} tags`;
179
196
  summary.appendChild(badge);
180
197
  }
181
198
 
@@ -438,7 +455,7 @@ export function createOutputEntryElement({
438
455
  modeGroup.appendChild(rawBtn);
439
456
  toolbar.appendChild(modeGroup);
440
457
 
441
- // Tree Action buttons group (Expand / Collapse / Copy)
458
+ // Tree Action buttons group (Expand / Collapse)
442
459
  const actionGroup = document.createElement("div");
443
460
  actionGroup.className = "k-action-group";
444
461
 
@@ -454,23 +471,8 @@ export function createOutputEntryElement({
454
471
  collapseAllBtn.innerHTML = `⊟ Collapse`;
455
472
  collapseAllBtn.title = "Reset trees to top 3 levels";
456
473
 
457
- const copyBtn = document.createElement("button");
458
- copyBtn.type = "button";
459
- copyBtn.className = "k-btn-action";
460
- copyBtn.innerHTML = `📋 Copy`;
461
- copyBtn.title = "Copy raw output to clipboard";
462
- copyBtn.onclick = (e) => {
463
- e.stopPropagation();
464
- navigator.clipboard.writeText(rawText);
465
- copyBtn.innerHTML = `✓ Copied`;
466
- setTimeout(() => {
467
- copyBtn.innerHTML = `📋 Copy`;
468
- }, 1500);
469
- };
470
-
471
474
  actionGroup.appendChild(expandAllBtn);
472
475
  actionGroup.appendChild(collapseAllBtn);
473
- actionGroup.appendChild(copyBtn);
474
476
  toolbar.appendChild(actionGroup);
475
477
 
476
478
  container.appendChild(toolbar);
@@ -486,7 +488,32 @@ export function createOutputEntryElement({
486
488
 
487
489
  const valSummary = document.createElement("summary");
488
490
  valSummary.className = "k-tree-section-summary";
489
- valSummary.innerHTML = `<span class="k-tree-arrow">▶</span> <span class="k-section-title">🌲 Value</span> <span class="k-section-preview">${escapeHtml(valueToK(value))}</span>`;
491
+ const rawValPreview = valueToK(value, 120);
492
+ const valPreview = rawValPreview.length > 120
493
+ ? `${rawValPreview.slice(0, 120)}...`
494
+ : rawValPreview;
495
+ const valEscaped = escapeHtml(valPreview);
496
+ valSummary.innerHTML =
497
+ `<span class="k-tree-arrow">▶</span> ` +
498
+ `<span class="k-section-title">🌲 Value</span> ` +
499
+ `<span class="k-section-preview">${valEscaped}</span>`;
500
+
501
+ const copyValBtn = document.createElement("button");
502
+ copyValBtn.type = "button";
503
+ copyValBtn.className = "k-btn-action k-btn-copy k-btn-copy-value";
504
+ copyValBtn.innerHTML = `📋 Copy`;
505
+ copyValBtn.title = "Copy value definition to clipboard";
506
+ copyValBtn.onclick = (e) => {
507
+ e.preventDefault();
508
+ e.stopPropagation();
509
+ const valStr = valueToK(value);
510
+ navigator.clipboard.writeText(valStr);
511
+ copyValBtn.innerHTML = `✓ Copied`;
512
+ setTimeout(() => {
513
+ copyValBtn.innerHTML = `📋 Copy`;
514
+ }, 1500);
515
+ };
516
+ valSummary.appendChild(copyValBtn);
490
517
  valSection.appendChild(valSummary);
491
518
 
492
519
  const valBody = document.createElement("div");
@@ -504,8 +531,32 @@ export function createOutputEntryElement({
504
531
 
505
532
  const patSummary = document.createElement("summary");
506
533
  patSummary.className = "k-tree-section-summary";
507
- const patPreview = propertyListToFilter(value.pattern);
508
- patSummary.innerHTML = `<span class="k-tree-arrow">▶</span> <span class="k-section-title">🌿 Pattern</span> <span class="k-section-preview">?${escapeHtml(patPreview)}</span>`;
534
+ const rawPatPreview = propertyListToFilter(value.pattern, "X", 120);
535
+ const patPreview = rawPatPreview.length > 120
536
+ ? `${rawPatPreview.slice(0, 120)}...`
537
+ : rawPatPreview;
538
+ const patEscaped = escapeHtml(patPreview);
539
+ patSummary.innerHTML =
540
+ `<span class="k-tree-arrow">▶</span> ` +
541
+ `<span class="k-section-title">🌿 Pattern</span> ` +
542
+ `<span class="k-section-preview">?${patEscaped}</span>`;
543
+
544
+ const copyPatBtn = document.createElement("button");
545
+ copyPatBtn.type = "button";
546
+ copyPatBtn.className = "k-btn-action k-btn-copy k-btn-copy-pattern";
547
+ copyPatBtn.innerHTML = `📋 Copy`;
548
+ copyPatBtn.title = "Copy pattern definition to clipboard";
549
+ copyPatBtn.onclick = (e) => {
550
+ e.preventDefault();
551
+ e.stopPropagation();
552
+ const patStr = `?${propertyListToFilter(value.pattern, "X")}`;
553
+ navigator.clipboard.writeText(patStr);
554
+ copyPatBtn.innerHTML = `✓ Copied`;
555
+ setTimeout(() => {
556
+ copyPatBtn.innerHTML = `📋 Copy`;
557
+ }, 1500);
558
+ };
559
+ patSummary.appendChild(copyPatBtn);
509
560
  patSection.appendChild(patSummary);
510
561
 
511
562
  patBody = document.createElement("div");
@@ -545,7 +596,14 @@ export function createOutputEntryElement({
545
596
 
546
597
  const rawPre = document.createElement("pre");
547
598
  rawPre.className = "k-raw-pre";
548
- rawPre.textContent = rawText;
599
+ const MAX_RAW_PRE_CHARS = 100000;
600
+ if (rawText.length > MAX_RAW_PRE_CHARS) {
601
+ rawPre.textContent =
602
+ rawText.slice(0, MAX_RAW_PRE_CHARS) +
603
+ `\n\n... [truncated, ${rawText.length - MAX_RAW_PRE_CHARS} more characters]`;
604
+ } else {
605
+ rawPre.textContent = rawText;
606
+ }
549
607
  rawWrapper.appendChild(rawPre);
550
608
 
551
609
  container.appendChild(rawWrapper);