@fraczak/k 6.1.3 → 6.2.1

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 (80) hide show
  1. package/AGENTS.md +4 -4
  2. package/CLAUDE.md +1 -1
  3. package/DOCS/KIR_SPECIALIZATION_DESIGN.md +11 -2
  4. package/DOCS/KVM_EXECUTION_MODEL.md +413 -0
  5. package/DOCS/OBJECT_FILE_AND_PATTERN.md +6 -0
  6. package/DOCS/REPL.md +22 -17
  7. package/{NAT.k~ → Examples/arithmetics.k} +1 -1
  8. package/Examples/bnat.k +291 -0
  9. package/Examples/byte.k +67 -0
  10. package/Examples/code.k +44 -0
  11. package/Examples/esc.k +9 -0
  12. package/Examples/ieee.k +15766 -0
  13. package/Examples/list.k +7 -0
  14. package/Examples/nat.k +12 -0
  15. package/Examples/vhdl_to_k.k +50 -0
  16. package/README.md +14 -5
  17. package/backend-api.mjs +12 -0
  18. package/codecs/runtime/codec.mjs +1 -0
  19. package/export.mjs +10 -0
  20. package/k-vscode/README.md +10 -1
  21. package/k-vscode/extension.js +273 -0
  22. package/k-vscode/package.json +22 -0
  23. package/k-vscode/syntaxes/k.tmLanguage.json +493 -137
  24. package/k-vscode/test/background-ranges.test.js +50 -0
  25. package/k-vscode/themes/k-contrast-color-theme.json +104 -0
  26. package/kvm.mjs +523 -0
  27. package/package.json +4 -3
  28. package/repl.mjs +43 -2
  29. package/run.mjs +1 -1
  30. package/scripts/run-tests.mjs +55 -0
  31. package/tests/README.md +35 -0
  32. package/{Code-derivation-tests → tests/code-derivation}/codec-witness-pattern.mjs +4 -4
  33. package/{Code-derivation-tests → tests/code-derivation}/convergence-strategy.mjs +1 -1
  34. package/{Code-derivation-tests → tests/code-derivation}/dot.mjs +1 -1
  35. package/{Code-derivation-tests → tests/code-derivation}/filter-syntax.mjs +1 -1
  36. package/{Code-derivation-tests → tests/code-derivation}/index.mjs +1 -1
  37. package/{Code-derivation-tests → tests/code-derivation}/pattern-envelope.mjs +5 -5
  38. package/{Code-derivation-tests → tests/code-derivation}/product.mjs +1 -1
  39. package/{tests.sh → tests/integration.sh} +11 -6
  40. package/{test-fingerprint.mjs → tests/test-fingerprint.mjs} +3 -3
  41. package/{test-hash-fuzz.mjs → tests/test-hash-fuzz.mjs} +1 -1
  42. package/{test-hash-normalization.mjs → tests/test-hash-normalization.mjs} +2 -2
  43. package/{test-ieee-arithmetic.mjs → tests/test-ieee-arithmetic.mjs} +14 -27
  44. package/{test-k-object.mjs → tests/test-k-object.mjs} +8 -8
  45. package/tests/test-kvm.mjs +163 -0
  46. package/{test-repl.mjs → tests/test-repl.mjs} +22 -4
  47. package/{test.mjs → tests/test.mjs} +1 -1
  48. package/.codex +0 -0
  49. package/DOCS/a.html +0 -398
  50. package/DOCS/dependency-graph.html +0 -140
  51. package/DOCS/dependency-graph.md +0 -144
  52. package/UU/ta.k +0 -1
  53. package/UU/ta.k~ +0 -0
  54. package/UU/tb.k +0 -0
  55. package/UU/tc.k +0 -0
  56. package/a.k +0 -138
  57. package/a.klib +0 -1
  58. package/codecs/BINARY_FORMAT.html +0 -471
  59. package/codecs/POLYMORPHIC_BINARY_FORMAT.html +0 -355
  60. package/core.json +0 -1
  61. package/core.klib +0 -1
  62. package/core.klib~ +0 -0
  63. package/ieee.klib +0 -1
  64. package/k-vscode/package-lock.json +0 -4176
  65. package/kkk.k +0 -197
  66. package/kkk.klib +0 -0
  67. package/kkk.klib~ +0 -0
  68. package/nak.klib +0 -1
  69. package/nak2.klib +0 -1
  70. package/nat.k +0 -10
  71. package/nat2.k +0 -9
  72. package/p.json +0 -5475
  73. package/type_registry/registry.mjs~ +0 -105
  74. package/type_registry/typeParser.jison~ +0 -132
  75. /package/{Code-derivation-tests → tests/code-derivation}/blowup.mjs +0 -0
  76. /package/{Code-derivation-tests → tests/code-derivation}/bnat.mjs +0 -0
  77. /package/{Code-derivation-tests → tests/code-derivation}/loop.mjs +0 -0
  78. /package/{Code-derivation-tests → tests/code-derivation}/nat.mjs +0 -0
  79. /package/{Code-derivation-tests → tests/code-derivation}/not-not.mjs +0 -0
  80. /package/{Code-derivation-tests → tests/code-derivation}/rlz.mjs +0 -0
@@ -0,0 +1,50 @@
1
+ const assert = require("assert");
2
+ const Module = require("module");
3
+
4
+ const originalLoad = Module._load;
5
+ Module._load = function load(request, parent, isMain) {
6
+ if (request === "vscode") return {};
7
+ return originalLoad.call(this, request, parent, isMain);
8
+ };
9
+
10
+ const { collectBackgroundRanges } = require("../extension");
11
+
12
+ function slices(text, ranges) {
13
+ return ranges.map(({ start, end }) => text.slice(start, end));
14
+ }
15
+
16
+ const source = [
17
+ "$ pair = { leaf left, leaf right };",
18
+ "pick = $pair ?{<$leaf some, ...>=X branch, ...} .branch;",
19
+ "-- ?<ignored tag>",
20
+ "/* $ignored */",
21
+ "$pair pick"
22
+ ].join("\n");
23
+
24
+ const ranges = collectBackgroundRanges(source);
25
+ const type = slices(source, ranges.type);
26
+ const filter = slices(source, ranges.filter);
27
+
28
+ assert.deepStrictEqual(type, [
29
+ "$ pair = { leaf left, leaf right };",
30
+ "$pair",
31
+ "$leaf",
32
+ "$pair"
33
+ ]);
34
+ assert.deepStrictEqual(filter, ["?{<$leaf some, ...>=X branch, ...}"]);
35
+
36
+ const nested = "add = ?{ $nat x, ... } = X <{.x pred x, .y succ y} ? X add, .y> ;";
37
+ const nestedRanges = collectBackgroundRanges(nested);
38
+
39
+ assert.deepStrictEqual(slices(nested, nestedRanges.filter), [
40
+ "?{ $nat x, ... } = X",
41
+ "? X"
42
+ ]);
43
+ assert.deepStrictEqual(slices(nested, nestedRanges.type), ["$nat"]);
44
+ assert.deepStrictEqual(nestedRanges.filter, [
45
+ { start: 6, end: 26 },
46
+ { start: 51, end: 54 }
47
+ ]);
48
+ assert.deepStrictEqual(nestedRanges.type, [{ start: 9, end: 13 }]);
49
+
50
+ console.log("background range scanner tests passed");
@@ -0,0 +1,104 @@
1
+ {
2
+ "$schema": "vscode://schemas/color-theme",
3
+ "name": "k Contrast",
4
+ "type": "dark",
5
+ "colors": {
6
+ "editor.background": "#161B22",
7
+ "editor.foreground": "#C9D1D9",
8
+ "editorLineNumber.foreground": "#6E7681",
9
+ "editorLineNumber.activeForeground": "#C9D1D9",
10
+ "editor.selectionBackground": "#264F78",
11
+ "editor.inactiveSelectionBackground": "#264F7855"
12
+ },
13
+ "tokenColors": [
14
+ {
15
+ "scope": [
16
+ "comment.block.k",
17
+ "comment.line.k"
18
+ ],
19
+ "settings": {
20
+ "foreground": "#8B949E",
21
+ "fontStyle": "italic"
22
+ }
23
+ },
24
+ {
25
+ "scope": "entity.name.type.k",
26
+ "settings": {
27
+ "foreground": "#FF7B72",
28
+ "fontStyle": "bold"
29
+ }
30
+ },
31
+ {
32
+ "scope": "support.type.k",
33
+ "settings": {
34
+ "foreground": "#FFA657"
35
+ }
36
+ },
37
+ {
38
+ "scope": "support.function.identifier.k",
39
+ "settings": {
40
+ "foreground": "#79C0FF"
41
+ }
42
+ },
43
+ {
44
+ "scope": "support.type.canonical.k",
45
+ "settings": {
46
+ "foreground": "#F778BA"
47
+ }
48
+ },
49
+ {
50
+ "scope": "support.function.canonical.k",
51
+ "settings": {
52
+ "foreground": "#FF967D"
53
+ }
54
+ },
55
+ {
56
+ "scope": "entity.name.label.k",
57
+ "settings": {
58
+ "foreground": "#7EE787"
59
+ }
60
+ },
61
+ {
62
+ "scope": "entity.name.tag.k",
63
+ "settings": {
64
+ "foreground": "#F2CC60"
65
+ }
66
+ },
67
+ {
68
+ "scope": "variable.other.pattern.k",
69
+ "settings": {
70
+ "foreground": "#56D4DD"
71
+ }
72
+ },
73
+ {
74
+ "scope": [
75
+ "keyword.operator.assignment.k",
76
+ "keyword.operator.binding.k",
77
+ "keyword.operator.filter.k",
78
+ "keyword.operator.projection.product.k",
79
+ "keyword.operator.projection.union.k",
80
+ "keyword.operator.type.k",
81
+ "keyword.operator.variant.k"
82
+ ],
83
+ "settings": {
84
+ "foreground": "#FFDF5D"
85
+ }
86
+ },
87
+ {
88
+ "scope": "punctuation.definition.canonical.k",
89
+ "settings": {
90
+ "foreground": "#B392F0"
91
+ }
92
+ },
93
+ {
94
+ "scope": [
95
+ "constant.language.any.k",
96
+ "string.quoted.double.k",
97
+ "string.quoted.single.k"
98
+ ],
99
+ "settings": {
100
+ "foreground": "#A5D6FF"
101
+ }
102
+ }
103
+ ]
104
+ }
package/kvm.mjs ADDED
@@ -0,0 +1,523 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import { argv, stdin, exit, stdout } from "node:process";
4
+ import { Product, Variant, composePattern, withPattern } from "./Value.mjs";
5
+ import { exportPatternGraph } from "./codecs/runtime/codec.mjs";
6
+ import { patternToPropertyList } from "./codecs/runtime/pattern-json.mjs";
7
+ import {
8
+ constrainWithPattern,
9
+ intersectPatterns,
10
+ projectionPattern,
11
+ verify,
12
+ run
13
+ } from "./run.mjs";
14
+ import { annotate } from "./index.mjs";
15
+ import { decodeWire, encodeToWire } from "./codecs/runtime/prefix-codec.mjs";
16
+ import { decodeObject, loadLibrary } from "./object.mjs";
17
+ import codes from "./codes.mjs";
18
+ import { isMainEntrypoint } from "./codecs/runtime/cli-entry.mjs";
19
+
20
+ class KVMBuilder {
21
+ constructor(typePatternGraph) {
22
+ this.typePatternGraph = typePatternGraph;
23
+ this.regCount = 0;
24
+ this.instructions = [];
25
+ }
26
+
27
+ nextReg() {
28
+ return `%v${this.regCount++}`;
29
+ }
30
+
31
+ emit(inst) {
32
+ this.instructions.push(inst);
33
+ }
34
+
35
+ getStaticPattern(exp, index) {
36
+ if (!this.typePatternGraph || !exp.patterns) return null;
37
+ const patternId = this.typePatternGraph.find(exp.patterns[index]);
38
+ return patternToPropertyList(exportPatternGraph(this.typePatternGraph, patternId));
39
+ }
40
+ }
41
+
42
+ function compile(exp, inputReg, builder) {
43
+ switch (exp.op) {
44
+ case "identity": {
45
+ const dest = builder.nextReg();
46
+ builder.emit({ op: "id", dest, src: inputReg });
47
+ return dest;
48
+ }
49
+ case "empty": {
50
+ builder.emit({ op: "fail" });
51
+ return builder.nextReg();
52
+ }
53
+ case "filter": {
54
+ const dest = builder.nextReg();
55
+ builder.emit({
56
+ op: "guard_pattern",
57
+ dest,
58
+ src: inputReg,
59
+ pattern: builder.getStaticPattern(exp, 0),
60
+ exp
61
+ });
62
+ return dest;
63
+ }
64
+ case "code": {
65
+ const dest = builder.nextReg();
66
+ builder.emit({
67
+ op: "guard_code",
68
+ dest,
69
+ src: inputReg,
70
+ code: exp.code,
71
+ exp
72
+ });
73
+ return dest;
74
+ }
75
+ case "dot": {
76
+ const dest = builder.nextReg();
77
+ builder.emit({
78
+ op: "project_field",
79
+ dest,
80
+ src: inputReg,
81
+ label: exp.dot,
82
+ pattern: builder.getStaticPattern(exp, 1),
83
+ exp
84
+ });
85
+ return dest;
86
+ }
87
+ case "div": {
88
+ const dest = builder.nextReg();
89
+ builder.emit({
90
+ op: "project_variant",
91
+ dest,
92
+ src: inputReg,
93
+ tag: exp.div,
94
+ pattern: builder.getStaticPattern(exp, 1),
95
+ exp
96
+ });
97
+ return dest;
98
+ }
99
+ case "vid": {
100
+ const dest = builder.nextReg();
101
+ builder.emit({
102
+ op: "make_variant",
103
+ dest,
104
+ tag: exp.vid,
105
+ src: inputReg
106
+ });
107
+ return dest;
108
+ }
109
+ case "ref": {
110
+ const dest = builder.nextReg();
111
+ if (exp.ref.startsWith("_")) {
112
+ builder.emit({
113
+ op: "call_intrinsic",
114
+ dest,
115
+ symbol: exp.ref,
116
+ src: inputReg,
117
+ pattern: builder.getStaticPattern(exp, 0),
118
+ exp
119
+ });
120
+ } else {
121
+ builder.emit({
122
+ op: "call",
123
+ dest,
124
+ func: exp.ref,
125
+ src: inputReg,
126
+ exp
127
+ });
128
+ }
129
+ return dest;
130
+ }
131
+ case "comp": {
132
+ let currentReg = inputReg;
133
+ const compInputPattern = builder.getStaticPattern(exp, 0);
134
+ if (compInputPattern) {
135
+ const guarded = builder.nextReg();
136
+ builder.emit({ op: "guard_pattern", dest: guarded, src: currentReg, pattern: compInputPattern, exp });
137
+ currentReg = guarded;
138
+ }
139
+ for (const subExp of exp.comp) {
140
+ currentReg = compile(subExp, currentReg, builder);
141
+ }
142
+ return currentReg;
143
+ }
144
+ case "product": {
145
+ const dest = builder.nextReg();
146
+ const branches = [];
147
+ for (const { label, exp: fieldExp } of exp.product) {
148
+ const branchBuilder = new KVMBuilder(builder.typePatternGraph);
149
+ const branchInput = "%in";
150
+ const branchOutput = compile(fieldExp, branchInput, branchBuilder);
151
+ branchBuilder.emit({ op: "return", src: branchOutput });
152
+ branches.push({
153
+ label,
154
+ body: branchBuilder.instructions
155
+ });
156
+ }
157
+ builder.emit({
158
+ op: "product",
159
+ dest,
160
+ src: inputReg,
161
+ branches,
162
+ pattern: builder.getStaticPattern(exp, 1),
163
+ exp
164
+ });
165
+ return dest;
166
+ }
167
+ case "union": {
168
+ const dest = builder.nextReg();
169
+ const branches = [];
170
+ for (const branchExp of exp.union) {
171
+ const branchBuilder = new KVMBuilder(builder.typePatternGraph);
172
+ const branchInput = "%in";
173
+ const branchOutput = compile(branchExp, branchInput, branchBuilder);
174
+ branchBuilder.emit({ op: "return", src: branchOutput });
175
+ branches.push({
176
+ body: branchBuilder.instructions
177
+ });
178
+ }
179
+ builder.emit({
180
+ op: "union",
181
+ dest,
182
+ src: inputReg,
183
+ branches,
184
+ exp
185
+ });
186
+ return dest;
187
+ }
188
+ default:
189
+ throw new Error(`Unsupported AST operation: ${exp.op}`);
190
+ }
191
+ }
192
+
193
+ export function lowerToKVM(relDef, name, options = {}) {
194
+ const typePatternGraph = relDef.typePatternGraph || null;
195
+ const builder = new KVMBuilder(typePatternGraph);
196
+ const inputReg = "%in";
197
+
198
+ let currentReg = inputReg;
199
+ const inputPattern = builder.getStaticPattern(relDef.def, 0);
200
+ if (inputPattern) {
201
+ const guarded = builder.nextReg();
202
+ builder.emit({ op: "guard_pattern", dest: guarded, src: currentReg, pattern: inputPattern, exp: relDef.def });
203
+ currentReg = guarded;
204
+ }
205
+
206
+ const bodyOutput = compile(relDef.def, currentReg, builder);
207
+
208
+ let finalReg = bodyOutput;
209
+ const outputPattern = builder.getStaticPattern(relDef.def, 1);
210
+ if (outputPattern) {
211
+ const guarded = builder.nextReg();
212
+ builder.emit({ op: "guard_pattern", dest: guarded, src: finalReg, pattern: outputPattern, exp: relDef.def });
213
+ finalReg = guarded;
214
+ }
215
+
216
+ builder.emit({ op: "return", src: finalReg });
217
+
218
+ return {
219
+ name,
220
+ inputPattern,
221
+ outputPattern,
222
+ isConverged: relDef.typeDerivation?.status === "converged",
223
+ body: builder.instructions
224
+ };
225
+ }
226
+
227
+ function executeBlock(instructions, inputVal, context) {
228
+ const registers = new Map();
229
+ registers.set("%in", inputVal);
230
+
231
+ for (const inst of instructions) {
232
+ const res = executeInstruction(inst, registers, context);
233
+ if (res === undefined) {
234
+ return undefined;
235
+ }
236
+ if (res.type === "return") {
237
+ return res.value;
238
+ }
239
+ }
240
+ return undefined;
241
+ }
242
+
243
+ function executeInstruction(inst, registers, context) {
244
+ const options = context.options || {};
245
+ switch (inst.op) {
246
+ case "id": {
247
+ registers.set(inst.dest, registers.get(inst.src));
248
+ return { type: "continue" };
249
+ }
250
+ case "fail": {
251
+ return undefined;
252
+ }
253
+ case "guard_pattern": {
254
+ const val = registers.get(inst.src);
255
+ if (options.envelopeFree) {
256
+ registers.set(inst.dest, val);
257
+ return { type: "continue" };
258
+ }
259
+ try {
260
+ const constrained = constrainWithPattern(val, inst.pattern, inst.exp);
261
+ registers.set(inst.dest, constrained);
262
+ return { type: "continue" };
263
+ } catch (err) {
264
+ if (err instanceof TypeError) {
265
+ throw err;
266
+ }
267
+ return undefined;
268
+ }
269
+ }
270
+ case "guard_code": {
271
+ const val = registers.get(inst.src);
272
+ if (options.envelopeFree) {
273
+ registers.set(inst.dest, val);
274
+ return { type: "continue" };
275
+ }
276
+ if (verify(context.findCode, inst.code, val)) {
277
+ registers.set(inst.dest, val);
278
+ return { type: "continue" };
279
+ }
280
+ return undefined;
281
+ }
282
+ case "project_field": {
283
+ const val = registers.get(inst.src);
284
+ if (!(val instanceof Product)) return undefined;
285
+ const fieldVal = val.product[inst.label];
286
+ if (fieldVal === undefined) return undefined;
287
+
288
+ if (options.envelopeFree) {
289
+ registers.set(inst.dest, fieldVal);
290
+ } else {
291
+ const pattern = projectionPattern(inst.pattern, val.pattern, inst.label, inst.exp);
292
+ registers.set(inst.dest, withPattern(fieldVal, pattern));
293
+ }
294
+ return { type: "continue" };
295
+ }
296
+ case "project_variant": {
297
+ const val = registers.get(inst.src);
298
+ if (!(val instanceof Variant) || val.tag !== inst.tag) return undefined;
299
+
300
+ if (options.envelopeFree) {
301
+ registers.set(inst.dest, val.value);
302
+ } else {
303
+ const pattern = projectionPattern(inst.pattern, val.pattern, inst.tag, inst.exp);
304
+ registers.set(inst.dest, withPattern(val.value, pattern));
305
+ }
306
+ return { type: "continue" };
307
+ }
308
+ case "make_variant": {
309
+ const val = registers.get(inst.src);
310
+ if (options.envelopeFree) {
311
+ registers.set(inst.dest, new Variant(inst.tag, val));
312
+ } else {
313
+ registers.set(
314
+ inst.dest,
315
+ new Variant(inst.tag, val, composePattern("open-union", [[inst.tag, val.pattern]]))
316
+ );
317
+ }
318
+ return { type: "continue" };
319
+ }
320
+ case "call": {
321
+ const val = registers.get(inst.src);
322
+ const relDef = context.rels[inst.func];
323
+ if (!relDef) {
324
+ throw new Error(`Unknown ref: '${inst.func}'`);
325
+ }
326
+ if (options.requireConverged && relDef.typeDerivation?.status !== "converged") {
327
+ throw new Error(`Cannot run '${inst.func}' without envelopes: type derivation is not converged`);
328
+ }
329
+ if (options.trace) {
330
+ console.log(`[Trace] Calling ${inst.func} with:`, val ? val.toString() : "null");
331
+ }
332
+ if (!relDef._kvmFunc) {
333
+ relDef._kvmFunc = lowerToKVM(relDef, inst.func);
334
+ }
335
+ const res = executeKVM(relDef._kvmFunc, val, context);
336
+ if (options.trace) {
337
+ console.log(`[Trace] Returned from ${inst.func} ->:`, res ? res.toString() : "fail");
338
+ }
339
+ if (res === undefined) return undefined;
340
+ registers.set(inst.dest, res);
341
+ return { type: "continue" };
342
+ }
343
+ case "call_intrinsic": {
344
+ const val = registers.get(inst.src);
345
+ const builtinFunc = run.builtin[inst.symbol];
346
+ if (!builtinFunc) {
347
+ throw new Error(`Unknown builtin: '${inst.symbol}'`);
348
+ }
349
+ if (!options.envelopeFree && inst.pattern) {
350
+ try {
351
+ const constrained = constrainWithPattern(val, inst.pattern, inst.exp);
352
+ const res = builtinFunc(constrained);
353
+ registers.set(inst.dest, res);
354
+ return { type: "continue" };
355
+ } catch (err) {
356
+ throw err;
357
+ }
358
+ } else {
359
+ const res = builtinFunc(val);
360
+ registers.set(inst.dest, res);
361
+ return { type: "continue" };
362
+ }
363
+ }
364
+ case "product": {
365
+ const val = registers.get(inst.src);
366
+ const result = {};
367
+ const patternEntries = [];
368
+ for (const branch of inst.branches) {
369
+ const branchRes = executeBlock(branch.body, val, context);
370
+ if (branchRes === undefined) return undefined;
371
+ result[branch.label] = branchRes;
372
+ if (!options.envelopeFree) {
373
+ patternEntries.push([branch.label, branchRes.pattern]);
374
+ }
375
+ }
376
+ let productValue;
377
+ if (options.envelopeFree) {
378
+ productValue = new Product(result);
379
+ } else {
380
+ const staticOutputPattern = inst.pattern;
381
+ if (staticOutputPattern) {
382
+ productValue = new Product(result, staticOutputPattern);
383
+ } else {
384
+ productValue = new Product(result, composePattern("closed-product", patternEntries));
385
+ }
386
+ }
387
+ registers.set(inst.dest, productValue);
388
+ return { type: "continue" };
389
+ }
390
+ case "union": {
391
+ const val = registers.get(inst.src);
392
+ for (const branch of inst.branches) {
393
+ const branchRes = executeBlock(branch.body, val, context);
394
+ if (branchRes !== undefined) {
395
+ registers.set(inst.dest, branchRes);
396
+ return { type: "continue" };
397
+ }
398
+ }
399
+ return undefined;
400
+ }
401
+ case "return": {
402
+ return { type: "return", value: registers.get(inst.src) };
403
+ }
404
+ default:
405
+ throw new Error(`Unknown instruction op: ${inst.op}`);
406
+ }
407
+ }
408
+
409
+ export function executeKVM(kvmFunc, inputVal, context) {
410
+ const options = context.options || {};
411
+ if (options.requireConverged && !kvmFunc.isConverged) {
412
+ throw new Error(`Cannot run '${kvmFunc.name}' without envelopes: type derivation is not converged`);
413
+ }
414
+
415
+ const result = executeBlock(kvmFunc.body, inputVal, context);
416
+ if (result === undefined) return undefined;
417
+
418
+ if (options.envelopeFree && kvmFunc.isConverged) {
419
+ return withPattern(result, kvmFunc.outputPattern);
420
+ }
421
+ return result;
422
+ }
423
+
424
+ export default {
425
+ lowerToKVM,
426
+ executeKVM
427
+ };
428
+
429
+ function usage() {
430
+ const prog = argv[1] || "kvm.mjs";
431
+ console.error(`Usage: node ${prog} [ options ] ( k-expr | -k file ) [ input-file ]`);
432
+ console.error("Options:");
433
+ console.error(" --lib file Load a .klib dependency before compiling. May be repeated.");
434
+ console.error(" --envelope-free Run the interpreter in envelope-free mode.");
435
+ console.error(" -h, --help Show this help.");
436
+ }
437
+
438
+ async function main() {
439
+ const args = argv.slice(2);
440
+ if (args.includes("-h") || args.includes("--help")) {
441
+ usage();
442
+ return exit(0);
443
+ }
444
+
445
+ let envelopeFree = false;
446
+ const libraries = [];
447
+
448
+ // Parse options
449
+ while (args.length > 0) {
450
+ if (args[0] === "--envelope-free") {
451
+ envelopeFree = true;
452
+ args.shift();
453
+ } else if (args[0] === "--lib") {
454
+ args.shift();
455
+ const libPath = args.shift();
456
+ if (!libPath) throw new Error("--lib requires a file argument");
457
+ const libBuffer = fs.readFileSync(libPath);
458
+ libraries.push(loadLibrary(decodeObject(libBuffer)));
459
+ } else {
460
+ break;
461
+ }
462
+ }
463
+
464
+ let kScriptStr = (function (arg) {
465
+ if (arg == null) {
466
+ throw new Error("Missing script argument");
467
+ }
468
+ if (arg === "-k") {
469
+ const fileArg = args.shift();
470
+ if (!fileArg) throw new Error("-k requires a file argument");
471
+ return fs.readFileSync(fileArg, "utf8");
472
+ } else {
473
+ return arg;
474
+ }
475
+ })(args.shift());
476
+
477
+ const inputStream = (function (arg) {
478
+ if (arg == null) {
479
+ return stdin;
480
+ }
481
+ return fs.createReadStream(arg);
482
+ })(args.shift());
483
+
484
+ const defs = annotate(kScriptStr, { libraries });
485
+ const mainRel = defs.rels.__main__;
486
+ if (!mainRel) {
487
+ throw new Error("No main relation (__main__) defined in script");
488
+ }
489
+
490
+ const kvmFunc = lowerToKVM(mainRel, "__main__");
491
+
492
+ const buffer = [];
493
+ inputStream.on("data", (data) => buffer.push(Buffer.isBuffer(data) ? data : Buffer.from(data)));
494
+ inputStream.on("end", () => {
495
+ try {
496
+ const inputBuffer = Buffer.concat(buffer);
497
+ const { pattern: inputPattern, value } = decodeWire(inputBuffer);
498
+ const context = {
499
+ rels: defs.rels,
500
+ findCode: codes.find,
501
+ options: {
502
+ envelopeFree
503
+ }
504
+ };
505
+ const result = executeKVM(kvmFunc, value, context);
506
+ if (result === undefined) {
507
+ throw new Error("kVM expression evaluated to undefined");
508
+ }
509
+ stdout.write(encodeToWire(result, result.pattern));
510
+ } catch (error) {
511
+ console.error(error.stack || error.message || String(error));
512
+ exit(1);
513
+ }
514
+ });
515
+ }
516
+
517
+ if (isMainEntrypoint(import.meta.url, argv[1])) {
518
+ main().catch((error) => {
519
+ console.error(error.stack || error.message || String(error));
520
+ usage();
521
+ exit(1);
522
+ });
523
+ }
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@fraczak/k",
3
- "version": "6.1.3",
3
+ "version": "6.2.1",
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
  "scripts": {
7
7
  "prepare": "jiwson -m es6 parser.jison -o parser.mjs; jiwson -m es6 valueParser.jison -o valueParser.mjs; ",
8
- "test": "node test.mjs; for f in Code-derivation-tests/*.mjs; do echo $f; node $f; done; node test-fingerprint.mjs; node test-hash-fuzz.mjs; node test-hash-normalization.mjs; node test-k-object.mjs; node test-repl.mjs; node test-ieee-arithmetic.mjs; ./tests.sh",
8
+ "test": "node scripts/run-tests.mjs",
9
9
  "perf:idempotency": "node scripts/benchmark-idempotency.mjs",
10
10
  "deps:graph": "node scripts/generate-dependency-graph.mjs"
11
11
  },
@@ -30,7 +30,8 @@
30
30
  "k-show": "./codecs/show.mjs",
31
31
  "k-unit": "./codecs/unit.mjs",
32
32
  "k-utf16": "./codecs/utf16.mjs",
33
- "k-utf8": "./codecs/utf8.mjs"
33
+ "k-utf8": "./codecs/utf8.mjs",
34
+ "k-vm": "./kvm.mjs"
34
35
  },
35
36
  "devDependencies": {
36
37
  "jiwson": "^0.1.2"