@fraczak/k 5.1.2 → 6.0.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 (115) hide show
  1. package/.codex +0 -0
  2. package/Code-derivation-tests/blowup.mjs +3 -3
  3. package/Code-derivation-tests/bnat.mjs +2 -2
  4. package/Code-derivation-tests/codec-witness-pattern.mjs +50 -0
  5. package/Code-derivation-tests/convergence-strategy.mjs +24 -0
  6. package/Code-derivation-tests/dot.mjs +12 -9
  7. package/Code-derivation-tests/filter-syntax.mjs +21 -0
  8. package/Code-derivation-tests/loop.mjs +8 -2
  9. package/Code-derivation-tests/nat.mjs +1 -1
  10. package/Code-derivation-tests/not-not.mjs +3 -3
  11. package/Code-derivation-tests/pattern-envelope.mjs +68 -0
  12. package/Code-derivation-tests/rlz.mjs +2 -2
  13. package/{BIG_PICTURE.md → DOCS/BIG_PICTURE.md} +103 -50
  14. package/DOCS/REPL.md +191 -0
  15. package/DOCS/a.html +398 -0
  16. package/DOCS/book/01-introduction.md +51 -0
  17. package/DOCS/book/02-syntax-and-values.md +111 -0
  18. package/DOCS/book/03-types-as-finite-automata.md +156 -0
  19. package/DOCS/book/04-partial-functions-and-composition.md +146 -0
  20. package/DOCS/book/05-typing-filters-and-normalization.md +111 -0
  21. package/DOCS/book-combined.html +3798 -0
  22. package/DOCS/book-combined.md +3745 -0
  23. package/DOCS/book-combined.pdf +0 -0
  24. package/DOCS/book-combined.tex +5682 -0
  25. package/DOCS/book.html +65 -0
  26. package/DOCS/book.md +54 -0
  27. package/DOCS/book.pdf +0 -0
  28. package/DOCS/book.tex +150 -0
  29. package/NAT.k~ +452 -0
  30. package/README.md +204 -508
  31. package/TypeGraph.mjs +43 -0
  32. package/TypePatternGraph.mjs +251 -0
  33. package/Value.mjs +192 -0
  34. package/augmentation.mjs +198 -0
  35. package/codecs/BINARY_FORMAT.html +471 -0
  36. package/codecs/BINARY_FORMAT.md +53 -0
  37. package/codecs/POLYMORPHIC_BINARY_FORMAT.html +355 -0
  38. package/codecs/POLYMORPHIC_BINARY_FORMAT.md +303 -0
  39. package/codecs/README.md +215 -0
  40. package/codecs/example-pipeline.mjs +149 -0
  41. package/codecs/ieee.mjs +140 -0
  42. package/codecs/int.mjs +104 -0
  43. package/codecs/json-codec.mjs +215 -0
  44. package/codecs/json.mjs +40 -0
  45. package/codecs/k-parse.mjs +90 -0
  46. package/codecs/k-pattern.mjs +75 -0
  47. package/codecs/k-print.mjs +46 -0
  48. package/codecs/runtime/codec.mjs +768 -0
  49. package/codecs/runtime/ieee-pattern.mjs +30 -0
  50. package/codecs/runtime/pattern-json.mjs +96 -0
  51. package/codecs/runtime/prefix-codec.mjs +425 -0
  52. package/codecs/runtime/show-value.mjs +68 -0
  53. package/codecs/runtime/typeFromValue.mjs +34 -0
  54. package/codecs/runtime/unicode-string.mjs +220 -0
  55. package/codecs/show.mjs +41 -0
  56. package/codecs/string-codec.mjs +80 -0
  57. package/codecs/unit.mjs +51 -0
  58. package/codecs/utf16.mjs +66 -0
  59. package/codecs/utf8.mjs +37 -0
  60. package/codes.mjs +146 -44
  61. package/compiler.mjs +111 -0
  62. package/convergence.mjs +197 -0
  63. package/core.k +197 -0
  64. package/export.mjs +22 -32
  65. package/hash.mjs +29 -31
  66. package/ieee.klib +0 -0
  67. package/index.mjs +41 -15
  68. package/k-vscode/.vscode/launch.json +14 -0
  69. package/k-vscode/README.md +65 -0
  70. package/k-vscode/language-configuration.json +42 -0
  71. package/k-vscode/package-lock.json +4176 -0
  72. package/k-vscode/package.json +57 -0
  73. package/k-vscode/snippets/k.json +92 -0
  74. package/k-vscode/syntaxes/k.tmLanguage.json +243 -0
  75. package/k.mjs +56 -54
  76. package/object.mjs +517 -0
  77. package/objects/README.md +38 -0
  78. package/objects/compile-lib.mjs +42 -0
  79. package/objects/compile.mjs +42 -0
  80. package/objects/decompile.mjs +32 -0
  81. package/package.json +13 -6
  82. package/parser.jison +27 -46
  83. package/parser.mjs +68 -100
  84. package/pretty.mjs +21 -40
  85. package/repl2.mjs +662 -0
  86. package/run.mjs +264 -231
  87. package/symbol-table.mjs +3 -17
  88. package/test-fingerprint.mjs +7 -7
  89. package/test-hash-fuzz.mjs +107 -0
  90. package/test-hash-normalization.mjs +134 -0
  91. package/test-k-object.mjs +74 -0
  92. package/test-repl2.mjs +106 -0
  93. package/test.mjs +45 -70
  94. package/tests.sh +10 -1
  95. package/type_registry/registry.mjs~ +105 -0
  96. package/type_registry/typeParser.jison~ +132 -0
  97. package/typing.mjs +129 -676
  98. package/unification.mjs +157 -0
  99. package/valueIO.mjs +54 -0
  100. package/valueParser.jison +143 -0
  101. package/valueParser.mjs +713 -0
  102. package/Code-derivation-tests/built-in.mjs +0 -19
  103. package/Code-derivation-tests/vector.mjs +0 -19
  104. package/Filters/bug.k +0 -3
  105. package/Filters/composing.k +0 -15
  106. package/Filters/filter.k +0 -9
  107. package/TODO.md +0 -53
  108. package/TYPING.md +0 -365
  109. package/k-repl.cast +0 -1913
  110. package/k.cast +0 -618
  111. package/my-objects.json +0 -6
  112. package/patterns.mjs +0 -543
  113. package/repl.mjs +0 -213
  114. package/test-filters.mjs +0 -45
  115. package/typing-test.mjs +0 -40
package/object.mjs ADDED
@@ -0,0 +1,517 @@
1
+ import { annotate } from "./index.mjs";
2
+ import run from "./run.mjs";
3
+ import codes from "./codes.mjs";
4
+ import { TypePatternGraph } from "./TypePatternGraph.mjs";
5
+ import { patterns2filters, prettyRel } from "./pretty.mjs";
6
+
7
+ const MAGIC = Buffer.from([0x4b, 0x4f, 0x42, 0x4a, 0x00, 0x01, 0x0a]);
8
+ const LIB_MAGIC = Buffer.from([0x4b, 0x4c, 0x49, 0x42, 0x00, 0x01, 0x0a]);
9
+
10
+ function serializeTypePatternGraph(typePatternGraph) {
11
+ return {
12
+ patterns: {
13
+ nodes: typePatternGraph.patterns.nodes,
14
+ parent: typePatternGraph.patterns.parent.map((parent) => parent ?? null)
15
+ },
16
+ edges: typePatternGraph.edges,
17
+ codeId: typePatternGraph.codeId
18
+ };
19
+ }
20
+
21
+ function hydrateTypePatternGraph(serialized) {
22
+ const graph = new TypePatternGraph(codes.register, codes.find);
23
+ graph.patterns.nodes = serialized.patterns.nodes;
24
+ graph.patterns.parent = serialized.patterns.parent.map((parent) => parent ?? undefined);
25
+ graph.edges = serialized.edges;
26
+ graph.codeId = serialized.codeId;
27
+ return graph;
28
+ }
29
+
30
+ function serializeRelation(rel) {
31
+ return {
32
+ ...rel,
33
+ typePatternGraph: serializeTypePatternGraph(rel.typePatternGraph)
34
+ };
35
+ }
36
+
37
+ function hydrateRelation(rel) {
38
+ return {
39
+ ...rel,
40
+ typePatternGraph: hydrateTypePatternGraph(rel.typePatternGraph)
41
+ };
42
+ }
43
+
44
+ function serializeAnnotated(annotated) {
45
+ return {
46
+ rels: Object.fromEntries(
47
+ Object.entries(annotated.rels).map(([name, rel]) => [name, serializeRelation(rel)])
48
+ ),
49
+ representatives: annotated.representatives,
50
+ relAlias: annotated.relAlias,
51
+ compileStats: annotated.compileStats
52
+ };
53
+ }
54
+
55
+ function hydrateAnnotated(serialized) {
56
+ return {
57
+ ...serialized,
58
+ rels: Object.fromEntries(
59
+ Object.entries(serialized.rels).map(([name, rel]) => [name, hydrateRelation(rel)])
60
+ )
61
+ };
62
+ }
63
+
64
+ function buildMeta(annotated, source) {
65
+ const meta = {};
66
+ const relAlias = annotated.relAlias || {};
67
+ const now = new Date().toISOString();
68
+ // Relation metadata: source name → canonical hash
69
+ for (const [name, hash] of Object.entries(relAlias)) {
70
+ if (name === "__main__") continue;
71
+ if (!meta[hash]) meta[hash] = { origins: [] };
72
+ meta[hash].origins.push({ source, name, compiledAt: now });
73
+ }
74
+ return meta;
75
+ }
76
+
77
+ function collectReachable(mainName, rels, allCodes) {
78
+ const reachableRels = new Set();
79
+ const reachableCodes = new Set();
80
+
81
+ function walkExp(exp) {
82
+ if (!exp) return;
83
+ switch (exp.op) {
84
+ case "ref":
85
+ if (exp.ref in rels && !reachableRels.has(exp.ref)) {
86
+ reachableRels.add(exp.ref);
87
+ walkExp(rels[exp.ref].def);
88
+ }
89
+ break;
90
+ case "code":
91
+ walkCode(exp.code);
92
+ break;
93
+ case "filter":
94
+ walkFilter(exp.filter);
95
+ break;
96
+ case "comp":
97
+ exp.comp.forEach(walkExp);
98
+ break;
99
+ case "union":
100
+ exp.union.forEach(walkExp);
101
+ break;
102
+ case "product":
103
+ exp.product.forEach(({ exp: e }) => walkExp(e));
104
+ break;
105
+ }
106
+ }
107
+
108
+ function walkFilter(filter) {
109
+ if (!filter) return;
110
+ if (filter.type === "code") walkCode(filter.code);
111
+ if (filter.fields) Object.values(filter.fields).forEach(walkFilter);
112
+ }
113
+
114
+ function walkCode(hash) {
115
+ if (!hash || reachableCodes.has(hash)) return;
116
+ if (!(hash in allCodes)) return;
117
+ reachableCodes.add(hash);
118
+ const code = allCodes[hash];
119
+ const fields = code[code.code];
120
+ if (fields) Object.values(fields).forEach(walkCode);
121
+ }
122
+
123
+ // Walk from main
124
+ reachableRels.add(mainName);
125
+ walkExp(rels[mainName].def);
126
+
127
+ // Also collect codes referenced in typePatternGraphs of reachable rels
128
+ for (const relName of reachableRels) {
129
+ const rel = rels[relName];
130
+ if (rel.typePatternGraph) {
131
+ const codeId = rel.typePatternGraph.codeId || (rel.typePatternGraph.codeId);
132
+ if (codeId) Object.values(codeId).forEach(walkCode);
133
+ }
134
+ }
135
+
136
+ return { reachableRels, reachableCodes };
137
+ }
138
+
139
+ function compileObject(script, options = {}) {
140
+ const annotated = annotate(script, options);
141
+ const allCodes = codes.dump();
142
+ const serialized = serializeAnnotated(annotated);
143
+ const meta = buildMeta(annotated, options.source || null);
144
+
145
+ // Prune to reachable from main
146
+ const { reachableRels, reachableCodes } = collectReachable("__main__", serialized.rels, allCodes);
147
+ const prunedCodes = Object.fromEntries(
148
+ Object.entries(allCodes).filter(([h]) => reachableCodes.has(h))
149
+ );
150
+ const prunedRels = Object.fromEntries(
151
+ Object.entries(serialized.rels).filter(([name]) => reachableRels.has(name))
152
+ );
153
+ const prunedMeta = Object.fromEntries(
154
+ Object.entries(meta).filter(([h]) => reachableRels.has(h) || reachableCodes.has(h))
155
+ );
156
+
157
+ return {
158
+ format: "k-object",
159
+ version: 2,
160
+ codes: prunedCodes,
161
+ rels: prunedRels,
162
+ relAlias: serialized.relAlias,
163
+ compileStats: serialized.compileStats,
164
+ meta: prunedMeta,
165
+ main: "__main__"
166
+ };
167
+ }
168
+
169
+ function rewriteRefsToCanonical(exp, relAlias) {
170
+ if (!exp) return exp;
171
+ const rewritten = { ...exp };
172
+ switch (exp.op) {
173
+ case "ref":
174
+ if (relAlias[exp.ref]) rewritten.ref = relAlias[exp.ref];
175
+ break;
176
+ case "comp":
177
+ rewritten.comp = exp.comp.map(e => rewriteRefsToCanonical(e, relAlias));
178
+ break;
179
+ case "union":
180
+ rewritten.union = exp.union.map(e => rewriteRefsToCanonical(e, relAlias));
181
+ break;
182
+ case "product":
183
+ rewritten.product = exp.product.map(({ label, exp: e }) => ({
184
+ label, exp: rewriteRefsToCanonical(e, relAlias)
185
+ }));
186
+ break;
187
+ }
188
+ return rewritten;
189
+ }
190
+
191
+ function compileLibrary(script, options = {}) {
192
+ const annotated = annotate(script, options);
193
+ const serialized = serializeAnnotated(annotated);
194
+ const meta = buildMeta(annotated, options.source || null);
195
+ const relAlias = serialized.relAlias || {};
196
+
197
+ // Key rels by canonical hash, rewrite internal refs to canonical hashes
198
+ const libRels = {};
199
+ for (const [name, rel] of Object.entries(serialized.rels)) {
200
+ if (name === "__main__") continue;
201
+ const canonicalName = relAlias[name] || name;
202
+ const { varRefs, ...relWithoutVarRefs } = rel;
203
+ libRels[canonicalName] = {
204
+ ...relWithoutVarRefs,
205
+ def: rewriteRefsToCanonical(rel.def, relAlias)
206
+ };
207
+ }
208
+
209
+ return {
210
+ format: "k-object",
211
+ version: 2,
212
+ codes: codes.dump(),
213
+ rels: libRels,
214
+ relAlias: serialized.relAlias,
215
+ compileStats: serialized.compileStats,
216
+ meta,
217
+ main: null
218
+ };
219
+ }
220
+
221
+ function hydrateObject(object) {
222
+ if (object?.format !== "k-object") {
223
+ throw new Error("Unsupported k object file");
224
+ }
225
+ // v1 compat: defs wrapper
226
+ if (object.version === 1) {
227
+ codes.load(object.codes);
228
+ return {
229
+ ...object,
230
+ defs: hydrateAnnotated(object.defs)
231
+ };
232
+ }
233
+ // v2: flat rels
234
+ codes.load(object.codes);
235
+ const hydratedRels = Object.fromEntries(
236
+ Object.entries(object.rels).map(([name, rel]) => [name, hydrateRelation(rel)])
237
+ );
238
+ return { ...object, rels: hydratedRels };
239
+ }
240
+
241
+ function loadLibrary(object) {
242
+ const hydrated = isHydratedObject(object) ? object : hydrateObject(object);
243
+ if (hydrated.main != null) {
244
+ throw new Error("Expected a library (main: null), got an executable");
245
+ }
246
+ return hydrated;
247
+ }
248
+
249
+ function isHydratedObject(object) {
250
+ // v2 format
251
+ if (object?.rels) {
252
+ const firstRel = Object.values(object.rels)[0];
253
+ return firstRel?.typePatternGraph instanceof TypePatternGraph;
254
+ }
255
+ // v1 format
256
+ return object?.defs?.rels?.[object.main]?.typePatternGraph instanceof TypePatternGraph;
257
+ }
258
+
259
+ function encodeObject(object) {
260
+ const magic = object.main == null ? LIB_MAGIC : MAGIC;
261
+ const payload = Buffer.from(JSON.stringify(object), "utf8");
262
+ if (payload.length > 0xffffffff) {
263
+ throw new Error("k object payload is too large");
264
+ }
265
+
266
+ const header = Buffer.alloc(magic.length + 4);
267
+ magic.copy(header, 0);
268
+ header.writeUInt32BE(payload.length, magic.length);
269
+ return Buffer.concat([header, payload]);
270
+ }
271
+
272
+ function decodeObject(buffer) {
273
+ if (!Buffer.isBuffer(buffer)) {
274
+ throw new Error("k object input must be a Buffer");
275
+ }
276
+ const isObj = buffer.length >= MAGIC.length && buffer.subarray(0, MAGIC.length).equals(MAGIC);
277
+ const isLib = buffer.length >= LIB_MAGIC.length && buffer.subarray(0, LIB_MAGIC.length).equals(LIB_MAGIC);
278
+ if (!isObj && !isLib) {
279
+ throw new Error("Invalid k object file header");
280
+ }
281
+
282
+ const magic = isLib ? LIB_MAGIC : MAGIC;
283
+ const length = buffer.readUInt32BE(magic.length);
284
+ const payloadStart = magic.length + 4;
285
+ const payloadEnd = payloadStart + length;
286
+ if (payloadEnd !== buffer.length) {
287
+ throw new Error("Invalid k object file length");
288
+ }
289
+
290
+ return hydrateObject(JSON.parse(buffer.subarray(payloadStart, payloadEnd).toString("utf8")));
291
+ }
292
+
293
+ function encodeLibrary(object) {
294
+ return encodeObject(object);
295
+ }
296
+
297
+ function decodeLibrary(buffer) {
298
+ const object = decodeObject(buffer);
299
+ if (object.main != null) {
300
+ throw new Error("Expected a library (main: null), got an executable");
301
+ }
302
+ return object;
303
+ }
304
+
305
+ function compileObjectBuffer(script, options = {}) {
306
+ return encodeObject(compileObject(script, options));
307
+ }
308
+
309
+ function compileLibraryBuffer(script, options = {}) {
310
+ return encodeObject(compileLibrary(script, options));
311
+ }
312
+
313
+ function getRels(hydrated) {
314
+ // v2: flat rels; v1: defs.rels
315
+ return hydrated.rels || hydrated.defs?.rels;
316
+ }
317
+
318
+ function runObject(object, value) {
319
+ const hydrated = isHydratedObject(object) ? object : hydrateObject(object);
320
+ const rels = getRels(hydrated);
321
+ run.defs = hydrated.defs || { rels };
322
+ const mainRel = rels[hydrated.main];
323
+ return run(codes.find, mainRel.def, value, mainRel.typePatternGraph);
324
+ }
325
+
326
+ function objectToFunction(object) {
327
+ const hydrated = isHydratedObject(object) ? object : hydrateObject(object);
328
+ return (value) => runObject(hydrated, value);
329
+ }
330
+
331
+ function hashAlias(hash) {
332
+ return hash.startsWith("@") ? hash.slice(1) : hash;
333
+ }
334
+
335
+ function shortestUniqueAliases(hashes, minimumLength = 4) {
336
+ const sorted = [...new Set(hashes)].sort();
337
+ const aliases = {};
338
+
339
+ for (const hash of sorted) {
340
+ const base = hashAlias(hash);
341
+ let length = Math.min(minimumLength, base.length);
342
+ while (
343
+ sorted.some((other) =>
344
+ other !== hash && hashAlias(other).startsWith(base.slice(0, length))
345
+ )
346
+ ) {
347
+ length += 1;
348
+ if (length > base.length) {
349
+ throw new Error(`Cannot derive unique prefix alias for ${hash}`);
350
+ }
351
+ }
352
+ aliases[hash] = base.slice(0, length);
353
+ }
354
+
355
+ return aliases;
356
+ }
357
+
358
+ function rewriteCodesInFilter(filter, aliases) {
359
+ const rewritten = { ...filter };
360
+ if (rewritten.type === "code" && aliases[rewritten.code]) {
361
+ rewritten.code = aliases[rewritten.code];
362
+ }
363
+ if (rewritten.fields) {
364
+ rewritten.fields = Object.fromEntries(
365
+ Object.entries(rewritten.fields).map(([label, child]) => [label, rewriteCodesInFilter(child, aliases)])
366
+ );
367
+ }
368
+ return rewritten;
369
+ }
370
+
371
+ function rewriteRefsInExp(exp, aliases, relAliases) {
372
+ const rewritten = { ...exp };
373
+ switch (rewritten.op) {
374
+ case "filter":
375
+ rewritten.filter = rewriteCodesInFilter(rewritten.filter, aliases);
376
+ break;
377
+ case "code":
378
+ if (aliases[rewritten.code]) rewritten.code = aliases[rewritten.code];
379
+ break;
380
+ case "ref":
381
+ if (relAliases[rewritten.ref]) rewritten.ref = aliases[relAliases[rewritten.ref]] || relAliases[rewritten.ref];
382
+ else if (aliases[rewritten.ref]) rewritten.ref = aliases[rewritten.ref];
383
+ break;
384
+ case "comp":
385
+ rewritten.comp = rewritten.comp.map((child) => rewriteRefsInExp(child, aliases, relAliases));
386
+ break;
387
+ case "union":
388
+ rewritten.union = rewritten.union.map((child) => rewriteRefsInExp(child, aliases, relAliases));
389
+ break;
390
+ case "product":
391
+ rewritten.product = rewritten.product.map(({ label, exp: child }) => ({
392
+ label,
393
+ exp: rewriteRefsInExp(child, aliases, relAliases)
394
+ }));
395
+ break;
396
+ }
397
+ return rewritten;
398
+ }
399
+
400
+ function codeToSource(code, aliases) {
401
+ const fields = code[code.code];
402
+ const body = Object.keys(fields)
403
+ .sort()
404
+ .map((label) => {
405
+ return `${aliases[fields[label]] || fields[label]} ${JSON.stringify(label)}`;
406
+ })
407
+ .join(", ");
408
+ return code.code === "product" ? `{${body}}` : `< ${body} >`;
409
+ }
410
+
411
+ function boundaryFilterSource(typePatternGraph, patternId, aliases) {
412
+ const [filter] = patterns2filters(typePatternGraph, patternId);
413
+ return prettyRel({ op: "filter", filter: rewriteCodesInFilter(filter, aliases) });
414
+ }
415
+
416
+ function decompileObject(object) {
417
+ const hydrated = isHydratedObject(object) ? object : hydrateObject(object);
418
+ const rels = getRels(hydrated);
419
+ const relAliases = hydrated.defs?.relAlias || hydrated.relAlias || {};
420
+ const aliases = shortestUniqueAliases([
421
+ ...Object.keys(hydrated.codes),
422
+ ...Object.values(relAliases)
423
+ ]);
424
+
425
+ const codeDefs = Object.keys(hydrated.codes)
426
+ .sort()
427
+ .map((name) => `$ ${aliases[name]} = ${codeToSource(hydrated.codes[name], aliases)};`);
428
+ const emittedRelAliases = new Set();
429
+ const relDefForName = (name) => {
430
+ const rel = rels[name];
431
+ if (!rel) return null;
432
+ const relName = relAliases[name] || name;
433
+ if (emittedRelAliases.has(relName)) return null;
434
+ emittedRelAliases.add(relName);
435
+ return `${aliases[relName] || relName} = ${prettyRel(rewriteRefsInExp(rel.def, aliases, relAliases))};`;
436
+ };
437
+ const compileStats = hydrated.defs?.compileStats || hydrated.compileStats;
438
+ const sccs = compileStats?.sccs || [];
439
+ const relGroups = sccs.map(({ members }) =>
440
+ members.map(relDefForName).filter((line) => line != null)
441
+ ).filter((group) => group.length > 0);
442
+ const missingRelGroup = Object.keys(rels)
443
+ .filter((name) => !sccs.some(({ members }) => members.includes(name)))
444
+ .map(relDefForName)
445
+ .filter((line) => line != null);
446
+ if (missingRelGroup.length > 0) relGroups.push(missingRelGroup);
447
+ const relDefs = relGroups.flatMap((group, index) =>
448
+ index === 0 ? group : ["", ...group]
449
+ );
450
+
451
+ if (hydrated.main == null) {
452
+ // Library: no main section
453
+ return [
454
+ "----- codes -----",
455
+ ...codeDefs,
456
+ "----- rels -----",
457
+ ...relDefs,
458
+ ""
459
+ ].join("\n");
460
+ }
461
+
462
+ const mainRel = relAliases[hydrated.main] || hydrated.main;
463
+ const mainRelDef = rels[hydrated.main];
464
+ const main = [
465
+ boundaryFilterSource(mainRelDef.typePatternGraph, mainRelDef.def.patterns[0], aliases),
466
+ aliases[mainRel] || mainRel,
467
+ boundaryFilterSource(mainRelDef.typePatternGraph, mainRelDef.def.patterns[1], aliases)
468
+ ].join(" ");
469
+
470
+ return [
471
+ "----- codes -----",
472
+ ...codeDefs,
473
+ "----- rels -----",
474
+ ...relDefs,
475
+ "----- main -----",
476
+ main,
477
+ ""
478
+ ].join("\n");
479
+ }
480
+
481
+ function decompileObjectBuffer(buffer) {
482
+ return decompileObject(decodeObject(buffer));
483
+ }
484
+
485
+ export {
486
+ compileObject,
487
+ compileObjectBuffer,
488
+ compileLibrary,
489
+ compileLibraryBuffer,
490
+ encodeObject,
491
+ encodeLibrary,
492
+ decodeObject,
493
+ decodeLibrary,
494
+ hydrateObject,
495
+ loadLibrary,
496
+ runObject,
497
+ objectToFunction,
498
+ decompileObject,
499
+ decompileObjectBuffer
500
+ };
501
+
502
+ export default {
503
+ compileObject,
504
+ compileObjectBuffer,
505
+ compileLibrary,
506
+ compileLibraryBuffer,
507
+ encodeObject,
508
+ encodeLibrary,
509
+ decodeObject,
510
+ decodeLibrary,
511
+ hydrateObject,
512
+ loadLibrary,
513
+ runObject,
514
+ objectToFunction,
515
+ decompileObject,
516
+ decompileObjectBuffer
517
+ };
@@ -0,0 +1,38 @@
1
+ # objects/
2
+
3
+ CLI tools for compiling and inspecting k object files (`.ko`) and library files (`.klib`).
4
+
5
+ ## Tools
6
+
7
+ ### compile.mjs
8
+
9
+ Compiles a `.k` source file into an executable object file (`.ko`).
10
+ The output contains only the codes and relations reachable from `main`.
11
+
12
+ ```bash
13
+ ./objects/compile.mjs [--lib lib-file]... [k-file [object-file]]
14
+ ```
15
+
16
+ ### compile-lib.mjs
17
+
18
+ Compiles a `.k` source file into a library file (`.klib`).
19
+ The output contains all codes and relations defined in the source (no main entry point).
20
+ Use `--lib` to build on top of existing libraries.
21
+
22
+ ```bash
23
+ ./objects/compile-lib.mjs [--lib lib-file]... [k-file [lib-file]]
24
+ ```
25
+
26
+ ### decompile.mjs
27
+
28
+ Decompiles a `.ko` or `.klib` back into human-readable k source.
29
+
30
+ ```bash
31
+ ./objects/decompile.mjs [object-file [k-file]]
32
+ ```
33
+
34
+ ## Further reading
35
+
36
+ - [DOCS/OBJECT_FILE_AND_PATTERN.md](../DOCS/OBJECT_FILE_AND_PATTERN.md) — object file format and pattern encoding
37
+ - [DOCS/TYPE_DERIVATION.md](../DOCS/TYPE_DERIVATION.md) — type derivation (what compilation skips when loading a `.ko`/`.klib`)
38
+ - [DOCS/CONVERGENCE.md](../DOCS/CONVERGENCE.md) — convergence strategies for type inference
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import { argv, exit, stdin, stdout } from "node:process";
5
+ import { compileLibraryBuffer, decodeObject, loadLibrary } from "../object.mjs";
6
+
7
+ function usage() {
8
+ console.error(`Usage: ${argv[1]} [ --lib lib-file ]... [ k-file [ lib-file ] ]`);
9
+ }
10
+
11
+ async function readStdinText() {
12
+ const chunks = [];
13
+ for await (const chunk of stdin) {
14
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
15
+ }
16
+ return Buffer.concat(chunks).toString("utf8");
17
+ }
18
+
19
+ try {
20
+ const args = argv.slice(2);
21
+ const libraries = [];
22
+ while (args.length > 0 && args[0] === "--lib") {
23
+ args.shift();
24
+ const libPath = args.shift();
25
+ if (!libPath) throw new Error("--lib requires a file argument");
26
+ libraries.push(loadLibrary(decodeObject(fs.readFileSync(libPath))));
27
+ }
28
+
29
+ const sourcePath = args.shift();
30
+ const outputPath = args.shift();
31
+ const source = sourcePath == null ? await readStdinText() : fs.readFileSync(sourcePath, "utf8");
32
+ const objectBuffer = compileLibraryBuffer(source, { source: sourcePath || "<stdin>", libraries });
33
+ if (outputPath == null) {
34
+ stdout.write(objectBuffer);
35
+ } else {
36
+ fs.writeFileSync(outputPath, objectBuffer);
37
+ }
38
+ } catch (error) {
39
+ console.error(error);
40
+ usage();
41
+ exit(1);
42
+ }
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import { argv, exit, stdin, stdout } from "node:process";
5
+ import { compileObjectBuffer, decodeObject, loadLibrary } from "../object.mjs";
6
+
7
+ function usage() {
8
+ console.error(`Usage: ${argv[1]} [ --lib lib-file ]... [ k-file [ object-file ] ]`);
9
+ }
10
+
11
+ async function readStdinText() {
12
+ const chunks = [];
13
+ for await (const chunk of stdin) {
14
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
15
+ }
16
+ return Buffer.concat(chunks).toString("utf8");
17
+ }
18
+
19
+ try {
20
+ const args = argv.slice(2);
21
+ const libraries = [];
22
+ while (args.length > 0 && args[0] === "--lib") {
23
+ args.shift();
24
+ const libPath = args.shift();
25
+ if (!libPath) throw new Error("--lib requires a file argument");
26
+ libraries.push(loadLibrary(decodeObject(fs.readFileSync(libPath))));
27
+ }
28
+
29
+ const sourcePath = args.shift();
30
+ const outputPath = args.shift();
31
+ const source = sourcePath == null ? await readStdinText() : fs.readFileSync(sourcePath, "utf8");
32
+ const objectBuffer = compileObjectBuffer(source, { source: sourcePath || "<stdin>", libraries });
33
+ if (outputPath == null) {
34
+ stdout.write(objectBuffer);
35
+ } else {
36
+ fs.writeFileSync(outputPath, objectBuffer);
37
+ }
38
+ } catch (error) {
39
+ console.error(error);
40
+ usage();
41
+ exit(1);
42
+ }
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import { argv, exit, stdin, stdout } from "node:process";
5
+ import { decompileObjectBuffer } from "../object.mjs";
6
+
7
+ function usage() {
8
+ console.error(`Usage: ${argv[1]} [ object-file [ k-file ] ]`);
9
+ }
10
+
11
+ async function readStdinBuffer() {
12
+ const chunks = [];
13
+ for await (const chunk of stdin) {
14
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
15
+ }
16
+ return Buffer.concat(chunks);
17
+ }
18
+
19
+ try {
20
+ const [, , objectPath, outputPath] = argv;
21
+ const objectBuffer = objectPath == null ? await readStdinBuffer() : fs.readFileSync(objectPath);
22
+ const source = decompileObjectBuffer(objectBuffer);
23
+ if (outputPath == null) {
24
+ stdout.write(source);
25
+ } else {
26
+ fs.writeFileSync(outputPath, source);
27
+ }
28
+ } catch (error) {
29
+ console.error(error);
30
+ usage();
31
+ exit(1);
32
+ }
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@fraczak/k",
3
- "version": "5.1.2",
4
- "description": "k-language for JSON-like data transformation",
3
+ "version": "6.0.1",
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
- "prepare": "jiwson -m es6 parser.jison -o parser.mjs",
8
- "test": "node test.mjs; for f in Code-derivation-tests/*.mjs; do echo $f; node $f; done; node test-fingerprint.mjs; ./tests.sh"
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-repl2.mjs; ./tests.sh",
9
+ "deps:graph": "node scripts/generate-dependency-graph.mjs"
9
10
  },
10
11
  "repository": {
11
12
  "type": "git",
@@ -15,9 +16,15 @@
15
16
  "license": "ISC",
16
17
  "bin": {
17
18
  "k": "./k.mjs",
18
- "k-repl": "./repl.mjs"
19
+ "k-compile-object": "./objects/compile.mjs",
20
+ "k-decompile-object": "./objects/decompile.mjs",
21
+ "k-parse": "./codecs/k-parse.mjs",
22
+ "k-pattern": "./codecs/k-pattern.mjs",
23
+ "k-print": "./codecs/k-print.mjs",
24
+ "k-repl": "./repl2.mjs",
25
+ "k-repl2": "./repl2.mjs"
19
26
  },
20
27
  "devDependencies": {
21
- "jiwson": "^0.1.1"
28
+ "jiwson": "^0.1.2"
22
29
  }
23
30
  }