@fraczak/k 6.10.4 → 6.10.5
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 +35 -0
- package/Examples/arithmetics.k +222 -110
- package/Examples/poly.k +14 -5
- package/browser/shims/fs.mjs +12 -7
- package/browser/vfs-data.mjs +7 -10
- package/core.k +20 -13
- package/harness/suites/poly.mjs +1 -1
- package/package.json +1 -1
- package/repl-codecs.mjs +6 -3
- package/scripts/build-repl-html.mjs +11 -10
- package/scripts/perf-poly.mjs +1 -1
- package/tests/test-arithmetics.mjs +96 -0
- package/tests/test-repl-html.mjs +23 -6
package/core.k
CHANGED
|
@@ -58,20 +58,27 @@ _inc = ?{X x, X y}
|
|
|
58
58
|
|
|
59
59
|
-- addition on $bits (unsigned, LSB-first with carry)
|
|
60
60
|
plus = ${bits x, bits y} {.x inv x, .y inv y, b0 c} _plus;
|
|
61
|
-
_plus =
|
|
61
|
+
_plus = {.x x, .y y, .c c, _ r} _plus_;
|
|
62
|
+
_plus_ = ${bits x, bits y, bit c, bits r}
|
|
62
63
|
<
|
|
63
|
-
{.x /_ if, .y /_ and,
|
|
64
|
-
{.x /_ if, .
|
|
65
|
-
{.x
|
|
66
|
-
{
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
64
|
+
{.x /_ if, .y /_ and, .c/0 c, .r then} .then,
|
|
65
|
+
{.x /_ if, .y /_ and, .c/1 c, .r |1 then} .then,
|
|
66
|
+
{.x /_ if, .c/0 and, {.y x, .r y} concat_ then} .then,
|
|
67
|
+
{.y /_ if, .c/0 and, {.x x, .r y} concat_ then} .then,
|
|
68
|
+
<
|
|
69
|
+
{.x/_ _ x, .y /0 y, b0 c, .r |1 r},
|
|
70
|
+
{.x/_ _ x, .y /1 y, b1 c, .r |0 r},
|
|
71
|
+
{.y/_ _ y, .x /0 x, b0 c, .r |1 r},
|
|
72
|
+
{.y/_ _ y, .x /1 x, b1 c, .r |0 r},
|
|
73
|
+
{.x /0 x, .y /0 y, .c/0 b0 c, .r |0 r},
|
|
74
|
+
{.x /0 x, .y /0 y, .c/1 b0 c, .r |1 r},
|
|
75
|
+
{.x /0 x, .y /1 y, .c/0 b0 c, .r |1 r},
|
|
76
|
+
{.x /0 x, .y /1 y, .c/1 b1 c, .r |0 r},
|
|
77
|
+
{.x /1 x, .y /0 y, .c/0 b0 c, .r |1 r},
|
|
78
|
+
{.x /1 x, .y /0 y, .c/1 b1 c, .r |0 r},
|
|
79
|
+
{.x /1 x, .y /1 y, .c/0 b1 c, .r |0 r},
|
|
80
|
+
{.x /1 x, .y /1 y, .c/1 b1 c, .r |1 r}
|
|
81
|
+
> _plus_
|
|
75
82
|
>;
|
|
76
83
|
|
|
77
84
|
-- multiplication on $bits (unsigned, shift-and-add)
|
package/harness/suites/poly.mjs
CHANGED
|
@@ -48,7 +48,7 @@ export async function createPolySuite({ listLength = 40, cacheDir = null } = {})
|
|
|
48
48
|
return lines.join("\n") + "\n";
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
const neededExports = ["0", "int", "inc", "dec", "nat", "zero_int?"
|
|
51
|
+
const neededExports = ["0", "int", "inc", "dec", "nat", "zero_int?"];
|
|
52
52
|
const exportPreamble = buildExportPreamble(neededExports, [arithmeticsLib]);
|
|
53
53
|
const polyLib = loadLibrary(compileLibrary(exportPreamble + polySource, {
|
|
54
54
|
source: polyPath,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fraczak/k",
|
|
3
|
-
"version": "6.10.
|
|
3
|
+
"version": "6.10.5",
|
|
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/repl-codecs.mjs
CHANGED
|
@@ -107,8 +107,10 @@ function registerCodec(state, rawCodec, filePath) {
|
|
|
107
107
|
|
|
108
108
|
function unregisterCodec(state, codecName) {
|
|
109
109
|
const store = codecStore(state);
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
const baseName = path.basename(codecName);
|
|
111
|
+
const key = store[codecName] ? codecName : (store[baseName] ? baseName : null);
|
|
112
|
+
if (!key) return 0;
|
|
113
|
+
delete store[key];
|
|
112
114
|
return 1;
|
|
113
115
|
}
|
|
114
116
|
|
|
@@ -129,7 +131,8 @@ function resolveCodec(state, codecName, capability = null) {
|
|
|
129
131
|
throw new Error("Codec name is required");
|
|
130
132
|
}
|
|
131
133
|
const store = codecStore(state);
|
|
132
|
-
const
|
|
134
|
+
const baseName = path.basename(codecName);
|
|
135
|
+
const codec = store[codecName] || store[baseName];
|
|
133
136
|
if (!codec) {
|
|
134
137
|
throw new Error(`Codec '${codecName}' is not loaded`);
|
|
135
138
|
}
|
|
@@ -78,8 +78,8 @@ if (fs.existsSync(coreKPath)) {
|
|
|
78
78
|
vfsFiles["core.k"] = fs.readFileSync(coreKPath, "utf8");
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
// Add verified k-code files: arithmetics.k, ieee.k, poly.k
|
|
82
|
-
const verifiedExamples = ["arithmetics.k", "ieee.k", "poly.k"];
|
|
81
|
+
// Add verified k-code files: arithmetics.k, ieee.k, poly.k, karatsuba-mult.k
|
|
82
|
+
const verifiedExamples = ["arithmetics.k", "ieee.k", "poly.k", "karatsuba-mult.k"];
|
|
83
83
|
const examplesDir = path.join(projectRoot, "Examples");
|
|
84
84
|
for (const filename of verifiedExamples) {
|
|
85
85
|
const fullPath = path.join(examplesDir, filename);
|
|
@@ -130,7 +130,6 @@ for (const filename of verifiedCodecs) {
|
|
|
130
130
|
}]
|
|
131
131
|
});
|
|
132
132
|
const bundledContent = buildRes.outputFiles[0].text;
|
|
133
|
-
vfsFiles[filename] = bundledContent;
|
|
134
133
|
vfsFiles[`codecs/${filename}`] = bundledContent;
|
|
135
134
|
}
|
|
136
135
|
}
|
|
@@ -1663,6 +1662,7 @@ const htmlContent = `<!DOCTYPE html>
|
|
|
1663
1662
|
<option value="arithmetics.k">arithmetics.k</option>
|
|
1664
1663
|
<option value="ieee.k">ieee.k</option>
|
|
1665
1664
|
<option value="poly.k">poly.k</option>
|
|
1665
|
+
<option value="karatsuba-mult.k">karatsuba-mult.k</option>
|
|
1666
1666
|
</optgroup>
|
|
1667
1667
|
<optgroup label="Quick Expressions">
|
|
1668
1668
|
<option value="expr:{} | ok">{} | ok</option>
|
|
@@ -1671,6 +1671,7 @@ const htmlContent = `<!DOCTYPE html>
|
|
|
1671
1671
|
<option value="expr:{10 x, 5 y} plus">{10 x, 5 y} plus (bits)</option>
|
|
1672
1672
|
<option value="expr:1 succ">1 succ</option>
|
|
1673
1673
|
<option value="expr:{10 int x, 5 int y} plus">{10 int x, 5 int y} plus (int)</option>
|
|
1674
|
+
<option value="expr:{10 int x, 5 int y} karatsuba">{10 int x, 5 int y} karatsuba</option>
|
|
1674
1675
|
<option value="expr::types">:types (list types)</option>
|
|
1675
1676
|
<option value="expr::rels">:rels (list relations)</option>
|
|
1676
1677
|
<option value="expr::engine">:engine (show engine)</option>
|
|
@@ -1680,13 +1681,13 @@ const htmlContent = `<!DOCTYPE html>
|
|
|
1680
1681
|
<optgroup label="Codecs & Format Adapters">
|
|
1681
1682
|
<option value="expr::codecs">:codecs</option>
|
|
1682
1683
|
<option value="expr::input">:input (interactive dialog)</option>
|
|
1683
|
-
<option value="expr::codec load int.mjs">:codec load int.mjs</option>
|
|
1684
|
-
<option value="expr::codec load utf8.mjs">:codec load utf8.mjs</option>
|
|
1685
|
-
<option value="expr::codec load json.mjs">:codec load json.mjs</option>
|
|
1686
|
-
<option value="expr::codec load ieee.mjs">:codec load ieee.mjs</option>
|
|
1687
|
-
<option value="expr::codec load unit.mjs">:codec load unit.mjs</option>
|
|
1688
|
-
<option value="expr::input json.mjs {"a":12,"b":"hello"}">:input json.mjs {"a":12,"b":"hello"}</option>
|
|
1689
|
-
<option value="expr::input int.mjs [0,1,2]">:input int.mjs [0,1,2]</option>
|
|
1684
|
+
<option value="expr::codec load codecs/int.mjs">:codec load codecs/int.mjs</option>
|
|
1685
|
+
<option value="expr::codec load codecs/utf8.mjs">:codec load codecs/utf8.mjs</option>
|
|
1686
|
+
<option value="expr::codec load codecs/json.mjs">:codec load codecs/json.mjs</option>
|
|
1687
|
+
<option value="expr::codec load codecs/ieee.mjs">:codec load codecs/ieee.mjs</option>
|
|
1688
|
+
<option value="expr::codec load codecs/unit.mjs">:codec load codecs/unit.mjs</option>
|
|
1689
|
+
<option value="expr::input codecs/json.mjs {"a":12,"b":"hello"}">:input codecs/json.mjs {"a":12,"b":"hello"}</option>
|
|
1690
|
+
<option value="expr::input codecs/int.mjs [0,1,2]">:input codecs/int.mjs [0,1,2]</option>
|
|
1690
1691
|
</optgroup>
|
|
1691
1692
|
</select>
|
|
1692
1693
|
<button id="btn-load-example" class="btn btn-primary">Load</button>
|
package/scripts/perf-poly.mjs
CHANGED
|
@@ -193,7 +193,7 @@ function buildExportPreamble(exports, libraries) {
|
|
|
193
193
|
return lines.join("\n") + "\n";
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
-
const neededExports = ["0", "int", "inc", "dec", "nat", "zero_int?"
|
|
196
|
+
const neededExports = ["0", "int", "inc", "dec", "nat", "zero_int?"];
|
|
197
197
|
const exportPreamble = buildExportPreamble(neededExports, [arithmeticsLib]);
|
|
198
198
|
const polyLib = loadLibrary(compileLibrary(exportPreamble + polySource, {
|
|
199
199
|
source: polyPath,
|
|
@@ -100,10 +100,13 @@ try {
|
|
|
100
100
|
assertOk(resDec, "2 int dec dec zero_int? should succeed");
|
|
101
101
|
|
|
102
102
|
const divTestCases = [
|
|
103
|
+
{ x: "0", yAlias: "7", yVal: 7n },
|
|
104
|
+
{ x: "3", yAlias: "7", yVal: 7n },
|
|
103
105
|
{ x: "4", yAlias: "1", yVal: 1n },
|
|
104
106
|
{ x: "10", yAlias: "2", yVal: 2n },
|
|
105
107
|
{ x: "12", yAlias: "3", yVal: 3n },
|
|
106
108
|
{ x: "11", yAlias: "3", yVal: 3n },
|
|
109
|
+
{ x: "12", yAlias: "12", yVal: 12n },
|
|
107
110
|
{ x: "100", yAlias: "7", yVal: 7n },
|
|
108
111
|
{ x: "-100", yAlias: "7", yVal: 7n },
|
|
109
112
|
{ x: "1000", yAlias: "10", yVal: 10n }
|
|
@@ -143,6 +146,99 @@ try {
|
|
|
143
146
|
assert.equal(remOut, expectedRem, `div(${x}, ${yAlias}) remainder should match BigInt oracle`);
|
|
144
147
|
}
|
|
145
148
|
|
|
149
|
+
// Regression tests for EQ
|
|
150
|
+
const dummyWire = parseIntWire("0");
|
|
151
|
+
const resEqTrue = run(node, [
|
|
152
|
+
"k.mjs",
|
|
153
|
+
"--lib", libPath,
|
|
154
|
+
"--export", "EQ:EQ",
|
|
155
|
+
"--export", "int:int",
|
|
156
|
+
"--export", "2:two",
|
|
157
|
+
"{two x, two y} EQ .x int"
|
|
158
|
+
], { input: dummyWire });
|
|
159
|
+
assertOk(resEqTrue, "{2, 2} EQ should succeed");
|
|
160
|
+
|
|
161
|
+
const resEqFalse = run(node, [
|
|
162
|
+
"k.mjs",
|
|
163
|
+
"--lib", libPath,
|
|
164
|
+
"--export", "EQ:EQ",
|
|
165
|
+
"--export", "int:int",
|
|
166
|
+
"--export", "2:two",
|
|
167
|
+
"--export", "3:three",
|
|
168
|
+
"{two x, three y} EQ .x int"
|
|
169
|
+
], { input: dummyWire });
|
|
170
|
+
assert.notEqual(resEqFalse.status, 0, "{2, 3} EQ should fail");
|
|
171
|
+
|
|
172
|
+
// Regression tests for pos?
|
|
173
|
+
const resPosTrue = run(node, [
|
|
174
|
+
"k.mjs",
|
|
175
|
+
"--lib", libPath,
|
|
176
|
+
"--export", "pos?:pos?",
|
|
177
|
+
"--export", "int:int",
|
|
178
|
+
"--export", "2:two",
|
|
179
|
+
"two int pos?"
|
|
180
|
+
], { input: dummyWire });
|
|
181
|
+
assertOk(resPosTrue, "2 int pos? should succeed");
|
|
182
|
+
|
|
183
|
+
const resPosZero = run(node, [
|
|
184
|
+
"k.mjs",
|
|
185
|
+
"--lib", libPath,
|
|
186
|
+
"--export", "pos?:pos?",
|
|
187
|
+
"--export", "int:int",
|
|
188
|
+
"--export", "0:zero",
|
|
189
|
+
"zero int pos?"
|
|
190
|
+
], { input: dummyWire });
|
|
191
|
+
assert.notEqual(resPosZero.status, 0, "0 int pos? should fail");
|
|
192
|
+
|
|
193
|
+
// Regression tests for mod, gcd, lcm
|
|
194
|
+
const resMod = run(node, [
|
|
195
|
+
"k.mjs",
|
|
196
|
+
"--lib", libPath,
|
|
197
|
+
"--export", "mod:mod",
|
|
198
|
+
"--export", "int:int",
|
|
199
|
+
"--export", "10:ten",
|
|
200
|
+
"--export", "3:three",
|
|
201
|
+
"{ten x, three y} mod int"
|
|
202
|
+
], { input: dummyWire });
|
|
203
|
+
assertOk(resMod, "10 % 3 mod");
|
|
204
|
+
assert.equal(printIntWire(resMod.stdout, "mod"), "1");
|
|
205
|
+
|
|
206
|
+
const resGcd = run(node, [
|
|
207
|
+
"k.mjs",
|
|
208
|
+
"--lib", libPath,
|
|
209
|
+
"--export", "gcd:gcd",
|
|
210
|
+
"--export", "int:int",
|
|
211
|
+
"--export", "12:twelve",
|
|
212
|
+
"--export", "8:eight",
|
|
213
|
+
"{twelve x, eight y} gcd int"
|
|
214
|
+
], { input: dummyWire });
|
|
215
|
+
assertOk(resGcd, "gcd(12, 8)");
|
|
216
|
+
assert.equal(printIntWire(resGcd.stdout, "gcd"), "4");
|
|
217
|
+
|
|
218
|
+
const resGcdZero = run(node, [
|
|
219
|
+
"k.mjs",
|
|
220
|
+
"--lib", libPath,
|
|
221
|
+
"--export", "gcd:gcd",
|
|
222
|
+
"--export", "int:int",
|
|
223
|
+
"--export", "4:four",
|
|
224
|
+
"--export", "0b:zero_b",
|
|
225
|
+
"{four x, zero_b y} gcd int"
|
|
226
|
+
], { input: dummyWire });
|
|
227
|
+
assertOk(resGcdZero, "gcd(4, 0b)");
|
|
228
|
+
assert.equal(printIntWire(resGcdZero.stdout, "gcd 0b"), "4");
|
|
229
|
+
|
|
230
|
+
const resLcm = run(node, [
|
|
231
|
+
"k.mjs",
|
|
232
|
+
"--lib", libPath,
|
|
233
|
+
"--export", "lcm:lcm",
|
|
234
|
+
"--export", "int:int",
|
|
235
|
+
"--export", "4:four",
|
|
236
|
+
"--export", "6:six",
|
|
237
|
+
"{four x, six y} lcm int"
|
|
238
|
+
], { input: dummyWire });
|
|
239
|
+
assertOk(resLcm, "lcm(4, 6)");
|
|
240
|
+
assert.equal(printIntWire(resLcm.stdout, "lcm"), "12");
|
|
241
|
+
|
|
146
242
|
console.log("OK");
|
|
147
243
|
} finally {
|
|
148
244
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
package/tests/test-repl-html.mjs
CHANGED
|
@@ -139,14 +139,15 @@ if (chromiumBin) {
|
|
|
139
139
|
const vfsList = await evaluateAsync(`window.kRepl.getAllVfsFiles().sort()`);
|
|
140
140
|
const expectedFiles = [
|
|
141
141
|
"arithmetics.k",
|
|
142
|
+
"codecs/ieee.mjs",
|
|
143
|
+
"codecs/int.mjs",
|
|
144
|
+
"codecs/json.mjs",
|
|
145
|
+
"codecs/unit.mjs",
|
|
146
|
+
"codecs/utf8.mjs",
|
|
142
147
|
"core.k",
|
|
143
148
|
"ieee.k",
|
|
144
|
-
"
|
|
145
|
-
"
|
|
146
|
-
"json.mjs",
|
|
147
|
-
"poly.k",
|
|
148
|
-
"unit.mjs",
|
|
149
|
-
"utf8.mjs"
|
|
149
|
+
"karatsuba-mult.k",
|
|
150
|
+
"poly.k"
|
|
150
151
|
].sort();
|
|
151
152
|
assert.deepStrictEqual(vfsList, expectedFiles, `getAllVfsFiles() must match curated files list, got: ${JSON.stringify(vfsList)}`);
|
|
152
153
|
|
|
@@ -158,6 +159,22 @@ if (chromiumBin) {
|
|
|
158
159
|
})()`);
|
|
159
160
|
assert(loadOut.includes("loaded arithmetics.k"), `Expected loaded arithmetics.k, got: ${loadOut}`);
|
|
160
161
|
|
|
162
|
+
// Test :load karatsuba-mult.k
|
|
163
|
+
const loadKaratsubaOut = await evaluateAsync(`(async () => {
|
|
164
|
+
await window.kRepl.executeCommand(":load karatsuba-mult.k");
|
|
165
|
+
const lines = Array.from(document.querySelectorAll(".entry-line")).map(el => el.textContent);
|
|
166
|
+
return lines[lines.length - 1];
|
|
167
|
+
})()`);
|
|
168
|
+
assert(loadKaratsubaOut.includes("loaded karatsuba-mult.k"), `Expected loaded karatsuba-mult.k, got: ${loadKaratsubaOut}`);
|
|
169
|
+
|
|
170
|
+
// Test evaluating {1 int x, 1 int y} karatsuba
|
|
171
|
+
const karatsubaVal = await evaluateAsync(`(async () => {
|
|
172
|
+
await window.kRepl.executeCommand("{1 int x, 1 int y} karatsuba");
|
|
173
|
+
const lines = Array.from(document.querySelectorAll(".entry-line")).map(el => el.textContent);
|
|
174
|
+
return lines[lines.length - 1];
|
|
175
|
+
})()`);
|
|
176
|
+
assert(karatsubaVal.includes("{}|_|1|+"), `Expected {}|_|1|+ in output, got: ${karatsubaVal}`);
|
|
177
|
+
|
|
161
178
|
// Test evaluating 10
|
|
162
179
|
const valOut = await evaluateAsync(`(async () => {
|
|
163
180
|
await window.kRepl.executeCommand("10");
|