@fraczak/k 7.0.2 → 7.2.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 (71) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/DOCS/CODECS.md +37 -2
  3. package/DOCS/CODEC_ARCHITECTURE.md +12 -5
  4. package/DOCS/FILE_FORMATS.md +238 -15
  5. package/DOCS/POLYMORPHIC_IR.md +104 -0
  6. package/DOCS/REPL.md +11 -3
  7. package/DOCS/WEB_REPL_REQUIREMENTS.md +1 -1
  8. package/JOURNAL.md +288 -0
  9. package/README.md +12 -3
  10. package/Value.mjs +28 -3
  11. package/access-table.mjs +343 -0
  12. package/backend-api.mjs +23 -1
  13. package/backends/llvm/README.md +20 -21
  14. package/backends/llvm/bin/k-llvm-build.mjs +105 -32
  15. package/backends/llvm/bin/k-llvm-compile.mjs +63 -24
  16. package/backends/llvm/bin/k-llvm.mjs +292 -0
  17. package/backends/llvm/runtime/krt.c +8 -0
  18. package/backends/llvm/runtime/krt.h +1 -0
  19. package/backends/llvm/src/cli.mjs +95 -17
  20. package/backends/llvm/src/executable.mjs +128 -11
  21. package/backends/llvm/src/kvm2llvm.mjs +10 -5
  22. package/backends/llvm/src/llvm.mjs +121 -9
  23. package/backends/llvm/tests/integration.sh +11 -11
  24. package/backends/llvm/{bin → tests}/k-llvm-run.mjs +48 -22
  25. package/backends/llvm/tests/perf-support.mjs +24 -3
  26. package/backends/llvm/tests/test-llvm.mjs +22 -1
  27. package/backends/wasm/bin/k-wasm-compile.mjs +46 -20
  28. package/backends/wasm/bin/k-wasm-run.mjs +61 -20
  29. package/backends/wasm/bin/k-wasm.mjs +47 -13
  30. package/backends/wasm/src/cli.mjs +141 -19
  31. package/backends/wasm/src/wasm.mjs +130 -23
  32. package/browser/repl-browser.mjs +16 -5
  33. package/browser/tree-view.mjs +47 -8
  34. package/browser/vfs-data.mjs +6 -5
  35. package/codecs/README.md +1 -0
  36. package/codecs/djson.mjs +270 -0
  37. package/codecs/int.mjs +2 -1
  38. package/codecs/json.mjs +7 -2
  39. package/codecs/k-parse.mjs +36 -9
  40. package/codecs/k-print.mjs +26 -6
  41. package/codecs/runtime/codec-sdk.mjs +24 -6
  42. package/codecs/runtime/pattern-json.mjs +80 -1
  43. package/codecs/runtime/prefix-codec.mjs +629 -67
  44. package/codecs/runtime/show-value.mjs +93 -51
  45. package/codecs/runtime/unicode-string.mjs +29 -6
  46. package/codecs/show.mjs +24 -6
  47. package/codecs/utf16.mjs +2 -1
  48. package/k.mjs +56 -16
  49. package/kir.mjs +58 -19
  50. package/kvm.mjs +49 -12
  51. package/objects/compile.mjs +37 -23
  52. package/objects/decompile.mjs +40 -10
  53. package/objects/extract-aliases.mjs +44 -14
  54. package/objects/inspect.mjs +19 -14
  55. package/objects/validate.mjs +18 -11
  56. package/package.json +11 -3
  57. package/pkir.mjs +772 -0
  58. package/repl.mjs +92 -23
  59. package/scripts/build-repl-html.mjs +22 -3
  60. package/scripts/perf-ieee.mjs +264 -13
  61. package/scripts/perf-int.mjs +315 -22
  62. package/scripts/perf-multiplication.mjs +58 -7
  63. package/scripts/perf-poly.mjs +306 -24
  64. package/scripts/run-tests.mjs +3 -0
  65. package/tests/test-access-table.mjs +213 -0
  66. package/tests/test-codecs.mjs +168 -0
  67. package/tests/test-pkir.mjs +530 -0
  68. package/tests/test-polymorphic-tdd.mjs +196 -0
  69. package/tests/test-repl-html.mjs +16 -2
  70. package/tests/test-repl.mjs +63 -1
  71. package/backends/llvm/bin/k-llvm-jit.mjs +0 -160
package/repl.mjs CHANGED
@@ -50,7 +50,7 @@ const NAME_RE = /^[a-zA-Z0-9_+-][a-zA-Z0-9_?!+-]*$/;
50
50
  const COMMAND_NAMES = [
51
51
  "help", "rel",
52
52
  "codecs", "rels", "codec", "input", "reset", "klib", "ko", "load",
53
- "engine", "wasm", "js",
53
+ "engine", "wasm", "pkir", "js", "limit",
54
54
  "quit", "exit"
55
55
  ];
56
56
  const CODEC_COMMAND_NAMES = ["load", "unload", "list"];
@@ -76,8 +76,10 @@ function emptyValue() {
76
76
  function createState(options = {}) {
77
77
  codes.load(cloneJSON(initialCodes));
78
78
  const engine = (options.engine || "wasm").toLowerCase();
79
- if (engine !== "wasm" && engine !== "js") {
80
- throw new Error(`Invalid engine '${options.engine}'. Valid engines: wasm, js`);
79
+ if (engine !== "wasm" && engine !== "pkir" && engine !== "js") {
80
+ throw new Error(
81
+ `Invalid engine '${options.engine}'. Valid engines: wasm, pkir, js`
82
+ );
81
83
  }
82
84
  return {
83
85
  engine,
@@ -93,7 +95,8 @@ function createState(options = {}) {
93
95
  lastResult: null,
94
96
  lastMain: null,
95
97
  lastTiming: null,
96
- showTiming: true
98
+ showTiming: true,
99
+ printLimit: options.printLimit ?? Infinity
97
100
  };
98
101
  }
99
102
 
@@ -352,7 +355,8 @@ function formatCodecOutput(output) {
352
355
  }
353
356
 
354
357
  function printValue(value, state = null) {
355
- const lines = [valueWithEnvelopeToK(value)];
358
+ const limit = state?.printLimit ?? Infinity;
359
+ const lines = [valueWithEnvelopeToK(value, limit)];
356
360
  if (!state || value === undefined) return lines[0];
357
361
 
358
362
  const store = state.codecs || {};
@@ -361,7 +365,11 @@ function printValue(value, state = null) {
361
365
  try {
362
366
  const output = codec.print(value, { state });
363
367
  if (output != null) {
364
- lines.push(`${codec.name}: ${formatCodecOutput(output)}`);
368
+ let text = formatCodecOutput(output);
369
+ if (Number.isFinite(limit) && text.length > limit) {
370
+ text = text.slice(0, limit) + "...";
371
+ }
372
+ lines.push(`${codec.name}: ${text}`);
365
373
  }
366
374
  } catch {
367
375
  // Codec cannot format this value; silently skip
@@ -768,7 +776,7 @@ function completeCommandArgument(line, state) {
768
776
  }
769
777
 
770
778
  if (command === "engine") {
771
- return completeCommandWord(line, argStart, arg, ["wasm", "js"]);
779
+ return completeCommandWord(line, argStart, arg, ["wasm", "pkir", "js"]);
772
780
  }
773
781
 
774
782
  if (command === "input") {
@@ -1003,7 +1011,8 @@ async function executeExpressionWithWasm(annotated, state, lineOffset = 0) {
1003
1011
 
1004
1012
  const wasmCompileStart = performance.now();
1005
1013
  const wasmBytes = await compileWasmArtifactFromObject(obj, {
1006
- inputEnvelopePattern: inputValue?.pattern
1014
+ inputEnvelopePattern: inputValue?.pattern,
1015
+ usePKIR: state.engine === "pkir" || state.usePKIR
1007
1016
  });
1008
1017
  const runner = await instantiateWasmArtifact(wasmBytes);
1009
1018
  const wasmCompileMs = performance.now() - wasmCompileStart;
@@ -1242,8 +1251,10 @@ async function evaluateCommand(line, state) {
1242
1251
  if (!mode) {
1243
1252
  return [`Current engine: ${state.engine}`];
1244
1253
  }
1245
- if (mode !== "wasm" && mode !== "js") {
1246
- throw new Error(`Invalid engine '${arg.trim()}'. Valid engines: wasm, js`);
1254
+ if (mode !== "wasm" && mode !== "pkir" && mode !== "js") {
1255
+ throw new Error(
1256
+ `Invalid engine '${arg.trim()}'. Valid engines: wasm, pkir, js`
1257
+ );
1247
1258
  }
1248
1259
  state.engine = mode;
1249
1260
  return [`engine set to ${mode}`];
@@ -1252,13 +1263,42 @@ async function evaluateCommand(line, state) {
1252
1263
  state.engine = "wasm";
1253
1264
  return ["engine set to wasm"];
1254
1265
  }
1266
+ case "pkir": {
1267
+ state.engine = "pkir";
1268
+ return ["engine set to pkir"];
1269
+ }
1255
1270
  case "js": {
1256
1271
  state.engine = "js";
1257
1272
  return ["engine set to js"];
1258
1273
  }
1274
+ case "limit": {
1275
+ const mode = (arg || "").trim().toLowerCase();
1276
+ if (!mode) {
1277
+ const current = Number.isFinite(state.printLimit)
1278
+ ? state.printLimit
1279
+ : "none";
1280
+ return [`Current output limit: ${current}`];
1281
+ }
1282
+ if (mode === "none" || mode === "infinity" || mode === "off") {
1283
+ state.printLimit = Infinity;
1284
+ return ["output limit disabled"];
1285
+ }
1286
+ const n = parseInt(mode, 10);
1287
+ if (Number.isNaN(n) || n < 0) {
1288
+ throw new Error(
1289
+ `Invalid limit '${arg.trim()}'. Usage: :limit [num|none]`
1290
+ );
1291
+ }
1292
+ state.printLimit = n;
1293
+ return [`output limit set to ${n}`];
1294
+ }
1259
1295
  case "reset": {
1260
1296
  const currentEngine = state.engine;
1261
- const fresh = createState({ engine: currentEngine });
1297
+ const currentLimit = state.printLimit;
1298
+ const fresh = createState({
1299
+ engine: currentEngine,
1300
+ printLimit: currentLimit
1301
+ });
1262
1302
  Object.assign(state, fresh);
1263
1303
  return ["reset"];
1264
1304
  }
@@ -1290,9 +1330,10 @@ async function evaluateCommand(line, state) {
1290
1330
 
1291
1331
  function helpText() {
1292
1332
  return [
1293
- ":engine [wasm|js] display or switch evaluation engine (wasm or js)",
1333
+ ":engine [wasm|pkir|js] display or switch evaluation engine",
1294
1334
  ":rel name show relation definition",
1295
1335
  ":rels list relation aliases",
1336
+ ":limit [num|none] set maximum characters for value output",
1296
1337
  ":codec load file load a codec module from file (e.g. :codec load codecs/int.mjs)",
1297
1338
  ":codec unload name unload a registered codec",
1298
1339
  ":codec list list loaded codecs (or simply :codecs)",
@@ -1316,15 +1357,19 @@ function promptForState(state) {
1316
1357
  }
1317
1358
 
1318
1359
  function cliUsage() {
1319
- console.log("Usage: k-repl [options]");
1360
+ console.log("Start the interactive k interpreter.");
1361
+ console.log("Type :help inside the REPL for commands.");
1320
1362
  console.log("");
1321
- console.log("Start the interactive k interpreter. Type :help inside the REPL for commands.");
1363
+ console.log("Usage: k-repl [options]");
1322
1364
  console.log("");
1323
1365
  console.log("Options:");
1324
- console.log(" --engine=<wasm|js> Select evaluation engine (default: wasm)");
1325
- console.log(" --js Shortcut for --engine=js");
1326
- console.log(" --wasm Shortcut for --engine=wasm");
1327
- console.log(" -h, --help Show this help.");
1366
+ console.log(" --engine=<wasm|pkir|js> Select engine: wasm, pkir, js");
1367
+ console.log(" (default: wasm).");
1368
+ console.log(" --pkir Shortcut for --engine=pkir.");
1369
+ console.log(" --wasm Shortcut for --engine=wasm.");
1370
+ console.log(" --js Shortcut for --engine=js.");
1371
+ console.log(" --limit=<num> Set maximum characters for output.");
1372
+ console.log(" -h, --help Show this help.");
1328
1373
  }
1329
1374
 
1330
1375
  function startRepl(options = {}) {
@@ -1419,6 +1464,7 @@ function startRepl(options = {}) {
1419
1464
  if (isMainEntrypoint()) {
1420
1465
  const args = argv.slice(2);
1421
1466
  let engine = "wasm";
1467
+ let printLimit = Infinity;
1422
1468
  for (let i = 0; i < args.length; i++) {
1423
1469
  const arg = args[i];
1424
1470
  if (arg === "-h" || arg === "--help") {
@@ -1428,28 +1474,51 @@ if (isMainEntrypoint()) {
1428
1474
  engine = "js";
1429
1475
  } else if (arg === "--wasm") {
1430
1476
  engine = "wasm";
1477
+ } else if (arg === "--pkir") {
1478
+ engine = "pkir";
1431
1479
  } else if (arg.startsWith("--engine=")) {
1432
1480
  const val = arg.slice("--engine=".length).toLowerCase();
1433
- if (val !== "wasm" && val !== "js") {
1434
- console.error(`Invalid engine '${val}'. Valid engines: wasm, js`);
1481
+ if (val !== "wasm" && val !== "pkir" && val !== "js") {
1482
+ console.error(
1483
+ `Invalid engine '${val}'. Valid engines: wasm, pkir, js`
1484
+ );
1435
1485
  exit(1);
1436
1486
  }
1437
1487
  engine = val;
1438
1488
  } else if (arg === "--engine") {
1439
1489
  i++;
1440
1490
  const val = (args[i] || "").toLowerCase();
1441
- if (val !== "wasm" && val !== "js") {
1442
- console.error(`Invalid engine '${val}'. Valid engines: wasm, js`);
1491
+ if (val !== "wasm" && val !== "pkir" && val !== "js") {
1492
+ console.error(
1493
+ `Invalid engine '${val}'. Valid engines: wasm, pkir, js`
1494
+ );
1443
1495
  exit(1);
1444
1496
  }
1445
1497
  engine = val;
1498
+ } else if (arg.startsWith("--limit=")) {
1499
+ const val = parseInt(arg.slice("--limit=".length), 10);
1500
+ if (Number.isNaN(val) || val < 0) {
1501
+ console.error(
1502
+ `Invalid limit '${arg.slice("--limit=".length)}'.`
1503
+ );
1504
+ exit(1);
1505
+ }
1506
+ printLimit = val;
1507
+ } else if (arg === "--limit") {
1508
+ i++;
1509
+ const val = parseInt(args[i] || "", 10);
1510
+ if (Number.isNaN(val) || val < 0) {
1511
+ console.error(`Invalid limit '${args[i]}'.`);
1512
+ exit(1);
1513
+ }
1514
+ printLimit = val;
1446
1515
  } else {
1447
1516
  console.error(`Unknown option '${arg}'.`);
1448
1517
  cliUsage();
1449
1518
  exit(1);
1450
1519
  }
1451
1520
  }
1452
- startRepl({ engine });
1521
+ startRepl({ engine, printLimit });
1453
1522
  }
1454
1523
 
1455
1524
  export {
@@ -91,7 +91,14 @@ for (const filename of verifiedExamples) {
91
91
  }
92
92
 
93
93
  // Bundle verified codecs for browser VFS as 100% self-contained ES modules
94
- const verifiedCodecs = ["json.mjs", "utf8.mjs", "int.mjs", "unit.mjs", "ieee.mjs"];
94
+ const verifiedCodecs = [
95
+ "json.mjs",
96
+ "djson.mjs",
97
+ "utf8.mjs",
98
+ "int.mjs",
99
+ "unit.mjs",
100
+ "ieee.mjs"
101
+ ];
95
102
  const codecsDir = path.join(projectRoot, "codecs");
96
103
 
97
104
  const browserCodecSdkShim = `
@@ -284,6 +291,17 @@ const htmlContent = `<!DOCTYPE html>
284
291
  border-color: rgba(240, 180, 41, 0.7);
285
292
  }
286
293
 
294
+ .engine-badge.pkir-mode {
295
+ background: rgba(187, 128, 255, 0.15);
296
+ color: #d2a8ff;
297
+ border-color: rgba(187, 128, 255, 0.4);
298
+ }
299
+
300
+ .engine-badge.pkir-mode:hover {
301
+ background: rgba(187, 128, 255, 0.3);
302
+ border-color: rgba(187, 128, 255, 0.7);
303
+ }
304
+
287
305
  .status-indicator {
288
306
  display: flex;
289
307
  align-items: center;
@@ -1644,7 +1662,7 @@ const htmlContent = `<!DOCTYPE html>
1644
1662
  <div class="nav-left">
1645
1663
  <div class="brand">
1646
1664
  <span class="brand-name">k repl</span>
1647
- <span id="engine-badge" class="engine-badge" title="Click to toggle engine (wasm/js)">wasm-in-process</span>
1665
+ <span id="engine-badge" class="engine-badge" title="Click to toggle engine (wasm/pkir/js)">wasm-in-process</span>
1648
1666
  </div>
1649
1667
  <div class="status-indicator">
1650
1668
  <span id="status-dot" class="status-dot ready"></span>
@@ -1673,6 +1691,7 @@ const htmlContent = `<!DOCTYPE html>
1673
1691
  <option value="expr::rels">:rels (list relations)</option>
1674
1692
  <option value="expr::engine">:engine (show engine)</option>
1675
1693
  <option value="expr::engine wasm">:engine wasm</option>
1694
+ <option value="expr::engine pkir">:engine pkir</option>
1676
1695
  <option value="expr::engine js">:engine js</option>
1677
1696
  </optgroup>
1678
1697
  <optgroup label="Codecs &amp; Format Adapters">
@@ -1867,7 +1886,7 @@ const htmlContent = `<!DOCTYPE html>
1867
1886
  <div class="help-section">
1868
1887
  <h4>REPL Commands</h4>
1869
1888
  <table class="help-table">
1870
- <tr><td><code>:engine [wasm|js]</code></td><td>Display or switch evaluation engine (<code>wasm</code> or <code>js</code>)</td></tr>
1889
+ <tr><td><code>:engine [wasm|pkir|js]</code></td><td>Display or switch evaluation engine (<code>wasm</code>, <code>pkir</code>, or <code>js</code>)</td></tr>
1871
1890
  <tr><td><code>:load &lt;file&gt;</code></td><td>Load a <code>.k</code> source or <code>.klib</code> library into current state</td></tr>
1872
1891
  <tr><td><code>:rel &lt;name&gt;</code></td><td>Display definition of relation <code>&lt;name&gt;</code></td></tr>
1873
1892
  <tr><td><code>:rels</code></td><td>List all relation aliases</td></tr>