@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/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 = ${bits x, bits y, bit c}
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, <.c/0 0, 1> then} .then,
64
- {.x /_ if, .c/0 and, .y then} .then,
65
- {.x y, .y /_|_ x, .c c} _plus,
66
- {<.c/0 0, 1> x, .y y, .x /_ b0 c} _plus,
67
- {.x /0 x, .y /0 y, .c/0 b0 c} _plus |0,
68
- {.x /0 x, .y /0 y, .c/1 b0 c} _plus |1,
69
- {.x /0 x, .y /1 y, .c/0 b0 c} _plus |1,
70
- {.x /0 x, .y /1 y, .c/1 b1 c} _plus |0,
71
- {.x /1 x, .y /0 y, .c/0 b0 c} _plus |1,
72
- {.x /1 x, .y /0 y, .c/1 b1 c} _plus |0,
73
- {.x /1 x, .y /1 y, .c/0 b1 c} _plus |0,
74
- {.x /1 x, .y /1 y, .c/1 b1 c} _plus |1
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)
@@ -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?", "nil", "cons", "car", "cdr"];
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.4",
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
- if (!store[codecName]) return 0;
111
- delete store[codecName];
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 codec = store[codecName];
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 &amp; 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 {&quot;a&quot;:12,&quot;b&quot;:&quot;hello&quot;}">: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 {&quot;a&quot;:12,&quot;b&quot;:&quot;hello&quot;}">: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>
@@ -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?", "nil", "cons", "car", "cdr"];
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 });
@@ -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
- "ieee.mjs",
145
- "int.mjs",
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");