@fraczak/k 6.4.0 → 6.6.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.
- package/CHANGELOG.md +17 -0
- package/Examples/arithmetics.k +86 -63
- package/Value.mjs +8 -2
- package/backends/arm64/src/runtime.c +20 -4
- package/backends/arm64/tests/integration.sh +1 -1
- package/backends/llvm/runtime/krt.c +387 -2
- package/backends/llvm/runtime/krt.h +1 -0
- package/backends/llvm/src/kvm2llvm.mjs +98 -29
- package/backends/llvm/tests/perf-support.mjs +1 -1
- package/backends/wasm/TECHNICAL-DEBT.md +11 -13
- package/backends/wasm/runtime.wat +375 -2
- package/backends/wasm/src/kvm2wasm.mjs +36 -0
- package/backends/wasm/src/wasm.mjs +48 -4
- package/backends/wasm/tests/test-wasm.mjs +8 -0
- package/browser/repl-browser.mjs +24 -7
- package/browser/tree-view.mjs +599 -0
- package/browser/vfs-data.mjs +3 -3
- package/codecs/runtime/show-value.mjs +10 -1
- package/package.json +1 -1
- package/repl.mjs +4 -0
- package/scripts/build-repl-html.mjs +301 -0
- package/scripts/perf-ieee.mjs +5 -2
- package/scripts/perf-int.mjs +331 -0
- package/scripts/run-tests.mjs +1 -0
- package/tests/test-repl-html.mjs +141 -0
- package/tests/test-tree-view.mjs +185 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { Value } from "../Value.mjs";
|
|
3
|
+
import {
|
|
4
|
+
renderValueNode,
|
|
5
|
+
renderPatternTree,
|
|
6
|
+
createOutputEntryElement
|
|
7
|
+
} from "../browser/tree-view.mjs";
|
|
8
|
+
|
|
9
|
+
console.log("=== Testing Tree View (browser/tree-view.mjs) ===");
|
|
10
|
+
|
|
11
|
+
// Lightweight DOM mock for testing tree construction in Node.js
|
|
12
|
+
class MockElement {
|
|
13
|
+
constructor(tagName) {
|
|
14
|
+
this.tagName = tagName.toUpperCase();
|
|
15
|
+
this.className = "";
|
|
16
|
+
this._textContent = "";
|
|
17
|
+
this._innerHTML = "";
|
|
18
|
+
this.open = false;
|
|
19
|
+
this.children = [];
|
|
20
|
+
this.listeners = {};
|
|
21
|
+
this.style = {};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get textContent() {
|
|
25
|
+
if (this._textContent) return this._textContent;
|
|
26
|
+
return this.children.map((c) => (typeof c === "string" ? c : c.textContent)).join("");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
set textContent(val) {
|
|
30
|
+
this._textContent = String(val);
|
|
31
|
+
this.children = [];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get innerHTML() {
|
|
35
|
+
return this._innerHTML || this.textContent;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
set innerHTML(val) {
|
|
39
|
+
this._innerHTML = String(val);
|
|
40
|
+
this._textContent = String(val).replace(/<[^>]*>/g, "");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
appendChild(child) {
|
|
44
|
+
this.children.push(child);
|
|
45
|
+
return child;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
addEventListener(type, fn) {
|
|
49
|
+
if (!this.listeners[type]) this.listeners[type] = [];
|
|
50
|
+
this.listeners[type].push(fn);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
dispatchEvent(event) {
|
|
54
|
+
const list = this.listeners[event.type] || [];
|
|
55
|
+
for (const fn of list) fn(event);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
querySelectorAll(selector) {
|
|
59
|
+
const results = [];
|
|
60
|
+
const check = (el) => {
|
|
61
|
+
for (const child of el.children) {
|
|
62
|
+
if (child instanceof MockElement) {
|
|
63
|
+
let matches = false;
|
|
64
|
+
if (selector === "details" && child.tagName === "DETAILS") matches = true;
|
|
65
|
+
if (selector.startsWith(".") && child.className.split(" ").includes(selector.slice(1))) matches = true;
|
|
66
|
+
if (matches) results.push(child);
|
|
67
|
+
check(child);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
check(this);
|
|
72
|
+
return results;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
querySelector(selector) {
|
|
76
|
+
return this.querySelectorAll(selector)[0] || null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
globalThis.document = {
|
|
81
|
+
createElement(tag) {
|
|
82
|
+
return new MockElement(tag);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
globalThis.Event = class Event {
|
|
86
|
+
constructor(type) {
|
|
87
|
+
this.type = type;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// 1. Test renderValueNode for empty product
|
|
92
|
+
const emptyVal = Value.product({});
|
|
93
|
+
const emptyEl = renderValueNode(emptyVal);
|
|
94
|
+
assert.strictEqual(emptyEl.textContent, "{}", "Empty product must render as '{}'");
|
|
95
|
+
|
|
96
|
+
// 2. Test renderValueNode for nested products (depth tracking)
|
|
97
|
+
// { a: { b: { c: { d: {} } } } }
|
|
98
|
+
const deepProduct = Value.product({
|
|
99
|
+
a: Value.product({
|
|
100
|
+
b: Value.product({
|
|
101
|
+
c: Value.product({
|
|
102
|
+
d: Value.product({})
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const treeRoot = renderValueNode(deepProduct, 1, 3);
|
|
109
|
+
assert.strictEqual(treeRoot.tagName, "DETAILS", "Root product should be a <details> element");
|
|
110
|
+
assert.strictEqual(treeRoot.open, true, "Root product (depth 1) must be open");
|
|
111
|
+
|
|
112
|
+
// Find child .a
|
|
113
|
+
const nodeA = treeRoot.querySelectorAll(".k-tree-node")[0];
|
|
114
|
+
assert(nodeA, "Node .a must exist");
|
|
115
|
+
assert.strictEqual(nodeA.open, true, "Node .a (depth 2) must be open");
|
|
116
|
+
|
|
117
|
+
// Find child .b
|
|
118
|
+
const nodeB = nodeA.querySelectorAll(".k-tree-node")[0];
|
|
119
|
+
assert(nodeB, "Node .b must exist");
|
|
120
|
+
assert.strictEqual(nodeB.open, true, "Node .b (depth 3) must be open");
|
|
121
|
+
|
|
122
|
+
// Find child .c
|
|
123
|
+
const nodeC = nodeB.querySelectorAll(".k-tree-node")[0];
|
|
124
|
+
assert(nodeC, "Node .c must exist");
|
|
125
|
+
assert.strictEqual(nodeC.open, false, "Node .c (depth 4) must be collapsed (open === false)");
|
|
126
|
+
|
|
127
|
+
// Test lazy unfolding of node .c
|
|
128
|
+
assert.strictEqual(nodeC.querySelector(".k-tree-children").children.length, 0, "Children of collapsed node must not be populated initially");
|
|
129
|
+
nodeC.open = true;
|
|
130
|
+
nodeC.dispatchEvent(new Event("toggle"));
|
|
131
|
+
assert(nodeC.querySelector(".k-tree-children").children.length > 0, "Unfolding node .c must lazily populate its children");
|
|
132
|
+
assert(nodeC.textContent.includes(".d:"), "Unfolded children must include .d:");
|
|
133
|
+
|
|
134
|
+
// 3. Test renderValueNode for variant chain (integers: + -> 1 -> 0 -> 1 -> _ -> {})
|
|
135
|
+
const variantVal = Value.variant(
|
|
136
|
+
"+",
|
|
137
|
+
Value.variant(
|
|
138
|
+
"1",
|
|
139
|
+
Value.variant(
|
|
140
|
+
"0",
|
|
141
|
+
Value.variant(
|
|
142
|
+
"1",
|
|
143
|
+
Value.variant("_", Value.product({}))
|
|
144
|
+
)
|
|
145
|
+
)
|
|
146
|
+
)
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const varTree = renderValueNode(variantVal, 1, 3);
|
|
150
|
+
assert.strictEqual(varTree.tagName, "DETAILS");
|
|
151
|
+
assert.strictEqual(varTree.open, true, "Variant depth 1 (+) must be open");
|
|
152
|
+
|
|
153
|
+
const var2 = varTree.querySelectorAll(".k-tree-variant")[0];
|
|
154
|
+
assert.strictEqual(var2.open, true, "Variant depth 2 (1) must be open");
|
|
155
|
+
|
|
156
|
+
const var3 = var2.querySelectorAll(".k-tree-variant")[0];
|
|
157
|
+
assert.strictEqual(var3.open, true, "Variant depth 3 (0) must be open");
|
|
158
|
+
|
|
159
|
+
const var4 = var3.querySelectorAll(".k-tree-variant")[0];
|
|
160
|
+
assert.strictEqual(var4.open, false, "Variant depth 4 (1) must be collapsed");
|
|
161
|
+
|
|
162
|
+
// 4. Test renderPatternTree with cycles (recursive integer type: ?<<X0 0, X0 1, {} _>=X0 +, X0 ->)
|
|
163
|
+
const recursivePattern = [
|
|
164
|
+
["closed-union", [["+", 1], ["-", 1]]],
|
|
165
|
+
["closed-union", [["0", 1], ["1", 1], ["_", 2]]],
|
|
166
|
+
["closed-product", []]
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
const patTree = renderPatternTree(recursivePattern, 3);
|
|
170
|
+
assert.strictEqual(patTree.tagName, "DETAILS");
|
|
171
|
+
assert.strictEqual(patTree.open, true, "Root pattern node must be open");
|
|
172
|
+
assert(patTree.textContent.includes("recursive"), "Recursive cycle must be detected and marked 'recursive'");
|
|
173
|
+
|
|
174
|
+
// 5. Test createOutputEntryElement
|
|
175
|
+
const entryEl = createOutputEntryElement({
|
|
176
|
+
value: variantVal,
|
|
177
|
+
rawText: "{}|_|1|0|1|+ ?<<X0 0, X0 1, {} _>=X0 +, X0 ->\nint: 11",
|
|
178
|
+
codecOutputs: ["int: 11"]
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
assert(entryEl.querySelector(".k-tree-view"), "Tree view container must exist");
|
|
182
|
+
assert(entryEl.querySelector(".k-raw-view"), "Raw view container must exist");
|
|
183
|
+
assert(entryEl.textContent.includes("int: 11"), "Codec output must be visible in container");
|
|
184
|
+
|
|
185
|
+
console.log("OK - All tree view unit tests passed.");
|