@fraczak/k 6.10.1 → 6.10.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.
- package/CHANGELOG.md +9 -0
- package/codecs/runtime/show-value.mjs +68 -16
- package/package.json +1 -1
- package/tests/test-repl-html.mjs +19 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,15 @@ All notable changes to this project will be documented here.
|
|
|
5
5
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
6
|
This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [6.10.2] — 2026-10-03 — Stack-Safe Value Serializer for REPL and Web REPL
|
|
9
|
+
|
|
10
|
+
### REPL & Codecs
|
|
11
|
+
|
|
12
|
+
- **Stack-Safe `valueToK()` Serializer**: Rewrote `valueToK()` in `codecs/runtime/show-value.mjs` using an explicit iterative worklist stack instead of JavaScript call-stack recursion. This prevents `RangeError: Maximum call stack size exceeded` crashes when displaying or previewing large, deep data structures (such as long lists) in the terminal REPL and Web REPL (`repl.html`).
|
|
13
|
+
- **Web REPL Tests**: Added end-to-end browser tests in `tests/test-repl-html.mjs` verifying list sorting (`poly.k`) and 10,000-element tail-loop compaction in `repl.html` under the `wasm` engine.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
8
17
|
## [6.10.1] — 2026-10-02 — Fix Compaction Mark Reset and False Tail Calls in LLVM & WASM Backends
|
|
9
18
|
|
|
10
19
|
### LLVM & WebAssembly Backends
|
|
@@ -49,24 +49,76 @@ function propertyListToFilter(propertyList, varPrefix = "X") {
|
|
|
49
49
|
return fmt(0);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
function valueToK(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
function valueToK(root) {
|
|
53
|
+
let result = "";
|
|
54
|
+
const stack = [{
|
|
55
|
+
val: root,
|
|
56
|
+
assign(s) { result = s; }
|
|
57
|
+
}];
|
|
58
|
+
|
|
59
|
+
while (stack.length > 0) {
|
|
60
|
+
const frame = stack.pop();
|
|
61
|
+
if (frame.finishProduct) {
|
|
62
|
+
frame.assign(`{${frame.parts.join(", ")}}`);
|
|
63
|
+
continue;
|
|
59
64
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
if (frame.finishVariant) {
|
|
66
|
+
const base = frame.base;
|
|
67
|
+
const tags = frame.tags;
|
|
68
|
+
frame.assign(tags.length === 0 ? base : `${base}|${tags.reverse().join("|")}`);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const v = frame.val;
|
|
73
|
+
if (isVariant(v)) {
|
|
74
|
+
const tags = [];
|
|
75
|
+
let curr = v;
|
|
76
|
+
while (isVariant(curr)) {
|
|
77
|
+
tags.push(pLabel(curr.tag).trimStart());
|
|
78
|
+
curr = curr.value;
|
|
79
|
+
}
|
|
80
|
+
const finishFrame = {
|
|
81
|
+
finishVariant: true,
|
|
82
|
+
tags,
|
|
83
|
+
base: "",
|
|
84
|
+
assign: frame.assign
|
|
85
|
+
};
|
|
86
|
+
stack.push(finishFrame);
|
|
87
|
+
stack.push({
|
|
88
|
+
val: curr,
|
|
89
|
+
assign(s) { finishFrame.base = s; }
|
|
90
|
+
});
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (isProduct(v)) {
|
|
95
|
+
const keys = Object.keys(v.product);
|
|
96
|
+
if (keys.length === 0) {
|
|
97
|
+
frame.assign("{}");
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const parts = new Array(keys.length);
|
|
101
|
+
const finishFrame = {
|
|
102
|
+
finishProduct: true,
|
|
103
|
+
parts,
|
|
104
|
+
assign: frame.assign
|
|
105
|
+
};
|
|
106
|
+
stack.push(finishFrame);
|
|
107
|
+
for (let i = keys.length - 1; i >= 0; i--) {
|
|
108
|
+
const k = keys[i];
|
|
109
|
+
const label = pLabel(k);
|
|
110
|
+
stack.push({
|
|
111
|
+
val: v.product[k],
|
|
112
|
+
assign(s) { parts[i] = `${s}${label}`; }
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
frame.assign(String(v));
|
|
68
119
|
}
|
|
69
|
-
|
|
120
|
+
|
|
121
|
+
return result;
|
|
70
122
|
}
|
|
71
123
|
|
|
72
124
|
function valueWithEnvelopeToK(value) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fraczak/k",
|
|
3
|
-
"version": "6.10.
|
|
3
|
+
"version": "6.10.2",
|
|
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
|
"exports": {
|
package/tests/test-repl-html.mjs
CHANGED
|
@@ -358,6 +358,25 @@ if (chromiumBin) {
|
|
|
358
358
|
})()`);
|
|
359
359
|
assert(ieeeResult.includes('ieee.mjs: 3.14159'), `Expected ieee.mjs: 3.14159, got: ${ieeeResult}`);
|
|
360
360
|
|
|
361
|
+
// Test :load poly.k and evaluate '10 int (gen_list sort)' in WASM mode
|
|
362
|
+
const sortListResult = await evaluateAsync(`(async () => {
|
|
363
|
+
await window.kRepl.executeCommand(":reset");
|
|
364
|
+
await window.kRepl.executeCommand(":load arithmetics.k");
|
|
365
|
+
await window.kRepl.executeCommand(":load poly.k");
|
|
366
|
+
await window.kRepl.executeCommand(":codec load int.mjs");
|
|
367
|
+
await window.kRepl.executeCommand("10 int (gen_list sort)");
|
|
368
|
+
const lines = Array.from(document.querySelectorAll(".entry-line")).map(el => el.textContent);
|
|
369
|
+
return lines[lines.length - 1];
|
|
370
|
+
})()`);
|
|
371
|
+
assert(sortListResult.includes('int.mjs: [0,1,2,3,4,5,6,7,8,9,10]'), `Expected sorted int list in browser REPL output, got: ${sortListResult}`);
|
|
372
|
+
|
|
373
|
+
// Test deep tail-loop list generation and compaction (10,000 elements) in browser WASM mode
|
|
374
|
+
const deepWasmResult = await evaluateAsync(`(async () => {
|
|
375
|
+
await window.kRepl.executeCommand("{{{10 int x, 10 int y} times x, 10 int y} times x, 10 int y} times (gen_list car)");
|
|
376
|
+
const lines = Array.from(document.querySelectorAll(".entry-line")).map(el => el.textContent);
|
|
377
|
+
return lines[lines.length - 1];
|
|
378
|
+
})()`);
|
|
379
|
+
assert(deepWasmResult.includes('int.mjs: 0'), `Expected 0 from car of 10,000-element list in browser REPL, got: ${deepWasmResult}`);
|
|
361
380
|
|
|
362
381
|
// Verify text selection holds in output element
|
|
363
382
|
const selectionCheck = await evaluateAsync(`(() => {
|