@fraczak/k 6.0.2 → 6.0.4
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.
- package/DOCS/KIR_SPECIALIZATION_DESIGN.md +458 -0
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +133 -43
- package/DOCS/REPL.md +10 -7
- package/README.md +16 -6
- package/UU/ta.k +1 -0
- package/UU/ta.k~ +0 -0
- package/UU/tb.k +0 -0
- package/UU/tc.k +0 -0
- package/codecs/README.md +4 -0
- package/core.json +1 -0
- package/core.klib +1 -0
- package/core.klib~ +0 -0
- package/export.mjs +1 -1
- package/ieee.klib +0 -0
- package/index.mjs +1 -1
- package/kkk.k +197 -0
- package/kkk.klib +0 -0
- package/kkk.klib~ +0 -0
- package/object.mjs +452 -57
- package/objects/README.md +28 -1
- package/objects/compile-lib.mjs +27 -2
- package/objects/compile.mjs +27 -2
- package/objects/decompile.mjs +25 -2
- package/objects/extract-aliases.mjs +59 -0
- package/p.json +5475 -0
- package/package.json +2 -1
- package/repl2.mjs +106 -38
- package/run.mjs +172 -2
- package/test-k-object.mjs +129 -2
- package/test-repl2.mjs +10 -0
package/object.mjs
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { annotate } from "./index.mjs";
|
|
2
|
-
import run from "./run.mjs";
|
|
2
|
+
import run, { run_rel, run_converged } from "./run.mjs";
|
|
3
3
|
import codes from "./codes.mjs";
|
|
4
4
|
import { TypePatternGraph } from "./TypePatternGraph.mjs";
|
|
5
5
|
import { patterns2filters, prettyRel } from "./pretty.mjs";
|
|
6
6
|
|
|
7
|
-
const
|
|
8
|
-
const LIB_MAGIC = Buffer.from([0x4b, 0x4c, 0x49, 0x42, 0x00, 0x01, 0x0a]);
|
|
7
|
+
const OBJECT_MAGIC = Buffer.from("KOBJ\n");
|
|
9
8
|
|
|
10
9
|
function serializeTypePatternGraph(typePatternGraph) {
|
|
11
10
|
return {
|
|
@@ -27,9 +26,11 @@ function hydrateTypePatternGraph(serialized) {
|
|
|
27
26
|
return graph;
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
function serializeRelation(rel) {
|
|
29
|
+
function serializeRelation(rel, typeDerivation = rel.typeDerivation) {
|
|
30
|
+
const def = stripDebugFieldsFromExp(stripRelationBoundaryFilters(rel.def, rel.typePatternGraph));
|
|
31
31
|
return {
|
|
32
|
-
|
|
32
|
+
def,
|
|
33
|
+
...(typeDerivation ? { typeDerivation } : {}),
|
|
33
34
|
typePatternGraph: serializeTypePatternGraph(rel.typePatternGraph)
|
|
34
35
|
};
|
|
35
36
|
}
|
|
@@ -42,9 +43,13 @@ function hydrateRelation(rel) {
|
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
function serializeAnnotated(annotated) {
|
|
46
|
+
const typeDerivations = buildRelTypeDerivations(annotated.rels, annotated.compileStats);
|
|
45
47
|
return {
|
|
46
48
|
rels: Object.fromEntries(
|
|
47
|
-
Object.entries(annotated.rels).map(([name, rel]) => [
|
|
49
|
+
Object.entries(annotated.rels).map(([name, rel]) => [
|
|
50
|
+
name,
|
|
51
|
+
serializeRelation(rel, typeDerivations[name])
|
|
52
|
+
])
|
|
48
53
|
),
|
|
49
54
|
representatives: annotated.representatives,
|
|
50
55
|
relAlias: annotated.relAlias,
|
|
@@ -52,28 +57,290 @@ function serializeAnnotated(annotated) {
|
|
|
52
57
|
};
|
|
53
58
|
}
|
|
54
59
|
|
|
55
|
-
|
|
60
|
+
const NAME_RE = /^[a-zA-Z0-9_+-][a-zA-Z0-9_?!+-]*$/;
|
|
61
|
+
|
|
62
|
+
function isSourceName(name) {
|
|
63
|
+
return NAME_RE.test(name) && !name.startsWith("@") && !name.startsWith(":");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function addOrigin(meta, hash, type, origin) {
|
|
67
|
+
if (!hash) return;
|
|
68
|
+
if (!meta[hash]) {
|
|
69
|
+
meta[hash] = { type, origins: [] };
|
|
70
|
+
} else if (meta[hash].type == null) {
|
|
71
|
+
meta[hash].type = type;
|
|
72
|
+
} else if (meta[hash].type !== type) {
|
|
73
|
+
throw new Error(`Metadata type conflict for ${hash}: ${meta[hash].type} vs ${type}`);
|
|
74
|
+
}
|
|
75
|
+
if (meta[hash].origins.some((existing) =>
|
|
76
|
+
existing.source === origin.source &&
|
|
77
|
+
existing.name === origin.name &&
|
|
78
|
+
existing.compiledAt === origin.compiledAt
|
|
79
|
+
)) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
meta[hash].origins.push(origin);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const TYPE_DERIVATION_STATUSES = new Set(["converged", "not-converged", "unknown"]);
|
|
86
|
+
|
|
87
|
+
function validTypeDerivationStatus(status) {
|
|
88
|
+
return TYPE_DERIVATION_STATUSES.has(status) ? status : "unknown";
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function compileStatsByRelName(compileStats = {}) {
|
|
92
|
+
const byName = {};
|
|
93
|
+
for (const scc of compileStats.sccs || []) {
|
|
94
|
+
for (const member of scc.members || []) {
|
|
95
|
+
byName[member] = scc;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return byName;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function samePatternId(typePatternGraph, left, right) {
|
|
102
|
+
return typePatternGraph.find(left) === typePatternGraph.find(right);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function isBoundaryFilter(exp, typePatternGraph, patternId) {
|
|
106
|
+
return exp?.op === "filter" &&
|
|
107
|
+
exp.patterns?.length === 2 &&
|
|
108
|
+
samePatternId(typePatternGraph, exp.patterns[0], patternId) &&
|
|
109
|
+
samePatternId(typePatternGraph, exp.patterns[1], patternId);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function stripRelationBoundaryFilters(exp, typePatternGraph = null) {
|
|
113
|
+
if (!exp) return exp;
|
|
114
|
+
if (typePatternGraph == null) {
|
|
115
|
+
return exp;
|
|
116
|
+
}
|
|
117
|
+
const [inputPattern, outputPattern] = exp.patterns || [];
|
|
118
|
+
if (inputPattern == null || outputPattern == null) return exp;
|
|
119
|
+
|
|
120
|
+
if (isBoundaryFilter(exp, typePatternGraph, inputPattern) && samePatternId(typePatternGraph, inputPattern, outputPattern)) {
|
|
121
|
+
return {
|
|
122
|
+
op: "identity",
|
|
123
|
+
patterns: [...exp.patterns],
|
|
124
|
+
...(exp.start ? { start: exp.start } : {}),
|
|
125
|
+
...(exp.end ? { end: exp.end } : {})
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (exp.op !== "comp") return exp;
|
|
130
|
+
let parts = exp.comp || [];
|
|
131
|
+
if (parts.length > 0 && isBoundaryFilter(parts[0], typePatternGraph, inputPattern)) {
|
|
132
|
+
parts = parts.slice(1);
|
|
133
|
+
}
|
|
134
|
+
if (parts.length > 0 && isBoundaryFilter(parts[parts.length - 1], typePatternGraph, outputPattern)) {
|
|
135
|
+
parts = parts.slice(0, -1);
|
|
136
|
+
}
|
|
137
|
+
if (parts.length === (exp.comp || []).length) return exp;
|
|
138
|
+
if (parts.length === 0) {
|
|
139
|
+
return {
|
|
140
|
+
op: "identity",
|
|
141
|
+
patterns: [...exp.patterns],
|
|
142
|
+
...(exp.start ? { start: exp.start } : {}),
|
|
143
|
+
...(exp.end ? { end: exp.end } : {})
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
if (parts.length === 1) return { ...parts[0], patterns: [...exp.patterns] };
|
|
147
|
+
return { ...exp, comp: parts };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function stripDebugFieldsFromFilter(filter) {
|
|
151
|
+
if (!filter) return filter;
|
|
152
|
+
const { start, end, fields, ...rest } = filter;
|
|
153
|
+
if (!fields) return rest;
|
|
56
154
|
return {
|
|
57
|
-
...
|
|
58
|
-
|
|
59
|
-
Object.entries(
|
|
155
|
+
...rest,
|
|
156
|
+
fields: Object.fromEntries(
|
|
157
|
+
Object.entries(fields).map(([label, child]) => [label, stripDebugFieldsFromFilter(child)])
|
|
60
158
|
)
|
|
61
159
|
};
|
|
62
160
|
}
|
|
63
161
|
|
|
162
|
+
function stripDebugFieldsFromExp(exp) {
|
|
163
|
+
if (!exp) return exp;
|
|
164
|
+
const { start, end, ...rest } = exp;
|
|
165
|
+
switch (rest.op) {
|
|
166
|
+
case "filter":
|
|
167
|
+
return { ...rest, filter: stripDebugFieldsFromFilter(rest.filter) };
|
|
168
|
+
case "comp":
|
|
169
|
+
return { ...rest, comp: rest.comp.map(stripDebugFieldsFromExp) };
|
|
170
|
+
case "union":
|
|
171
|
+
return { ...rest, union: rest.union.map(stripDebugFieldsFromExp) };
|
|
172
|
+
case "product":
|
|
173
|
+
return {
|
|
174
|
+
...rest,
|
|
175
|
+
product: rest.product.map(({ label, exp: child }) => ({
|
|
176
|
+
label,
|
|
177
|
+
exp: stripDebugFieldsFromExp(child)
|
|
178
|
+
}))
|
|
179
|
+
};
|
|
180
|
+
default:
|
|
181
|
+
return rest;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function stripDebugFieldsFromCode(code) {
|
|
186
|
+
if (!code) return code;
|
|
187
|
+
const { start, end, ...rest } = code;
|
|
188
|
+
return rest;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function stripDebugFieldsFromCodes(codeTable) {
|
|
192
|
+
return Object.fromEntries(
|
|
193
|
+
Object.entries(codeTable || {}).map(([hash, code]) => [hash, stripDebugFieldsFromCode(code)])
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function firstFilterSourceRange(filter) {
|
|
198
|
+
if (!filter) return null;
|
|
199
|
+
if (filter.start || filter.end) {
|
|
200
|
+
return {
|
|
201
|
+
...(filter.start ? { start: filter.start } : {}),
|
|
202
|
+
...(filter.end ? { end: filter.end } : {})
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
for (const child of Object.values(filter.fields || {})) {
|
|
206
|
+
const range = firstFilterSourceRange(child);
|
|
207
|
+
if (range) return range;
|
|
208
|
+
}
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function firstExpSourceRange(exp) {
|
|
213
|
+
if (!exp) return null;
|
|
214
|
+
if (exp.start || exp.end) {
|
|
215
|
+
return {
|
|
216
|
+
...(exp.start ? { start: exp.start } : {}),
|
|
217
|
+
...(exp.end ? { end: exp.end } : {})
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
switch (exp.op) {
|
|
221
|
+
case "filter":
|
|
222
|
+
return firstFilterSourceRange(exp.filter);
|
|
223
|
+
case "comp":
|
|
224
|
+
for (const child of exp.comp) {
|
|
225
|
+
const range = firstExpSourceRange(child);
|
|
226
|
+
if (range) return range;
|
|
227
|
+
}
|
|
228
|
+
return null;
|
|
229
|
+
case "union":
|
|
230
|
+
for (const child of exp.union) {
|
|
231
|
+
const range = firstExpSourceRange(child);
|
|
232
|
+
if (range) return range;
|
|
233
|
+
}
|
|
234
|
+
return null;
|
|
235
|
+
case "product":
|
|
236
|
+
for (const { exp: child } of exp.product) {
|
|
237
|
+
const range = firstExpSourceRange(child);
|
|
238
|
+
if (range) return range;
|
|
239
|
+
}
|
|
240
|
+
return null;
|
|
241
|
+
default:
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function originFromSourceNode(source, name, compiledAt, node) {
|
|
247
|
+
return {
|
|
248
|
+
source,
|
|
249
|
+
name,
|
|
250
|
+
compiledAt,
|
|
251
|
+
...(node?.start ? { start: node.start } : {}),
|
|
252
|
+
...(node?.end ? { end: node.end } : {})
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function relationOrigin(source, name, compiledAt, rel) {
|
|
257
|
+
const printableDef = stripRelationBoundaryFilters(rel.def, rel.typePatternGraph);
|
|
258
|
+
const range = firstExpSourceRange(printableDef);
|
|
259
|
+
return {
|
|
260
|
+
source,
|
|
261
|
+
name,
|
|
262
|
+
compiledAt,
|
|
263
|
+
...(range?.start ? { start: range.start } : {}),
|
|
264
|
+
...(range?.end ? { end: range.end } : {})
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function buildRelTypeDerivation(rel, sccStats) {
|
|
269
|
+
const existing = rel?.typeDerivation || {};
|
|
270
|
+
const status = sccStats
|
|
271
|
+
? (sccStats.converged ? "converged" : "not-converged")
|
|
272
|
+
: validTypeDerivationStatus(existing.status);
|
|
273
|
+
return { status };
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function buildRelTypeDerivations(rels, compileStats) {
|
|
277
|
+
const statsByName = compileStatsByRelName(compileStats);
|
|
278
|
+
return Object.fromEntries(
|
|
279
|
+
Object.entries(rels || {}).map(([name, rel]) => [
|
|
280
|
+
name,
|
|
281
|
+
buildRelTypeDerivation(rel, statsByName[name])
|
|
282
|
+
])
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function mergeMetaEntries(...metas) {
|
|
287
|
+
const merged = {};
|
|
288
|
+
for (const meta of metas) {
|
|
289
|
+
for (const [hash, entry] of Object.entries(meta || {})) {
|
|
290
|
+
const type = entry?.type;
|
|
291
|
+
if (type !== "code" && type !== "rel") continue;
|
|
292
|
+
for (const origin of entry.origins || []) {
|
|
293
|
+
if (!origin?.name) continue;
|
|
294
|
+
addOrigin(merged, hash, type, { ...origin });
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return merged;
|
|
299
|
+
}
|
|
300
|
+
|
|
64
301
|
function buildMeta(annotated, source) {
|
|
65
302
|
const meta = {};
|
|
303
|
+
const representatives = annotated.representatives || {};
|
|
66
304
|
const relAlias = annotated.relAlias || {};
|
|
67
305
|
const now = new Date().toISOString();
|
|
68
|
-
|
|
306
|
+
|
|
307
|
+
for (const [name, hash] of Object.entries(representatives)) {
|
|
308
|
+
if (!isSourceName(name)) continue;
|
|
309
|
+
addOrigin(meta, hash, "code", originFromSourceNode(
|
|
310
|
+
source,
|
|
311
|
+
name,
|
|
312
|
+
now,
|
|
313
|
+
annotated.sourceDefs?.codes?.[name]
|
|
314
|
+
));
|
|
315
|
+
}
|
|
316
|
+
|
|
69
317
|
for (const [name, hash] of Object.entries(relAlias)) {
|
|
70
|
-
|
|
71
|
-
if (!
|
|
72
|
-
|
|
318
|
+
const rel = annotated.rels?.[name];
|
|
319
|
+
if (!rel) continue;
|
|
320
|
+
if (name === "__main__" || isSourceName(name)) {
|
|
321
|
+
addOrigin(meta, hash, "rel", relationOrigin(source, name, now, rel));
|
|
322
|
+
}
|
|
73
323
|
}
|
|
74
324
|
return meta;
|
|
75
325
|
}
|
|
76
326
|
|
|
327
|
+
function importedLibraryMeta(libraries = []) {
|
|
328
|
+
return mergeMetaEntries(...libraries.map((library) => library.meta || {}));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function isEofParseError(error) {
|
|
332
|
+
return error?.hash?.token === "EOF" || /got 'EOF'|Expecting/.test(error?.message || "");
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function annotateLibrary(script, options = {}) {
|
|
336
|
+
try {
|
|
337
|
+
return annotate(script, options);
|
|
338
|
+
} catch (error) {
|
|
339
|
+
if (!isEofParseError(error)) throw error;
|
|
340
|
+
return annotate(`${script}\n()`, options);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
77
344
|
function collectReachable(mainName, rels, allCodes) {
|
|
78
345
|
const reachableRels = new Set();
|
|
79
346
|
const reachableCodes = new Set();
|
|
@@ -129,7 +396,7 @@ function collectReachable(mainName, rels, allCodes) {
|
|
|
129
396
|
const rel = rels[relName];
|
|
130
397
|
if (rel.typePatternGraph) {
|
|
131
398
|
const codeId = rel.typePatternGraph.codeId || (rel.typePatternGraph.codeId);
|
|
132
|
-
if (codeId) Object.
|
|
399
|
+
if (codeId) Object.keys(codeId).forEach(walkCode);
|
|
133
400
|
}
|
|
134
401
|
}
|
|
135
402
|
|
|
@@ -138,9 +405,12 @@ function collectReachable(mainName, rels, allCodes) {
|
|
|
138
405
|
|
|
139
406
|
function compileObject(script, options = {}) {
|
|
140
407
|
const annotated = annotate(script, options);
|
|
141
|
-
const allCodes = codes.dump();
|
|
408
|
+
const allCodes = stripDebugFieldsFromCodes(codes.dump());
|
|
142
409
|
const serialized = serializeAnnotated(annotated);
|
|
143
|
-
const meta =
|
|
410
|
+
const meta = mergeMetaEntries(
|
|
411
|
+
importedLibraryMeta(options.libraries),
|
|
412
|
+
buildMeta(annotated, options.source || null)
|
|
413
|
+
);
|
|
144
414
|
|
|
145
415
|
// Prune to reachable from main
|
|
146
416
|
const { reachableRels, reachableCodes } = collectReachable("__main__", serialized.rels, allCodes);
|
|
@@ -150,13 +420,15 @@ function compileObject(script, options = {}) {
|
|
|
150
420
|
const prunedRels = Object.fromEntries(
|
|
151
421
|
Object.entries(serialized.rels).filter(([name]) => reachableRels.has(name))
|
|
152
422
|
);
|
|
423
|
+
const reachableRelHashes = new Set(
|
|
424
|
+
[...reachableRels].map((name) => serialized.relAlias?.[name] || name)
|
|
425
|
+
);
|
|
153
426
|
const prunedMeta = Object.fromEntries(
|
|
154
|
-
Object.entries(meta).filter(([h]) => reachableRels.has(h) || reachableCodes.has(h))
|
|
427
|
+
Object.entries(meta).filter(([h]) => reachableRels.has(h) || reachableRelHashes.has(h) || reachableCodes.has(h))
|
|
155
428
|
);
|
|
156
429
|
|
|
157
430
|
return {
|
|
158
431
|
format: "k-object",
|
|
159
|
-
version: 2,
|
|
160
432
|
codes: prunedCodes,
|
|
161
433
|
rels: prunedRels,
|
|
162
434
|
relAlias: serialized.relAlias,
|
|
@@ -189,9 +461,13 @@ function rewriteRefsToCanonical(exp, relAlias) {
|
|
|
189
461
|
}
|
|
190
462
|
|
|
191
463
|
function compileLibrary(script, options = {}) {
|
|
192
|
-
const annotated =
|
|
464
|
+
const annotated = annotateLibrary(script, options);
|
|
465
|
+
const allCodes = stripDebugFieldsFromCodes(codes.dump());
|
|
193
466
|
const serialized = serializeAnnotated(annotated);
|
|
194
|
-
const meta =
|
|
467
|
+
const meta = mergeMetaEntries(
|
|
468
|
+
importedLibraryMeta(options.libraries),
|
|
469
|
+
buildMeta(annotated, options.source || null)
|
|
470
|
+
);
|
|
195
471
|
const relAlias = serialized.relAlias || {};
|
|
196
472
|
|
|
197
473
|
// Key rels by canonical hash, rewrite internal refs to canonical hashes
|
|
@@ -205,15 +481,21 @@ function compileLibrary(script, options = {}) {
|
|
|
205
481
|
def: rewriteRefsToCanonical(rel.def, relAlias)
|
|
206
482
|
};
|
|
207
483
|
}
|
|
484
|
+
const libraryMetaHashes = new Set([
|
|
485
|
+
...Object.keys(allCodes),
|
|
486
|
+
...Object.keys(libRels)
|
|
487
|
+
]);
|
|
488
|
+
const libMeta = Object.fromEntries(
|
|
489
|
+
Object.entries(meta).filter(([hash]) => libraryMetaHashes.has(hash))
|
|
490
|
+
);
|
|
208
491
|
|
|
209
492
|
return {
|
|
210
493
|
format: "k-object",
|
|
211
|
-
|
|
212
|
-
codes: codes.dump(),
|
|
494
|
+
codes: allCodes,
|
|
213
495
|
rels: libRels,
|
|
214
496
|
relAlias: serialized.relAlias,
|
|
215
497
|
compileStats: serialized.compileStats,
|
|
216
|
-
meta,
|
|
498
|
+
meta: libMeta,
|
|
217
499
|
main: null
|
|
218
500
|
};
|
|
219
501
|
}
|
|
@@ -222,15 +504,6 @@ function hydrateObject(object) {
|
|
|
222
504
|
if (object?.format !== "k-object") {
|
|
223
505
|
throw new Error("Unsupported k object file");
|
|
224
506
|
}
|
|
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
507
|
codes.load(object.codes);
|
|
235
508
|
const hydratedRels = Object.fromEntries(
|
|
236
509
|
Object.entries(object.rels).map(([name, rel]) => [name, hydrateRelation(rel)])
|
|
@@ -247,25 +520,23 @@ function loadLibrary(object) {
|
|
|
247
520
|
}
|
|
248
521
|
|
|
249
522
|
function isHydratedObject(object) {
|
|
250
|
-
// v2 format
|
|
251
523
|
if (object?.rels) {
|
|
252
524
|
const firstRel = Object.values(object.rels)[0];
|
|
253
525
|
return firstRel?.typePatternGraph instanceof TypePatternGraph;
|
|
254
526
|
}
|
|
255
|
-
|
|
256
|
-
return object?.defs?.rels?.[object.main]?.typePatternGraph instanceof TypePatternGraph;
|
|
527
|
+
return false;
|
|
257
528
|
}
|
|
258
529
|
|
|
259
530
|
function encodeObject(object) {
|
|
260
|
-
|
|
531
|
+
if (object.main == null) return encodeLibrary(object);
|
|
261
532
|
const payload = Buffer.from(JSON.stringify(object), "utf8");
|
|
262
533
|
if (payload.length > 0xffffffff) {
|
|
263
534
|
throw new Error("k object payload is too large");
|
|
264
535
|
}
|
|
265
536
|
|
|
266
|
-
const header = Buffer.alloc(
|
|
267
|
-
|
|
268
|
-
header.writeUInt32BE(payload.length,
|
|
537
|
+
const header = Buffer.alloc(OBJECT_MAGIC.length + 4);
|
|
538
|
+
OBJECT_MAGIC.copy(header, 0);
|
|
539
|
+
header.writeUInt32BE(payload.length, OBJECT_MAGIC.length);
|
|
269
540
|
return Buffer.concat([header, payload]);
|
|
270
541
|
}
|
|
271
542
|
|
|
@@ -273,15 +544,16 @@ function decodeObject(buffer) {
|
|
|
273
544
|
if (!Buffer.isBuffer(buffer)) {
|
|
274
545
|
throw new Error("k object input must be a Buffer");
|
|
275
546
|
}
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
|
|
547
|
+
const trimmed = buffer.toString("utf8").trimStart();
|
|
548
|
+
if (trimmed.startsWith("{")) {
|
|
549
|
+
return hydrateObject(JSON.parse(trimmed));
|
|
550
|
+
}
|
|
551
|
+
if (buffer.length < OBJECT_MAGIC.length || !buffer.subarray(0, OBJECT_MAGIC.length).equals(OBJECT_MAGIC)) {
|
|
279
552
|
throw new Error("Invalid k object file header");
|
|
280
553
|
}
|
|
281
554
|
|
|
282
|
-
const
|
|
283
|
-
const
|
|
284
|
-
const payloadStart = magic.length + 4;
|
|
555
|
+
const length = buffer.readUInt32BE(OBJECT_MAGIC.length);
|
|
556
|
+
const payloadStart = OBJECT_MAGIC.length + 4;
|
|
285
557
|
const payloadEnd = payloadStart + length;
|
|
286
558
|
if (payloadEnd !== buffer.length) {
|
|
287
559
|
throw new Error("Invalid k object file length");
|
|
@@ -291,7 +563,7 @@ function decodeObject(buffer) {
|
|
|
291
563
|
}
|
|
292
564
|
|
|
293
565
|
function encodeLibrary(object) {
|
|
294
|
-
return
|
|
566
|
+
return Buffer.from(JSON.stringify(object), "utf8");
|
|
295
567
|
}
|
|
296
568
|
|
|
297
569
|
function decodeLibrary(buffer) {
|
|
@@ -307,20 +579,19 @@ function compileObjectBuffer(script, options = {}) {
|
|
|
307
579
|
}
|
|
308
580
|
|
|
309
581
|
function compileLibraryBuffer(script, options = {}) {
|
|
310
|
-
return
|
|
582
|
+
return encodeLibrary(compileLibrary(script, options));
|
|
311
583
|
}
|
|
312
584
|
|
|
313
585
|
function getRels(hydrated) {
|
|
314
|
-
|
|
315
|
-
return hydrated.rels || hydrated.defs?.rels;
|
|
586
|
+
return hydrated.rels;
|
|
316
587
|
}
|
|
317
588
|
|
|
318
589
|
function runObject(object, value) {
|
|
319
590
|
const hydrated = isHydratedObject(object) ? object : hydrateObject(object);
|
|
320
591
|
const rels = getRels(hydrated);
|
|
321
|
-
run.defs =
|
|
592
|
+
run.defs = { rels };
|
|
322
593
|
const mainRel = rels[hydrated.main];
|
|
323
|
-
return
|
|
594
|
+
return run_rel(codes.find, mainRel, value, hydrated.main);
|
|
324
595
|
}
|
|
325
596
|
|
|
326
597
|
function objectToFunction(object) {
|
|
@@ -328,6 +599,29 @@ function objectToFunction(object) {
|
|
|
328
599
|
return (value) => runObject(hydrated, value);
|
|
329
600
|
}
|
|
330
601
|
|
|
602
|
+
function assertRelConverged(rel, name) {
|
|
603
|
+
const status = rel?.typeDerivation?.status || "unknown";
|
|
604
|
+
if (status !== "converged") {
|
|
605
|
+
throw new Error(`Cannot run '${name}' without envelopes: type derivation is ${status}`);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
function runConvergedObject(object, value) {
|
|
610
|
+
const hydrated = isHydratedObject(object) ? object : hydrateObject(object);
|
|
611
|
+
const rels = getRels(hydrated);
|
|
612
|
+
const mainRel = rels[hydrated.main];
|
|
613
|
+
assertRelConverged(mainRel, hydrated.main);
|
|
614
|
+
run_converged.defs = { rels };
|
|
615
|
+
return run_converged(codes.find, mainRel.def, value, mainRel.typePatternGraph, {
|
|
616
|
+
requireConverged: true
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
function objectToConvergedFunction(object) {
|
|
621
|
+
const hydrated = isHydratedObject(object) ? object : hydrateObject(object);
|
|
622
|
+
return (value) => runConvergedObject(hydrated, value);
|
|
623
|
+
}
|
|
624
|
+
|
|
331
625
|
function hashAlias(hash) {
|
|
332
626
|
return hash.startsWith("@") ? hash.slice(1) : hash;
|
|
333
627
|
}
|
|
@@ -413,10 +707,23 @@ function boundaryFilterSource(typePatternGraph, patternId, aliases) {
|
|
|
413
707
|
return prettyRel({ op: "filter", filter: rewriteCodesInFilter(filter, aliases) });
|
|
414
708
|
}
|
|
415
709
|
|
|
710
|
+
function prettyRelation(rel, aliases = {}, relAliases = {}) {
|
|
711
|
+
const body = rewriteRefsInExp(
|
|
712
|
+
stripRelationBoundaryFilters(stripDebugFieldsFromExp(rel.def), rel.typePatternGraph),
|
|
713
|
+
aliases,
|
|
714
|
+
relAliases
|
|
715
|
+
);
|
|
716
|
+
return [
|
|
717
|
+
boundaryFilterSource(rel.typePatternGraph, rel.def.patterns[0], aliases),
|
|
718
|
+
prettyRel(body),
|
|
719
|
+
boundaryFilterSource(rel.typePatternGraph, rel.def.patterns[1], aliases)
|
|
720
|
+
].join(" ");
|
|
721
|
+
}
|
|
722
|
+
|
|
416
723
|
function decompileObject(object) {
|
|
417
724
|
const hydrated = isHydratedObject(object) ? object : hydrateObject(object);
|
|
418
725
|
const rels = getRels(hydrated);
|
|
419
|
-
const relAliases = hydrated.
|
|
726
|
+
const relAliases = hydrated.relAlias || {};
|
|
420
727
|
const aliases = shortestUniqueAliases([
|
|
421
728
|
...Object.keys(hydrated.codes),
|
|
422
729
|
...Object.values(relAliases)
|
|
@@ -432,9 +739,9 @@ function decompileObject(object) {
|
|
|
432
739
|
const relName = relAliases[name] || name;
|
|
433
740
|
if (emittedRelAliases.has(relName)) return null;
|
|
434
741
|
emittedRelAliases.add(relName);
|
|
435
|
-
return `${aliases[relName] || relName} = ${
|
|
742
|
+
return `${aliases[relName] || relName} = ${prettyRelation(rel, aliases, relAliases)};`;
|
|
436
743
|
};
|
|
437
|
-
const compileStats = hydrated.
|
|
744
|
+
const compileStats = hydrated.compileStats;
|
|
438
745
|
const sccs = compileStats?.sccs || [];
|
|
439
746
|
const relGroups = sccs.map(({ members }) =>
|
|
440
747
|
members.map(relDefForName).filter((line) => line != null)
|
|
@@ -482,6 +789,84 @@ function decompileObjectBuffer(buffer) {
|
|
|
482
789
|
return decompileObject(decodeObject(buffer));
|
|
483
790
|
}
|
|
484
791
|
|
|
792
|
+
function hashBody(hash) {
|
|
793
|
+
return hash.startsWith("@") ? hash.slice(1) : hash;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
function compareAliasEntries(left, right) {
|
|
797
|
+
return (
|
|
798
|
+
left.typeOrder - right.typeOrder ||
|
|
799
|
+
left.name.localeCompare(right.name) ||
|
|
800
|
+
compareMaybeTimestamp(left.compiledAt, right.compiledAt) ||
|
|
801
|
+
left.hash.localeCompare(right.hash) ||
|
|
802
|
+
left.source.localeCompare(right.source)
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
function compareMaybeTimestamp(left, right) {
|
|
807
|
+
if (left == null && right == null) return 0;
|
|
808
|
+
if (left == null) return 1;
|
|
809
|
+
if (right == null) return -1;
|
|
810
|
+
return left.localeCompare(right);
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
function originComment(origin) {
|
|
814
|
+
return JSON.stringify({
|
|
815
|
+
...(origin.source == null ? {} : { source: origin.source }),
|
|
816
|
+
...(origin.compiledAt == null ? {} : { compiledAt: origin.compiledAt })
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
function extractAliasesFromObject(object) {
|
|
821
|
+
const hydrated = isHydratedObject(object) ? object : hydrateObject(object);
|
|
822
|
+
const entries = [];
|
|
823
|
+
|
|
824
|
+
for (const [hash, entry] of Object.entries(hydrated.meta || {})) {
|
|
825
|
+
const type = entry?.type;
|
|
826
|
+
if (type !== "code" && type !== "rel") continue;
|
|
827
|
+
const typeOrder = type === "code" ? 0 : 1;
|
|
828
|
+
for (const origin of entry.origins || []) {
|
|
829
|
+
if (origin?.name === "__main__") continue;
|
|
830
|
+
if (!origin?.name || !isSourceName(origin.name)) continue;
|
|
831
|
+
entries.push({
|
|
832
|
+
type,
|
|
833
|
+
typeOrder,
|
|
834
|
+
hash,
|
|
835
|
+
name: origin.name,
|
|
836
|
+
source: origin.source || "",
|
|
837
|
+
compiledAt: origin.compiledAt,
|
|
838
|
+
comment: originComment(origin)
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
entries.sort(compareAliasEntries);
|
|
844
|
+
|
|
845
|
+
const activeEntries = new Set();
|
|
846
|
+
for (let i = 0; i < entries.length; i++) {
|
|
847
|
+
const next = entries[i + 1];
|
|
848
|
+
if (!next || next.type !== entries[i].type || next.name !== entries[i].name) {
|
|
849
|
+
activeEntries.add(entries[i]);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
const lines = [];
|
|
854
|
+
let lastType = null;
|
|
855
|
+
for (const entry of entries) {
|
|
856
|
+
if (lastType != null && lastType !== entry.type) lines.push("");
|
|
857
|
+
lastType = entry.type;
|
|
858
|
+
const prefix = entry.type === "code" ? "$ " : "";
|
|
859
|
+
const line = `${prefix}${entry.name} = @${hashBody(entry.hash)}; # ${entry.comment}`;
|
|
860
|
+
lines.push(activeEntries.has(entry) ? line : `# ${line}`);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
return `${lines.join("\n")}${lines.length === 0 ? "" : "\n"}`;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
function extractAliasesFromObjectBuffer(buffer) {
|
|
867
|
+
return extractAliasesFromObject(decodeObject(buffer));
|
|
868
|
+
}
|
|
869
|
+
|
|
485
870
|
export {
|
|
486
871
|
compileObject,
|
|
487
872
|
compileObjectBuffer,
|
|
@@ -494,9 +879,14 @@ export {
|
|
|
494
879
|
hydrateObject,
|
|
495
880
|
loadLibrary,
|
|
496
881
|
runObject,
|
|
882
|
+
runConvergedObject,
|
|
497
883
|
objectToFunction,
|
|
884
|
+
objectToConvergedFunction,
|
|
885
|
+
prettyRelation,
|
|
498
886
|
decompileObject,
|
|
499
|
-
decompileObjectBuffer
|
|
887
|
+
decompileObjectBuffer,
|
|
888
|
+
extractAliasesFromObject,
|
|
889
|
+
extractAliasesFromObjectBuffer
|
|
500
890
|
};
|
|
501
891
|
|
|
502
892
|
export default {
|
|
@@ -511,7 +901,12 @@ export default {
|
|
|
511
901
|
hydrateObject,
|
|
512
902
|
loadLibrary,
|
|
513
903
|
runObject,
|
|
904
|
+
runConvergedObject,
|
|
514
905
|
objectToFunction,
|
|
906
|
+
objectToConvergedFunction,
|
|
907
|
+
prettyRelation,
|
|
515
908
|
decompileObject,
|
|
516
|
-
decompileObjectBuffer
|
|
909
|
+
decompileObjectBuffer,
|
|
910
|
+
extractAliasesFromObject,
|
|
911
|
+
extractAliasesFromObjectBuffer
|
|
517
912
|
};
|