@fraczak/k 7.0.1 → 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 (89) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/DOCS/BIG_PICTURE.md +5 -5
  3. package/DOCS/FILE_FORMATS.md +241 -18
  4. package/DOCS/OBJECT_FILE_AND_PATTERN.md +9 -9
  5. package/DOCS/PATTERNS.md +3 -3
  6. package/DOCS/POLYMORPHIC_IR.md +104 -0
  7. package/DOCS/PROFILING_AND_TRACING.md +60 -72
  8. package/DOCS/REPL.md +3 -3
  9. package/DOCS/book/03-types-as-finite-automata.md +4 -4
  10. package/DOCS/book/06-values-in-memory.md +9 -9
  11. package/DOCS/book/08-operational-semantics-and-execution.md +1 -1
  12. package/DOCS/book/09-compiler-architecture.md +2 -2
  13. package/DOCS/book/10-from-ast-to-intermediate-representation.md +2 -2
  14. package/DOCS/book/14-canonical-serialization.md +1 -1
  15. package/Examples/arithmetics.k +2 -2
  16. package/Examples/bnat.k +1 -1
  17. package/Examples/karatsuba-mult.k +2 -2
  18. package/JOURNAL.md +288 -0
  19. package/README.md +13 -10
  20. package/access-table.mjs +343 -0
  21. package/backend-api.mjs +18 -0
  22. package/backends/llvm/README.md +20 -21
  23. package/backends/llvm/bin/k-llvm-build.mjs +105 -32
  24. package/backends/llvm/bin/k-llvm-compile.mjs +63 -24
  25. package/backends/llvm/bin/k-llvm.mjs +292 -0
  26. package/backends/llvm/runtime/krt.c +41 -0
  27. package/backends/llvm/runtime/krt.h +2 -0
  28. package/backends/llvm/src/cli.mjs +95 -17
  29. package/backends/llvm/src/executable.mjs +132 -15
  30. package/backends/llvm/src/kvm2llvm.mjs +50 -23
  31. package/backends/llvm/src/llvm.mjs +133 -20
  32. package/backends/llvm/tests/integration.sh +11 -11
  33. package/backends/llvm/{bin → tests}/k-llvm-run.mjs +48 -22
  34. package/backends/llvm/tests/perf-support.mjs +25 -58
  35. package/backends/llvm/tests/test-llvm.mjs +25 -4
  36. package/backends/wasm/bin/k-wasm-compile.mjs +46 -20
  37. package/backends/wasm/bin/k-wasm-run.mjs +61 -20
  38. package/backends/wasm/bin/k-wasm.mjs +47 -13
  39. package/backends/wasm/src/cli.mjs +141 -19
  40. package/backends/wasm/src/wasm.mjs +132 -24
  41. package/backends/wasm/tests/test-wasm.mjs +5 -5
  42. package/browser/repl-browser.mjs +16 -5
  43. package/browser/vfs-data.mjs +5 -5
  44. package/codecs/k-parse.mjs +29 -8
  45. package/codecs/k-print.mjs +22 -6
  46. package/codecs/runtime/codec-sdk.mjs +8 -4
  47. package/codecs/show.mjs +20 -6
  48. package/core.k +8 -8
  49. package/harness/format.mjs +2 -2
  50. package/harness/registry.mjs +0 -2
  51. package/k.mjs +56 -16
  52. package/kir.mjs +200 -75
  53. package/kvm.mjs +49 -12
  54. package/objects/compile.mjs +37 -23
  55. package/objects/decompile.mjs +40 -10
  56. package/objects/extract-aliases.mjs +44 -14
  57. package/objects/inspect.mjs +19 -14
  58. package/objects/validate.mjs +18 -11
  59. package/package.json +10 -7
  60. package/pkir.mjs +772 -0
  61. package/repl.mjs +36 -18
  62. package/scripts/benchmark-idempotency.mjs +12 -8
  63. package/scripts/benchmark.mjs +5 -9
  64. package/scripts/build-repl-html.mjs +16 -4
  65. package/scripts/perf-ieee.mjs +253 -103
  66. package/scripts/perf-int.mjs +585 -297
  67. package/scripts/perf-multiplication.mjs +66 -25
  68. package/scripts/perf-poly.mjs +292 -164
  69. package/scripts/run-tests.mjs +3 -0
  70. package/tests/code-derivation/pattern-envelope.mjs +4 -4
  71. package/tests/test-access-table.mjs +213 -0
  72. package/tests/test-kvm-polymorphic.mjs +2 -2
  73. package/tests/test-pkir.mjs +530 -0
  74. package/tests/test-polymorphic-tdd.mjs +196 -0
  75. package/tests/test-repl-html.mjs +15 -2
  76. package/tests/test-repl.mjs +30 -1
  77. package/backends/arm64/README.md +0 -103
  78. package/backends/arm64/bin/k-arm64-compile.mjs +0 -93
  79. package/backends/arm64/bin/k-arm64-run.mjs +0 -58
  80. package/backends/arm64/bin/k-arm64.mjs +0 -88
  81. package/backends/arm64/scripts/run-tests.mjs +0 -57
  82. package/backends/arm64/src/arm64.mjs +0 -229
  83. package/backends/arm64/src/cli.mjs +0 -155
  84. package/backends/arm64/src/kvm2arm64.mjs +0 -906
  85. package/backends/arm64/src/runtime.c +0 -744
  86. package/backends/arm64/tests/integration.sh +0 -112
  87. package/backends/arm64/tests/test-arm64.mjs +0 -240
  88. package/backends/llvm/bin/k-llvm-jit.mjs +0 -160
  89. package/harness/adapters/arm64.mjs +0 -105
@@ -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);
@@ -439,7 +447,8 @@ function relTypeStatus(defs, name) {
439
447
  const rel = defs.rels?.[name];
440
448
  const explicit = rel?.typeDerivation?.status;
441
449
  if (explicit) return explicit;
442
- const scc = compileStatsByRelName(defs.compileStats).get(name);
450
+ const stats = compileStatsByRelName(defs.compileStats);
451
+ const scc = stats.get(name) || (name.includes("$") ? stats.get(name.split("$")[0]) : null);
443
452
  if (scc) return scc.converged ? "converged" : "not-converged";
444
453
  return "unknown";
445
454
  }
@@ -501,7 +510,7 @@ function buildExportPreamble(exportSpecs, libraries) {
501
510
  async function compileWasmArtifactFromDefs(
502
511
  defs,
503
512
  mainRelName = "__main__",
504
- { typingMode = "generic" } = {}
513
+ { typingMode = "generic", usePKIR = false } = {}
505
514
  ) {
506
515
  resetTagIds();
507
516
  const mainRel = defs.rels[mainRelName];
@@ -509,7 +518,11 @@ async function compileWasmArtifactFromDefs(
509
518
  throw new Error(`No main relation (${mainRelName}) defined in script`);
510
519
  }
511
520
 
512
- const { wat: moduleWatBody, relationNames, entryName } = compileModule(mainRelName, defs);
521
+ const { wat: moduleWatBody, relationNames, entryName } = compileModule(
522
+ mainRelName,
523
+ defs,
524
+ { usePKIR }
525
+ );
513
526
  assertRelationsConverged(defs, relationNames);
514
527
  const fullWat = runtimeWat.trim().slice(0, -1) + "\n" + moduleWatBody + "\n)";
515
528
  const graph = mainRel.typePatternGraph;
@@ -522,7 +535,12 @@ async function compileWasmArtifactFromDefs(
522
535
  entry: entryName || cleanName(mainRelName),
523
536
  inputPattern,
524
537
  outputPattern,
525
- typing: classifyTyping(inputPattern, outputPattern, relTypeStatus(defs, mainRelName), typingMode),
538
+ typing: classifyTyping(
539
+ inputPattern,
540
+ outputPattern,
541
+ relTypeStatus(defs, mainRelName),
542
+ typingMode
543
+ ),
526
544
  tags: getTagEntries()
527
545
  };
528
546
  return appendCustomSection(await compileWat(fullWat), METADATA_SECTION, JSON.stringify(metadata));
@@ -597,12 +615,17 @@ async function compileWasmArtifactFromKVM(kvmInput, options = {}) {
597
615
  return appendCustomSection(await compileWat(fullWat), METADATA_SECTION, JSON.stringify(metadata));
598
616
  }
599
617
 
600
- async function compileWasmArtifactFromObject(object, { entry = null, inputEnvelopePattern = null } = {}) {
618
+ async function compileWasmArtifactFromObject(
619
+ object,
620
+ { entry = null, inputEnvelopePattern = null, usePKIR = false } = {}
621
+ ) {
601
622
  if (!object?.rels) {
602
623
  throw new Error("Expected .ko input to contain k object relations");
603
624
  }
604
625
  if (object.main == null) {
605
- 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
+ );
606
629
  }
607
630
  const mainRelName = entry || object.main || "__main__";
608
631
  let defs = { rels: object.rels, compileStats: object.compileStats };
@@ -610,43 +633,126 @@ async function compileWasmArtifactFromObject(object, { entry = null, inputEnvelo
610
633
 
611
634
  if (inputEnvelopePattern) {
612
635
  const mainRel = object.rels[mainRelName];
613
- if (!mainRel) throw new Error(`No main relation (${mainRelName}) defined in object`);
614
- const inputPattern = getPatternPropertyList(mainRel.typePatternGraph, mainRel.def.patterns[0]);
615
- 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
+ );
616
647
  const typing = classifyTyping(inputPattern, outputPattern);
617
648
  if (typing.program === "polymorphic") {
618
- const specialized = specializeObjectRelations(object, mainRelName, inputEnvelopePattern);
619
- 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
+ };
620
659
  typingMode = "specialized";
621
660
  }
622
661
  }
623
662
 
624
- return compileWasmArtifactFromDefs(defs, mainRelName, { typingMode });
663
+ return compileWasmArtifactFromDefs(defs, mainRelName, {
664
+ typingMode,
665
+ usePKIR
666
+ });
625
667
  }
626
668
 
627
669
  async function compileWasmArtifact(
628
670
  source,
629
- { libraries = [], exports = [], source: sourceName = null, inputEnvelopePattern = null } = {}
671
+ {
672
+ libraries = [],
673
+ exports = [],
674
+ source: sourceName = null,
675
+ inputEnvelopePattern = null,
676
+ usePKIR = false
677
+ } = {}
630
678
  ) {
631
679
  const preamble = buildExportPreamble(exports, libraries);
632
680
  const fullSource = preamble + source;
633
- const options = { libraries, ...(sourceName ? { source: sourceName } : {}) };
681
+ const options = {
682
+ libraries,
683
+ ...(sourceName ? { source: sourceName } : {})
684
+ };
634
685
  let defs = annotate(fullSource, options);
635
686
 
636
687
  let typingMode = "generic";
637
688
  if (inputEnvelopePattern) {
638
689
  const mainRel = defs.rels.__main__;
639
- const inputPattern = getPatternPropertyList(mainRel.typePatternGraph, mainRel.def.patterns[0]);
640
- 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
+ );
641
698
  if (classifyTyping(inputPattern, outputPattern).program === "polymorphic") {
642
- const obj = { format: "k-object", rels: defs.rels, relAlias: defs.relAlias, compileStats: defs.compileStats, main: "__main__" };
643
- const specialized = specializeObjectRelations(obj, "__main__", inputEnvelopePattern);
644
- 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
+ };
645
716
  typingMode = "specialized";
646
717
  }
647
718
  }
648
719
 
649
- 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
+ );
650
756
  }
651
757
 
652
758
  function createTagRegistry(entries) {
@@ -1049,6 +1155,7 @@ export {
1049
1155
  appendCustomSection,
1050
1156
  compileWasmArtifactFromKVM,
1051
1157
  compileWasmArtifactFromObject,
1158
+ compileWasmArtifactFromPKIR,
1052
1159
  compileWasmArtifact,
1053
1160
  instantiateWasmArtifact,
1054
1161
  metadataFromModule,
@@ -1066,6 +1173,7 @@ export default {
1066
1173
  appendCustomSection,
1067
1174
  compileWasmArtifactFromKVM,
1068
1175
  compileWasmArtifactFromObject,
1176
+ compileWasmArtifactFromPKIR,
1069
1177
  compileWasmArtifact,
1070
1178
  metadataFromModule,
1071
1179
  readArenaValue,
@@ -443,11 +443,11 @@ console.log("==> Running End-to-End Peano Addition & Serialization Tests");
443
443
  const runtimeWat = fs.readFileSync("runtime.wat", "utf8");
444
444
 
445
445
  const script = `
446
- nat = ?< {} 0, nat +1 >;
447
- 0 = {} | 0 nat;
448
- inc = | +1 nat;
449
- dec = nat / +1;
450
- add = ?{ nat x, nat y } = X <
446
+ nat? = ?< {} 0, nat? +1 >;
447
+ 0 = {} | 0 nat?;
448
+ inc = | +1 nat?;
449
+ dec = nat? / +1;
450
+ add = ?{ nat? x, nat? y } = X <
451
451
  { . x dec x, . y inc y } ?X add,
452
452
  . y
453
453
  >;
@@ -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
  }