@fraczak/k 7.0.2 → 7.1.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 (54) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/DOCS/FILE_FORMATS.md +238 -15
  3. package/DOCS/POLYMORPHIC_IR.md +104 -0
  4. package/JOURNAL.md +288 -0
  5. package/README.md +10 -2
  6. package/access-table.mjs +343 -0
  7. package/backend-api.mjs +18 -0
  8. package/backends/llvm/README.md +20 -21
  9. package/backends/llvm/bin/k-llvm-build.mjs +105 -32
  10. package/backends/llvm/bin/k-llvm-compile.mjs +63 -24
  11. package/backends/llvm/bin/k-llvm.mjs +292 -0
  12. package/backends/llvm/runtime/krt.c +8 -0
  13. package/backends/llvm/runtime/krt.h +1 -0
  14. package/backends/llvm/src/cli.mjs +95 -17
  15. package/backends/llvm/src/executable.mjs +128 -11
  16. package/backends/llvm/src/kvm2llvm.mjs +10 -5
  17. package/backends/llvm/src/llvm.mjs +121 -9
  18. package/backends/llvm/tests/integration.sh +11 -11
  19. package/backends/llvm/{bin → tests}/k-llvm-run.mjs +48 -22
  20. package/backends/llvm/tests/perf-support.mjs +24 -3
  21. package/backends/llvm/tests/test-llvm.mjs +22 -1
  22. package/backends/wasm/bin/k-wasm-compile.mjs +46 -20
  23. package/backends/wasm/bin/k-wasm-run.mjs +61 -20
  24. package/backends/wasm/bin/k-wasm.mjs +47 -13
  25. package/backends/wasm/src/cli.mjs +141 -19
  26. package/backends/wasm/src/wasm.mjs +130 -23
  27. package/browser/repl-browser.mjs +16 -5
  28. package/codecs/k-parse.mjs +29 -8
  29. package/codecs/k-print.mjs +22 -6
  30. package/codecs/runtime/codec-sdk.mjs +8 -4
  31. package/codecs/show.mjs +20 -6
  32. package/k.mjs +56 -16
  33. package/kir.mjs +58 -19
  34. package/kvm.mjs +49 -12
  35. package/objects/compile.mjs +37 -23
  36. package/objects/decompile.mjs +40 -10
  37. package/objects/extract-aliases.mjs +44 -14
  38. package/objects/inspect.mjs +19 -14
  39. package/objects/validate.mjs +18 -11
  40. package/package.json +10 -3
  41. package/pkir.mjs +772 -0
  42. package/repl.mjs +36 -18
  43. package/scripts/build-repl-html.mjs +14 -2
  44. package/scripts/perf-ieee.mjs +264 -13
  45. package/scripts/perf-int.mjs +315 -22
  46. package/scripts/perf-multiplication.mjs +58 -7
  47. package/scripts/perf-poly.mjs +306 -24
  48. package/scripts/run-tests.mjs +3 -0
  49. package/tests/test-access-table.mjs +213 -0
  50. package/tests/test-pkir.mjs +530 -0
  51. package/tests/test-polymorphic-tdd.mjs +196 -0
  52. package/tests/test-repl-html.mjs +15 -2
  53. package/tests/test-repl.mjs +30 -1
  54. package/backends/llvm/bin/k-llvm-jit.mjs +0 -160
@@ -1,26 +1,112 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
 
4
- import { decodeObject, loadLibrary } from "@fraczak/k/backend-api.mjs";
4
+ import {
5
+ compileLibrary,
6
+ decodeObject,
7
+ loadLibrary
8
+ } from "@fraczak/k/backend-api.mjs";
5
9
  import {
6
10
  compileWasmArtifact,
7
11
  compileWasmArtifactFromKVM,
8
- compileWasmArtifactFromObject
12
+ compileWasmArtifactFromObject,
13
+ compileWasmArtifactFromPKIR
9
14
  } from "./wasm.mjs";
10
15
 
11
16
  function readAll(stream) {
12
17
  return new Promise((resolve, reject) => {
13
18
  const chunks = [];
14
- stream.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
19
+ stream.on("data", (chunk) => {
20
+ chunks.push(
21
+ Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)
22
+ );
23
+ });
15
24
  stream.on("end", () => resolve(Buffer.concat(chunks)));
16
25
  stream.on("error", reject);
17
26
  });
18
27
  }
19
28
 
29
+ export function buildExportPreamble(exports = [], libraries = []) {
30
+ if (exports.length === 0) return "";
31
+ const aliasMap = {};
32
+ for (const lib of libraries) {
33
+ for (const [name, hash] of Object.entries(lib.relAlias || {})) {
34
+ if (name !== "__main__") aliasMap[name] = hash;
35
+ }
36
+ for (const [hash, entry] of Object.entries(lib.meta || {})) {
37
+ if (entry?.type !== "rel") continue;
38
+ for (const origin of entry?.origins || []) {
39
+ if (origin?.name && origin.name !== "__main__") {
40
+ aliasMap[origin.name] = hash;
41
+ }
42
+ }
43
+ }
44
+ }
45
+ const lines = [];
46
+ for (const spec of exports) {
47
+ const [libName, localName] = spec.includes(":")
48
+ ? spec.split(":", 2)
49
+ : [spec, spec];
50
+ const hash = aliasMap[libName];
51
+ if (!hash) {
52
+ throw new Error(
53
+ `--export: '${libName}' not found in loaded libraries`
54
+ );
55
+ }
56
+ const body = hash.startsWith("@") ? hash.slice(1) : hash;
57
+ lines.push(`${localName} = @${body};`);
58
+ }
59
+ return lines.join("\n") + "\n";
60
+ }
61
+
62
+ export function loadLibraryFromPath(libPath) {
63
+ const ext = path.extname(libPath).toLowerCase();
64
+ if (ext === ".klib" || ext === ".ko") {
65
+ return loadLibrary(decodeObject(fs.readFileSync(libPath)));
66
+ }
67
+ if (ext === ".k") {
68
+ let depLibs = [];
69
+ const baseName = path.basename(libPath);
70
+ if (baseName === "poly.k") {
71
+ const dir = path.dirname(libPath);
72
+ const arithPath = path.join(dir, "arithmetics.k");
73
+ if (fs.existsSync(arithPath)) {
74
+ const arithLib = loadLibrary(
75
+ compileLibrary(fs.readFileSync(arithPath, "utf8"), {
76
+ source: arithPath
77
+ })
78
+ );
79
+ depLibs.push(arithLib);
80
+ }
81
+ }
82
+ const rawSource = fs.readFileSync(libPath, "utf8");
83
+ if (depLibs.length > 0) {
84
+ const neededExports = [
85
+ "0", "int", "inc", "dec", "nat", "zero_int?", "neg?", "GT"
86
+ ];
87
+ const preamble = buildExportPreamble(neededExports, depLibs);
88
+ const compiled = compileLibrary(preamble + rawSource, {
89
+ source: libPath,
90
+ libraries: depLibs
91
+ });
92
+ const mergedLib = loadLibrary(compiled);
93
+ for (const dep of depLibs) {
94
+ for (const [k, v] of Object.entries(dep.relAlias || {})) {
95
+ if (!mergedLib.relAlias[k]) mergedLib.relAlias[k] = v;
96
+ }
97
+ }
98
+ return mergedLib;
99
+ }
100
+ return loadLibrary(compileLibrary(rawSource, { source: libPath }));
101
+ }
102
+ throw new Error(`Unsupported library extension: ${ext}`);
103
+ }
104
+
20
105
  function parseCompileOptions(args) {
21
106
  const libraries = [];
22
107
  const exportSpecs = [];
23
108
  let loadedLibrary = false;
109
+ let usePKIR = false;
24
110
 
25
111
  while (args.length > 0) {
26
112
  if (args[0] === "--") {
@@ -28,25 +114,34 @@ function parseCompileOptions(args) {
28
114
  break;
29
115
  }
30
116
  if (args[0] === "--lib") {
31
- if (loadedLibrary) throw new Error("--lib may only be specified once");
117
+ if (loadedLibrary) {
118
+ throw new Error("--lib may only be specified once");
119
+ }
32
120
  args.shift();
33
121
  const libPath = args.shift();
34
122
  if (!libPath) throw new Error("--lib requires a file argument");
35
- libraries.push(loadLibrary(decodeObject(fs.readFileSync(libPath))));
123
+ libraries.push(loadLibraryFromPath(libPath));
36
124
  loadedLibrary = true;
37
125
  } else if (args[0] === "--export") {
38
126
  args.shift();
39
127
  const spec = args.shift();
40
- if (!spec) throw new Error("--export requires a spec argument (name or libname:localname)");
128
+ if (!spec) {
129
+ throw new Error(
130
+ "--export requires a spec argument (name or libname:localname)"
131
+ );
132
+ }
41
133
  exportSpecs.push(spec);
134
+ } else if (args[0] === "--pkir") {
135
+ args.shift();
136
+ usePKIR = true;
42
137
  } else if (args[0].startsWith("--")) {
43
- throw new Error(`Unknown option: ${args[0]}`);
138
+ break;
44
139
  } else {
45
140
  break;
46
141
  }
47
142
  }
48
143
 
49
- return { libraries, exportSpecs };
144
+ return { libraries, exportSpecs, usePKIR };
50
145
  }
51
146
 
52
147
  function fileInputType(filePath) {
@@ -54,6 +149,7 @@ function fileInputType(filePath) {
54
149
  if (ext === ".ko") return "ko";
55
150
  if (ext === ".kvm") return "kvm";
56
151
  if (ext === ".klib") return "klib";
152
+ if (ext === ".pkir") return "pkir";
57
153
  return "source-file";
58
154
  }
59
155
 
@@ -68,38 +164,55 @@ function resolveProgramInput(args, { allowStdinSource = false } = {}) {
68
164
  if (fs.existsSync(inputArg)) {
69
165
  const kind = fileInputType(inputArg);
70
166
  if (kind === "klib") {
71
- throw new Error("Cannot compile a .klib library to WebAssembly without a main relation; load it with --lib.");
167
+ throw new Error(
168
+ "Cannot compile a .klib library to WebAssembly without a main " +
169
+ "relation; load it with --lib."
170
+ );
72
171
  }
73
172
  return { kind, path: inputArg, sourceName: inputArg };
74
173
  }
75
174
 
76
- if ([".k", ".ko", ".kvm", ".klib", ".wasm"].includes(ext)) {
175
+ if ([".k", ".ko", ".kvm", ".klib", ".wasm", ".pkir"].includes(ext)) {
77
176
  throw new Error(`Input file not found: ${inputArg}`);
78
177
  }
79
178
 
80
- return { kind: "inline-source", source: inputArg, sourceName: "<inline>" };
179
+ return {
180
+ kind: "inline-source",
181
+ source: inputArg,
182
+ sourceName: "<inline>"
183
+ };
81
184
  }
82
185
 
83
186
  async function compileProgramInput(
84
187
  input,
85
- { libraries = [], exportSpecs = [], stdin = null, inputEnvelopePattern = null } = {}
188
+ {
189
+ libraries = [],
190
+ exportSpecs = [],
191
+ stdin = null,
192
+ inputEnvelopePattern = null,
193
+ usePKIR = false
194
+ } = {}
86
195
  ) {
87
196
  if (input.kind === "inline-source") {
88
197
  return compileWasmArtifact(input.source, {
89
198
  libraries,
90
199
  exports: exportSpecs,
91
200
  source: input.sourceName,
92
- inputEnvelopePattern
201
+ inputEnvelopePattern,
202
+ usePKIR
93
203
  });
94
204
  }
95
205
 
96
206
  if (input.kind === "stdin-source") {
97
- if (!stdin) throw new Error("stdin source requested without a stdin stream");
207
+ if (!stdin) {
208
+ throw new Error("stdin source requested without a stdin stream");
209
+ }
98
210
  return compileWasmArtifact((await readAll(stdin)).toString("utf8"), {
99
211
  libraries,
100
212
  exports: exportSpecs,
101
213
  source: input.sourceName,
102
- inputEnvelopePattern
214
+ inputEnvelopePattern,
215
+ usePKIR
103
216
  });
104
217
  }
105
218
 
@@ -108,18 +221,27 @@ async function compileProgramInput(
108
221
  libraries,
109
222
  exports: exportSpecs,
110
223
  source: input.sourceName,
111
- inputEnvelopePattern
224
+ inputEnvelopePattern,
225
+ usePKIR
112
226
  });
113
227
  }
114
228
 
115
229
  if (input.kind === "ko") {
116
- return compileWasmArtifactFromObject(decodeObject(fs.readFileSync(input.path)), {
117
- inputEnvelopePattern
230
+ const obj = decodeObject(fs.readFileSync(input.path));
231
+ return compileWasmArtifactFromObject(obj, {
232
+ inputEnvelopePattern,
233
+ usePKIR
118
234
  });
119
235
  }
120
236
 
237
+ if (input.kind === "pkir") {
238
+ const pkir = JSON.parse(fs.readFileSync(input.path, "utf8"));
239
+ return compileWasmArtifactFromPKIR(pkir);
240
+ }
241
+
121
242
  if (input.kind === "kvm") {
122
- return compileWasmArtifactFromKVM(JSON.parse(fs.readFileSync(input.path, "utf8")));
243
+ const kvm = JSON.parse(fs.readFileSync(input.path, "utf8"));
244
+ return compileWasmArtifactFromKVM(kvm);
123
245
  }
124
246
 
125
247
  throw new Error(`Unsupported input kind: ${input.kind}`);
@@ -14,7 +14,9 @@ import {
14
14
  propertyListToPattern,
15
15
  Value,
16
16
  specializeKVM,
17
- specializeObjectRelations
17
+ specializeObjectRelations,
18
+ compileRelationToPKIR,
19
+ lowerPKIRToKVM
18
20
  } from "@fraczak/k/backend-api.mjs";
19
21
  import { intersectPropertyListPatterns } from "@fraczak/k/codecs/runtime/codec.mjs";
20
22
  import { propertyListToFilter } from "@fraczak/k/codecs/runtime/show-value.mjs";
@@ -283,7 +285,7 @@ function cloneKVMFunction(kvmFunc) {
283
285
  };
284
286
  }
285
287
 
286
- function compileModule(mainRelName, defs) {
288
+ function compileModule(mainRelName, defs, { usePKIR = false } = {}) {
287
289
  const compiled = new Set();
288
290
  const queue = [mainRelName];
289
291
  const wats = [];
@@ -299,8 +301,14 @@ function compileModule(mainRelName, defs) {
299
301
  throw new Error(`Relation ${name} not found`);
300
302
  }
301
303
 
302
- const kvmFunc = lowerToKVM(relDef, name);
303
- kvmFunc.typePatternGraph = relDef.typePatternGraph;
304
+ let kvmFunc;
305
+ if (usePKIR) {
306
+ const pkir = compileRelationToPKIR(relDef, name);
307
+ kvmFunc = lowerPKIRToKVM(pkir);
308
+ } else {
309
+ kvmFunc = lowerToKVM(relDef, name);
310
+ kvmFunc.typePatternGraph = relDef.typePatternGraph;
311
+ }
304
312
  scanCalls(kvmFunc.body, compiled, queue);
305
313
 
306
314
  kvmFunc.name = nameMap.get(name) || cleanName(name);
@@ -502,7 +510,7 @@ function buildExportPreamble(exportSpecs, libraries) {
502
510
  async function compileWasmArtifactFromDefs(
503
511
  defs,
504
512
  mainRelName = "__main__",
505
- { typingMode = "generic" } = {}
513
+ { typingMode = "generic", usePKIR = false } = {}
506
514
  ) {
507
515
  resetTagIds();
508
516
  const mainRel = defs.rels[mainRelName];
@@ -510,7 +518,11 @@ async function compileWasmArtifactFromDefs(
510
518
  throw new Error(`No main relation (${mainRelName}) defined in script`);
511
519
  }
512
520
 
513
- const { wat: moduleWatBody, relationNames, entryName } = compileModule(mainRelName, defs);
521
+ const { wat: moduleWatBody, relationNames, entryName } = compileModule(
522
+ mainRelName,
523
+ defs,
524
+ { usePKIR }
525
+ );
514
526
  assertRelationsConverged(defs, relationNames);
515
527
  const fullWat = runtimeWat.trim().slice(0, -1) + "\n" + moduleWatBody + "\n)";
516
528
  const graph = mainRel.typePatternGraph;
@@ -523,7 +535,12 @@ async function compileWasmArtifactFromDefs(
523
535
  entry: entryName || cleanName(mainRelName),
524
536
  inputPattern,
525
537
  outputPattern,
526
- typing: classifyTyping(inputPattern, outputPattern, relTypeStatus(defs, mainRelName), typingMode),
538
+ typing: classifyTyping(
539
+ inputPattern,
540
+ outputPattern,
541
+ relTypeStatus(defs, mainRelName),
542
+ typingMode
543
+ ),
527
544
  tags: getTagEntries()
528
545
  };
529
546
  return appendCustomSection(await compileWat(fullWat), METADATA_SECTION, JSON.stringify(metadata));
@@ -598,12 +615,17 @@ async function compileWasmArtifactFromKVM(kvmInput, options = {}) {
598
615
  return appendCustomSection(await compileWat(fullWat), METADATA_SECTION, JSON.stringify(metadata));
599
616
  }
600
617
 
601
- async function compileWasmArtifactFromObject(object, { entry = null, inputEnvelopePattern = null } = {}) {
618
+ async function compileWasmArtifactFromObject(
619
+ object,
620
+ { entry = null, inputEnvelopePattern = null, usePKIR = false } = {}
621
+ ) {
602
622
  if (!object?.rels) {
603
623
  throw new Error("Expected .ko input to contain k object relations");
604
624
  }
605
625
  if (object.main == null) {
606
- throw new Error("Cannot compile a .klib library to WebAssembly without a main relation");
626
+ throw new Error(
627
+ "Cannot compile a .klib library to WebAssembly without a main relation"
628
+ );
607
629
  }
608
630
  const mainRelName = entry || object.main || "__main__";
609
631
  let defs = { rels: object.rels, compileStats: object.compileStats };
@@ -611,43 +633,126 @@ async function compileWasmArtifactFromObject(object, { entry = null, inputEnvelo
611
633
 
612
634
  if (inputEnvelopePattern) {
613
635
  const mainRel = object.rels[mainRelName];
614
- if (!mainRel) throw new Error(`No main relation (${mainRelName}) defined in object`);
615
- const inputPattern = getPatternPropertyList(mainRel.typePatternGraph, mainRel.def.patterns[0]);
616
- const outputPattern = getPatternPropertyList(mainRel.typePatternGraph, mainRel.def.patterns[1]);
636
+ if (!mainRel) {
637
+ throw new Error(`No main relation (${mainRelName}) defined in object`);
638
+ }
639
+ const inputPattern = getPatternPropertyList(
640
+ mainRel.typePatternGraph,
641
+ mainRel.def.patterns[0]
642
+ );
643
+ const outputPattern = getPatternPropertyList(
644
+ mainRel.typePatternGraph,
645
+ mainRel.def.patterns[1]
646
+ );
617
647
  const typing = classifyTyping(inputPattern, outputPattern);
618
648
  if (typing.program === "polymorphic") {
619
- const specialized = specializeObjectRelations(object, mainRelName, inputEnvelopePattern);
620
- defs = { rels: specialized.rels, relAlias: specialized.relAlias, compileStats: specialized.compileStats };
649
+ const specialized = specializeObjectRelations(
650
+ object,
651
+ mainRelName,
652
+ inputEnvelopePattern
653
+ );
654
+ defs = {
655
+ rels: specialized.rels,
656
+ relAlias: specialized.relAlias,
657
+ compileStats: specialized.compileStats
658
+ };
621
659
  typingMode = "specialized";
622
660
  }
623
661
  }
624
662
 
625
- return compileWasmArtifactFromDefs(defs, mainRelName, { typingMode });
663
+ return compileWasmArtifactFromDefs(defs, mainRelName, {
664
+ typingMode,
665
+ usePKIR
666
+ });
626
667
  }
627
668
 
628
669
  async function compileWasmArtifact(
629
670
  source,
630
- { libraries = [], exports = [], source: sourceName = null, inputEnvelopePattern = null } = {}
671
+ {
672
+ libraries = [],
673
+ exports = [],
674
+ source: sourceName = null,
675
+ inputEnvelopePattern = null,
676
+ usePKIR = false
677
+ } = {}
631
678
  ) {
632
679
  const preamble = buildExportPreamble(exports, libraries);
633
680
  const fullSource = preamble + source;
634
- const options = { libraries, ...(sourceName ? { source: sourceName } : {}) };
681
+ const options = {
682
+ libraries,
683
+ ...(sourceName ? { source: sourceName } : {})
684
+ };
635
685
  let defs = annotate(fullSource, options);
636
686
 
637
687
  let typingMode = "generic";
638
688
  if (inputEnvelopePattern) {
639
689
  const mainRel = defs.rels.__main__;
640
- const inputPattern = getPatternPropertyList(mainRel.typePatternGraph, mainRel.def.patterns[0]);
641
- const outputPattern = getPatternPropertyList(mainRel.typePatternGraph, mainRel.def.patterns[1]);
690
+ const inputPattern = getPatternPropertyList(
691
+ mainRel.typePatternGraph,
692
+ mainRel.def.patterns[0]
693
+ );
694
+ const outputPattern = getPatternPropertyList(
695
+ mainRel.typePatternGraph,
696
+ mainRel.def.patterns[1]
697
+ );
642
698
  if (classifyTyping(inputPattern, outputPattern).program === "polymorphic") {
643
- const obj = { format: "k-object", rels: defs.rels, relAlias: defs.relAlias, compileStats: defs.compileStats, main: "__main__" };
644
- const specialized = specializeObjectRelations(obj, "__main__", inputEnvelopePattern);
645
- defs = { rels: specialized.rels, relAlias: specialized.relAlias, compileStats: specialized.compileStats };
699
+ const obj = {
700
+ format: "k-object",
701
+ rels: defs.rels,
702
+ relAlias: defs.relAlias,
703
+ compileStats: defs.compileStats,
704
+ main: "__main__"
705
+ };
706
+ const specialized = specializeObjectRelations(
707
+ obj,
708
+ "__main__",
709
+ inputEnvelopePattern
710
+ );
711
+ defs = {
712
+ rels: specialized.rels,
713
+ relAlias: specialized.relAlias,
714
+ compileStats: specialized.compileStats
715
+ };
646
716
  typingMode = "specialized";
647
717
  }
648
718
  }
649
719
 
650
- return compileWasmArtifactFromDefs(defs, "__main__", { typingMode });
720
+ return compileWasmArtifactFromDefs(defs, "__main__", {
721
+ typingMode,
722
+ usePKIR
723
+ });
724
+ }
725
+
726
+ async function compileWasmArtifactFromPKIR(pkirInput, options = {}) {
727
+ let kvmProgram;
728
+ let entry = options.entry || "__main__";
729
+ if (pkirInput && typeof pkirInput === "object") {
730
+ if (pkirInput.format === "pk-ir" && pkirInput.functions) {
731
+ entry = pkirInput.entry || entry;
732
+ kvmProgram = {};
733
+ for (const [name, f] of Object.entries(pkirInput.functions)) {
734
+ kvmProgram[name] = lowerPKIRToKVM(f);
735
+ }
736
+ } else if (pkirInput.instructions) {
737
+ const kvm = lowerPKIRToKVM(pkirInput);
738
+ entry = kvm.name || entry;
739
+ kvmProgram = { [entry]: kvm };
740
+ } else if (pkirInput.functions) {
741
+ entry = pkirInput.entry || entry;
742
+ kvmProgram = {};
743
+ for (const [name, f] of Object.entries(pkirInput.functions)) {
744
+ kvmProgram[name] = lowerPKIRToKVM(f);
745
+ }
746
+ } else {
747
+ throw new Error("Invalid PKIR input for WebAssembly compilation");
748
+ }
749
+ } else {
750
+ throw new Error("Expected PKIR input object");
751
+ }
752
+ return compileWasmArtifactFromKVM(
753
+ { format: "k-vm", layer: "KVM", entry, functions: kvmProgram },
754
+ options
755
+ );
651
756
  }
652
757
 
653
758
  function createTagRegistry(entries) {
@@ -1050,6 +1155,7 @@ export {
1050
1155
  appendCustomSection,
1051
1156
  compileWasmArtifactFromKVM,
1052
1157
  compileWasmArtifactFromObject,
1158
+ compileWasmArtifactFromPKIR,
1053
1159
  compileWasmArtifact,
1054
1160
  instantiateWasmArtifact,
1055
1161
  metadataFromModule,
@@ -1067,6 +1173,7 @@ export default {
1067
1173
  appendCustomSection,
1068
1174
  compileWasmArtifactFromKVM,
1069
1175
  compileWasmArtifactFromObject,
1176
+ compileWasmArtifactFromPKIR,
1070
1177
  compileWasmArtifact,
1071
1178
  metadataFromModule,
1072
1179
  readArenaValue,
@@ -311,13 +311,17 @@ export async function executeCommand(input) {
311
311
  function updateEngineUI() {
312
312
  const badge = document.getElementById("engine-badge");
313
313
  if (!badge) return;
314
- badge.textContent = state.engine === "js" ? "js-in-process" : "wasm-in-process";
315
- badge.title = `Engine: ${state.engine} (click to toggle wasm/js)`;
314
+ badge.classList.remove("js-mode", "pkir-mode");
316
315
  if (state.engine === "js") {
316
+ badge.textContent = "js-in-process";
317
317
  badge.classList.add("js-mode");
318
+ } else if (state.engine === "pkir") {
319
+ badge.textContent = "pkir-wasm";
320
+ badge.classList.add("pkir-mode");
318
321
  } else {
319
- badge.classList.remove("js-mode");
322
+ badge.textContent = "wasm-in-process";
320
323
  }
324
+ badge.title = `Engine: ${state.engine} (click to toggle wasm/pkir/js)`;
321
325
  }
322
326
 
323
327
  function adjustInputHeight() {
@@ -979,11 +983,18 @@ export function initRepl() {
979
983
  }
980
984
  });
981
985
 
982
- // Engine Badge toggle (wasm <-> js)
986
+ // Engine Badge toggle (wasm -> pkir -> js -> wasm)
983
987
  const engineBadge = document.getElementById("engine-badge");
984
988
  if (engineBadge) {
985
989
  engineBadge.onclick = () => {
986
- const nextEngine = state.engine === "wasm" ? "js" : "wasm";
990
+ let nextEngine;
991
+ if (state.engine === "wasm") {
992
+ nextEngine = "pkir";
993
+ } else if (state.engine === "pkir") {
994
+ nextEngine = "js";
995
+ } else {
996
+ nextEngine = "wasm";
997
+ }
987
998
  executeCommand(`:engine ${nextEngine}`);
988
999
  };
989
1000
  }
@@ -7,10 +7,32 @@ import { isMainEntrypoint } from "./runtime/cli-entry.mjs";
7
7
  import { patternFromFilter } from "./runtime/pattern-k.mjs";
8
8
  import { encodeToWire } from "./runtime/prefix-codec.mjs";
9
9
 
10
- function usage(prog) {
11
- console.error(`Usage: ${prog} [--input-type <type-script|type-file> | --input-pattern <pattern-script|pattern-file>] [value-file]`);
12
- console.error(" Parse a textual k value and emit the self-hosted binary pattern+value stream.");
13
- console.error(" If no pattern or type is provided, derive a closed pattern from the value.");
10
+ function helpText() {
11
+ const prog = argv[1] || "k-parse.mjs";
12
+ return [
13
+ "Parse a textual k value and emit a binary pattern+value stream.",
14
+ "If no pattern or type is provided, derives a closed pattern from",
15
+ "the value.",
16
+ "",
17
+ `Usage: ${prog} [options] [value-file]`,
18
+ "",
19
+ "Arguments:",
20
+ " value-file Input textual k value file.",
21
+ " Reads from stdin when omitted.",
22
+ "",
23
+ "Options:",
24
+ " --input-type type Type filter script or file for pattern.",
25
+ " --input-pattern json Pattern JSON string or file.",
26
+ " -h, --help Show this help.",
27
+ "",
28
+ "Examples:",
29
+ ` echo '{"x": 1}' | ${prog} | k-print`,
30
+ ` ${prog} --input-type '<{} a, {} b>' value.kv`
31
+ ].join("\n");
32
+ }
33
+
34
+ function usage(stream = console.error) {
35
+ stream(helpText());
14
36
  }
15
37
 
16
38
  function maybeReadFile(s) {
@@ -31,11 +53,10 @@ function readAll(stream) {
31
53
  }
32
54
 
33
55
  async function main() {
34
- const prog = argv[1];
35
56
  const args = argv.slice(2);
36
57
 
37
58
  if (args.includes("-h") || args.includes("--help")) {
38
- usage(prog);
59
+ usage(console.log);
39
60
  return exit(0);
40
61
  }
41
62
 
@@ -51,13 +72,13 @@ async function main() {
51
72
  } else if (valueFile == null) {
52
73
  valueFile = args[i];
53
74
  } else {
54
- usage(prog);
75
+ usage();
55
76
  return exit(1);
56
77
  }
57
78
  }
58
79
 
59
80
  if (inputTypeArg != null && inputPatternArg != null) {
60
- usage(prog);
81
+ usage();
61
82
  return exit(1);
62
83
  }
63
84
 
@@ -5,13 +5,29 @@ import { argv, stdin, stdout } from "node:process";
5
5
  import { isMainEntrypoint } from "./runtime/cli-entry.mjs";
6
6
  import { decodeWire } from "./runtime/prefix-codec.mjs";
7
7
 
8
+ function helpText() {
9
+ const prog = argv[1] || "k-print.mjs";
10
+ return [
11
+ "Read a binary pattern+value stream and print the decoded",
12
+ "textual value.",
13
+ "",
14
+ `Usage: ${prog} [options] [file]`,
15
+ "",
16
+ "Arguments:",
17
+ " file Input binary wire file (default: stdin).",
18
+ "",
19
+ "Options:",
20
+ " --debug Print decoded pattern and value as JSON.",
21
+ " -h, --help Show this help.",
22
+ "",
23
+ "Examples:",
24
+ ` echo '"hello"' | k-parse | ${prog}`,
25
+ ` ${prog} input.wire`
26
+ ].join("\n");
27
+ }
28
+
8
29
  function usage(stream = console.error) {
9
- stream(`Usage: ${argv[1]} [--debug] [file]`);
10
- stream(" Read a binary pattern+value stream and print the decoded textual value.");
11
- stream("");
12
- stream("Options:");
13
- stream(" --debug Print decoded pattern and value as JSON.");
14
- stream(" -h, --help Show this help.");
30
+ stream(helpText());
15
31
  }
16
32
 
17
33
  function readAll(stream) {
@@ -22,10 +22,14 @@ function printUsage(fileName, doc) {
22
22
  if (doc) {
23
23
  stdout.write(`${doc.trim()}\n\n`);
24
24
  }
25
- stdout.write("Options:\n");
26
- stdout.write(" --parse Read external text from stdin, write binary pattern+value stream to stdout.\n");
27
- stdout.write(" --print Read binary pattern+value stream from stdin, write external text to stdout.\n");
28
- stdout.write(" -h, --help Show this help.\n");
25
+ stdout.write(
26
+ "Options:\n" +
27
+ " --parse Read external text from stdin, write binary\n" +
28
+ " pattern+value stream to stdout.\n" +
29
+ " --print Read binary pattern+value stream from stdin,\n" +
30
+ " write external text to stdout.\n" +
31
+ " -h, --help Show this help.\n"
32
+ );
29
33
  }
30
34
 
31
35
  function runCodecCLI(metaUrl, codec) {