@fraczak/k 7.2.0 → 8.0.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.
- package/CHANGELOG.md +66 -0
- package/DOCS/BIG_PICTURE.md +54 -7
- package/DOCS/CODECS.md +21 -11
- package/DOCS/CODEC_ARCHITECTURE.md +5 -3
- package/DOCS/DICTIONARY.md +13 -4
- package/DOCS/FILE_FORMATS.md +3 -2
- package/DOCS/JSON_APPROACHES_COMPARISON.md +306 -0
- package/DOCS/NAMED_PATTERNS.md +317 -0
- package/DOCS/PATTERNS.md +59 -11
- package/DOCS/REPL.md +13 -2
- package/DOCS/WEB_REPL_REQUIREMENTS.md +4 -2
- package/Examples/arithmetics.k +22 -17
- package/Examples/bnat.k +21 -11
- package/Examples/buda.k +37 -20
- package/Examples/byte.k +3 -1
- package/Examples/code.k +38 -39
- package/Examples/djson-btrie.k +414 -0
- package/Examples/djson-ptrie.k +663 -0
- package/Examples/djson.k +323 -0
- package/Examples/esc.k +1 -1
- package/Examples/karatsuba-mult.k +16 -13
- package/Examples/list.k +8 -4
- package/Examples/nat.k +17 -11
- package/Examples/poly.k +11 -3
- package/Examples/vhdl_to_k.k +43 -31
- package/README.md +42 -16
- package/browser/repl-browser.mjs +6 -0
- package/browser/tree-view.mjs +35 -16
- package/browser/vfs-data.mjs +15 -7
- package/codecs/README.md +2 -0
- package/codecs/djson-btrie.mjs +560 -0
- package/codecs/djson-ptrie.mjs +587 -0
- package/core.k +79 -115
- package/index.mjs +3 -0
- package/named-patterns.mjs +267 -0
- package/object.mjs +31 -3
- package/package.json +4 -1
- package/parser.jison +68 -5
- package/parser.mjs +111 -60
- package/pretty.mjs +5 -0
- package/repl.mjs +188 -22
- package/scripts/build-repl-html.mjs +68 -4
- package/scripts/perf-djson.mjs +1142 -0
- package/scripts/run-tests.mjs +5 -0
- package/symbol-table.mjs +20 -2
- package/tests/bench-djson-tries.mjs +340 -0
- package/tests/test-codecs.mjs +59 -16
- package/tests/test-named-patterns.mjs +189 -0
- package/tests/test-repl-html.mjs +51 -4
- package/tests/test-repl.mjs +190 -0
package/repl.mjs
CHANGED
|
@@ -21,7 +21,7 @@ if (typeof globalThis !== "undefined") {
|
|
|
21
21
|
globalThis.isVariant = isVariant;
|
|
22
22
|
globalThis.patternFromFilter = patternFromFilter;
|
|
23
23
|
}
|
|
24
|
-
import { prettyCode } from "./pretty.mjs";
|
|
24
|
+
import { prettyCode, prettyFilter } from "./pretty.mjs";
|
|
25
25
|
import {
|
|
26
26
|
compileObject,
|
|
27
27
|
compileLibrary,
|
|
@@ -32,7 +32,11 @@ import {
|
|
|
32
32
|
loadLibrary,
|
|
33
33
|
prettyRelation
|
|
34
34
|
} from "./object.mjs";
|
|
35
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
propertyListToFilter,
|
|
37
|
+
valueToK,
|
|
38
|
+
valueWithEnvelopeToK
|
|
39
|
+
} from "./codecs/runtime/show-value.mjs";
|
|
36
40
|
import {
|
|
37
41
|
codecNames,
|
|
38
42
|
codeHashToPattern,
|
|
@@ -48,7 +52,7 @@ import {
|
|
|
48
52
|
|
|
49
53
|
const NAME_RE = /^[a-zA-Z0-9_+-][a-zA-Z0-9_?!+-]*$/;
|
|
50
54
|
const COMMAND_NAMES = [
|
|
51
|
-
"help", "rel",
|
|
55
|
+
"help", "rel", "pattern", "pat", "patterns", "pats",
|
|
52
56
|
"codecs", "rels", "codec", "input", "reset", "klib", "ko", "load",
|
|
53
57
|
"engine", "wasm", "pkir", "js", "limit",
|
|
54
58
|
"quit", "exit"
|
|
@@ -87,6 +91,7 @@ function createState(options = {}) {
|
|
|
87
91
|
rels: {},
|
|
88
92
|
relAliases: {},
|
|
89
93
|
typeAliases: {},
|
|
94
|
+
patterns: {},
|
|
90
95
|
codecs: {},
|
|
91
96
|
loadedFiles: new Set(),
|
|
92
97
|
pendingInput: null,
|
|
@@ -106,6 +111,7 @@ function stateLibrary(state) {
|
|
|
106
111
|
codes: state.codes,
|
|
107
112
|
rels: state.rels,
|
|
108
113
|
relAlias: state.relAliases,
|
|
114
|
+
patterns: state.patterns,
|
|
109
115
|
meta: state.meta,
|
|
110
116
|
main: null
|
|
111
117
|
};
|
|
@@ -227,6 +233,11 @@ function mergeLibrary(state, lib, source = "<load>", options = {}) {
|
|
|
227
233
|
const loadAliases = options.loadAliases ?? true;
|
|
228
234
|
state.codes = { ...state.codes, ...(lib.codes || {}) };
|
|
229
235
|
state.rels = { ...state.rels, ...(lib.rels || {}) };
|
|
236
|
+
state.patterns = {
|
|
237
|
+
...state.patterns,
|
|
238
|
+
...(lib.patterns || lib.sourceDefs?.patterns ||
|
|
239
|
+
lib.defs?.patterns || {})
|
|
240
|
+
};
|
|
230
241
|
mergeMeta(state, lib.meta);
|
|
231
242
|
|
|
232
243
|
if (loadAliases) {
|
|
@@ -310,6 +321,7 @@ function savedLibrary(state) {
|
|
|
310
321
|
rels,
|
|
311
322
|
relAlias: state.relAliases,
|
|
312
323
|
compileStats: { sccs: [], sccCount: 0 },
|
|
324
|
+
patterns: state.patterns || {},
|
|
313
325
|
meta: Object.fromEntries(
|
|
314
326
|
Object.entries(meta).filter(([hash]) => storedHashes.has(hash))
|
|
315
327
|
),
|
|
@@ -320,7 +332,10 @@ function savedLibrary(state) {
|
|
|
320
332
|
function executableObject(state, mainExpression) {
|
|
321
333
|
const main = (mainExpression || state.lastMain || "").trim();
|
|
322
334
|
if (!main) {
|
|
323
|
-
throw new Error(
|
|
335
|
+
throw new Error(
|
|
336
|
+
":ko file expr requires a main expression unless one has " +
|
|
337
|
+
"already been evaluated or defined"
|
|
338
|
+
);
|
|
324
339
|
}
|
|
325
340
|
|
|
326
341
|
restoreCodes(state);
|
|
@@ -328,7 +343,8 @@ function executableObject(state, mainExpression) {
|
|
|
328
343
|
try {
|
|
329
344
|
return compileObject([preamble, main].filter(Boolean).join("\n"), {
|
|
330
345
|
source: "<repl>",
|
|
331
|
-
libraries: [stateLibrary(state)]
|
|
346
|
+
libraries: [stateLibrary(state)],
|
|
347
|
+
patterns: state.patterns
|
|
332
348
|
});
|
|
333
349
|
} catch (error) {
|
|
334
350
|
throw remapError(error, preambleLineCount(preamble));
|
|
@@ -343,11 +359,72 @@ function resolveRel(state, name) {
|
|
|
343
359
|
}
|
|
344
360
|
|
|
345
361
|
function listAliases(aliases) {
|
|
346
|
-
const entries = Object.entries(aliases).sort(([a], [b]) =>
|
|
362
|
+
const entries = Object.entries(aliases).sort(([a], [b]) =>
|
|
363
|
+
a.localeCompare(b)
|
|
364
|
+
);
|
|
347
365
|
if (entries.length === 0) return "(none)";
|
|
348
366
|
return entries.map(([name, hash]) => `${name} = ${hash}`).join("\n");
|
|
349
367
|
}
|
|
350
368
|
|
|
369
|
+
function resolvePatternCanonicalName(state, name, pat) {
|
|
370
|
+
if (!state || !pat) return null;
|
|
371
|
+
if (pat._canonical) return pat._canonical;
|
|
372
|
+
const params = pat.params || [];
|
|
373
|
+
const source = `? ${name}[${params.join(", ")}]`;
|
|
374
|
+
try {
|
|
375
|
+
restoreCodes(state);
|
|
376
|
+
const annotated = annotate(source, {
|
|
377
|
+
libraries: [stateLibrary(state)],
|
|
378
|
+
patterns: state.patterns
|
|
379
|
+
});
|
|
380
|
+
const mainRel = annotated.rels.__main__;
|
|
381
|
+
if (
|
|
382
|
+
mainRel?.typePatternGraph &&
|
|
383
|
+
mainRel?.def?.patterns?.[0] != null
|
|
384
|
+
) {
|
|
385
|
+
const rootId = mainRel.typePatternGraph.find(
|
|
386
|
+
mainRel.def.patterns[0]
|
|
387
|
+
);
|
|
388
|
+
const propList = patternToPropertyList(
|
|
389
|
+
exportPatternGraph(mainRel.typePatternGraph, rootId)
|
|
390
|
+
);
|
|
391
|
+
const codeHash = closedPatternToCodeHash(propList);
|
|
392
|
+
if (codeHash) {
|
|
393
|
+
state.codes = codes.dump();
|
|
394
|
+
pat._canonical = codeHash;
|
|
395
|
+
return codeHash;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
const relHash = annotated.relAlias?.__main__ || null;
|
|
399
|
+
if (relHash) {
|
|
400
|
+
pat._canonical = relHash;
|
|
401
|
+
return relHash;
|
|
402
|
+
}
|
|
403
|
+
} catch {
|
|
404
|
+
restoreCodes(state);
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function prettyPattern(name, pat, state = null) {
|
|
411
|
+
const params = (pat?.params || []).join(", ");
|
|
412
|
+
const filterStr = pat?.filter ? prettyFilter(pat.filter) : "()";
|
|
413
|
+
const canonical = resolvePatternCanonicalName(state, name, pat);
|
|
414
|
+
const suffix = canonical ? ` -- ${canonical}` : "";
|
|
415
|
+
return `${name}[${params}] = ${filterStr};${suffix}`;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function listPatterns(patterns) {
|
|
419
|
+
const entries = Object.entries(patterns || {}).sort(([a], [b]) =>
|
|
420
|
+
a.localeCompare(b)
|
|
421
|
+
);
|
|
422
|
+
if (entries.length === 0) return "(none)";
|
|
423
|
+
return entries
|
|
424
|
+
.map(([name, pat]) => `${name}[${(pat?.params || []).join(", ")}]`)
|
|
425
|
+
.join("\n");
|
|
426
|
+
}
|
|
427
|
+
|
|
351
428
|
function formatCodecOutput(output) {
|
|
352
429
|
if (typeof Buffer !== "undefined" && Buffer.isBuffer(output)) return output.toString("utf8");
|
|
353
430
|
if (typeof Uint8Array !== "undefined" && output instanceof Uint8Array) return new TextDecoder().decode(output);
|
|
@@ -644,9 +721,16 @@ function resolveTypeExpressionHash(state, rawType) {
|
|
|
644
721
|
].filter(Boolean).join("\n");
|
|
645
722
|
|
|
646
723
|
try {
|
|
647
|
-
const annotated = annotate(source, {
|
|
724
|
+
const annotated = annotate(source, {
|
|
725
|
+
libraries: [stateLibrary(state)],
|
|
726
|
+
patterns: state.patterns
|
|
727
|
+
});
|
|
648
728
|
const hash = annotated.representatives[INPUT_TYPE_NAME];
|
|
649
|
-
if (!hash)
|
|
729
|
+
if (!hash) {
|
|
730
|
+
throw new Error(
|
|
731
|
+
":input type expression did not produce a code hash"
|
|
732
|
+
);
|
|
733
|
+
}
|
|
650
734
|
state.codes = codes.dump();
|
|
651
735
|
return hash;
|
|
652
736
|
} catch (error) {
|
|
@@ -672,7 +756,10 @@ function resolvePatternExpression(state, patternExpr) {
|
|
|
672
756
|
patternExpr
|
|
673
757
|
].filter(Boolean).join("\n");
|
|
674
758
|
try {
|
|
675
|
-
const annotated = annotate(source, {
|
|
759
|
+
const annotated = annotate(source, {
|
|
760
|
+
libraries: [stateLibrary(state)],
|
|
761
|
+
patterns: state.patterns
|
|
762
|
+
});
|
|
676
763
|
const mainRel = annotated.rels.__main__;
|
|
677
764
|
if (!mainRel || !mainRel.typePatternGraph) {
|
|
678
765
|
throw new Error(`Invalid pattern expression '${patternExpr}'`);
|
|
@@ -771,6 +858,25 @@ function completeCommandArgument(line, state) {
|
|
|
771
858
|
const argStart = 1 + firstSpace + 1;
|
|
772
859
|
const arg = line.slice(argStart);
|
|
773
860
|
|
|
861
|
+
if (command === "pattern" || command === "pat") {
|
|
862
|
+
const trimmed = arg.trimStart();
|
|
863
|
+
const leadingWhitespace = arg.length - trimmed.length;
|
|
864
|
+
const prefix = line.slice(0, argStart + leadingWhitespace);
|
|
865
|
+
const names = Object.keys(state.patterns || {}).sort();
|
|
866
|
+
const matches = names
|
|
867
|
+
.filter((name) => name.startsWith(trimmed))
|
|
868
|
+
.map((name) => `${prefix}${name}`);
|
|
869
|
+
if (trimmed.startsWith("@")) {
|
|
870
|
+
for (const [name, p] of Object.entries(state.patterns || {})) {
|
|
871
|
+
const hash = resolvePatternCanonicalName(state, name, p);
|
|
872
|
+
if (hash && hash.startsWith(trimmed)) {
|
|
873
|
+
matches.push(`${prefix}${hash}`);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
return [matches, line];
|
|
878
|
+
}
|
|
879
|
+
|
|
774
880
|
if (command === "codec" || command === "codecs") {
|
|
775
881
|
return completeCodecCommand(line, argStart, arg, state);
|
|
776
882
|
}
|
|
@@ -877,7 +983,10 @@ function resolveKFilePath(filePath) {
|
|
|
877
983
|
if (fs.existsSync(strippedEx)) return strippedEx;
|
|
878
984
|
} catch {}
|
|
879
985
|
try {
|
|
880
|
-
const fromRepoStripped = path.resolve(
|
|
986
|
+
const fromRepoStripped = path.resolve(
|
|
987
|
+
path.dirname(fileURLToPath(import.meta.url)),
|
|
988
|
+
strippedEx
|
|
989
|
+
);
|
|
881
990
|
if (fs.existsSync(fromRepoStripped)) return fromRepoStripped;
|
|
882
991
|
} catch {}
|
|
883
992
|
return filePath;
|
|
@@ -908,7 +1017,8 @@ function loadSourceOrKlib(state, targetPath, options = {}) {
|
|
|
908
1017
|
const fullSource = [preamble, source].filter(Boolean).join("\n");
|
|
909
1018
|
const compileOptions = {
|
|
910
1019
|
source: targetPath,
|
|
911
|
-
libraries: [stateLibrary(state)]
|
|
1020
|
+
libraries: [stateLibrary(state)],
|
|
1021
|
+
patterns: state.patterns
|
|
912
1022
|
};
|
|
913
1023
|
try {
|
|
914
1024
|
const lib = compileWithOptionalIdentity(fullSource, compileOptions);
|
|
@@ -972,15 +1082,29 @@ function compileSnippetArtifacts(source, state, sourceName = "<repl>") {
|
|
|
972
1082
|
const fullSource = [preamble, source].filter(Boolean).join("\n");
|
|
973
1083
|
const options = {
|
|
974
1084
|
source: sourceName,
|
|
975
|
-
libraries: [stateLibrary(state)]
|
|
1085
|
+
libraries: [stateLibrary(state)],
|
|
1086
|
+
patterns: state.patterns
|
|
976
1087
|
};
|
|
977
1088
|
try {
|
|
978
1089
|
const lib = compileWithOptionalIdentity(fullSource, options);
|
|
979
|
-
const { relAlias, meta } = libraryOriginsFromSource(
|
|
1090
|
+
const { relAlias, meta } = libraryOriginsFromSource(
|
|
1091
|
+
source,
|
|
1092
|
+
fullSource,
|
|
1093
|
+
lib,
|
|
1094
|
+
options
|
|
1095
|
+
);
|
|
980
1096
|
const annotated = annotateWithOptionalIdentity(fullSource, options);
|
|
981
1097
|
return {
|
|
982
1098
|
annotated,
|
|
983
|
-
lib: {
|
|
1099
|
+
lib: {
|
|
1100
|
+
...lib,
|
|
1101
|
+
relAlias,
|
|
1102
|
+
meta,
|
|
1103
|
+
patterns: {
|
|
1104
|
+
...(state.patterns || {}),
|
|
1105
|
+
...(annotated.sourceDefs?.patterns || {})
|
|
1106
|
+
}
|
|
1107
|
+
},
|
|
984
1108
|
lineOffset: preambleLineCount(preamble)
|
|
985
1109
|
};
|
|
986
1110
|
} catch (error) {
|
|
@@ -1233,14 +1357,49 @@ async function evaluateCommand(line, state) {
|
|
|
1233
1357
|
case "rel": {
|
|
1234
1358
|
if (!arg) throw new Error(`${usagePrefix}rel requires a relation name`);
|
|
1235
1359
|
if (arg.includes("=")) {
|
|
1236
|
-
throw new Error(
|
|
1360
|
+
throw new Error(
|
|
1361
|
+
"Relation definitions use syntax: name = relExpr; " +
|
|
1362
|
+
"Use :rel <name> to show a relation definition"
|
|
1363
|
+
);
|
|
1237
1364
|
}
|
|
1238
1365
|
const { hash, rel } = resolveRel(state, arg);
|
|
1239
1366
|
if (!rel) throw new Error(`Unknown relation '${arg}'`);
|
|
1240
|
-
|
|
1367
|
+
const prettyRelStr = prettyRelation(
|
|
1368
|
+
rel,
|
|
1369
|
+
displayAliases(state),
|
|
1370
|
+
state.relAliases
|
|
1371
|
+
);
|
|
1372
|
+
return [`${arg} = ${prettyRelStr}; -- ${hash}`];
|
|
1241
1373
|
}
|
|
1242
1374
|
case "rels":
|
|
1243
1375
|
return [listAliases(state.relAliases)];
|
|
1376
|
+
case "pattern":
|
|
1377
|
+
case "pat": {
|
|
1378
|
+
if (!arg) {
|
|
1379
|
+
throw new Error(`${usagePrefix}pattern requires a pattern name`);
|
|
1380
|
+
}
|
|
1381
|
+
const rawName = arg.trim();
|
|
1382
|
+
let patternName = rawName.replace(/\[.*\]$/, "").trim();
|
|
1383
|
+
let pat = state.patterns?.[patternName];
|
|
1384
|
+
if (!pat && patternName.startsWith("@")) {
|
|
1385
|
+
for (const [name, p] of Object.entries(state.patterns || {})) {
|
|
1386
|
+
if (
|
|
1387
|
+
resolvePatternCanonicalName(state, name, p) === patternName
|
|
1388
|
+
) {
|
|
1389
|
+
patternName = name;
|
|
1390
|
+
pat = p;
|
|
1391
|
+
break;
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
if (!pat) {
|
|
1396
|
+
throw new Error(`Unknown pattern '${rawName}'`);
|
|
1397
|
+
}
|
|
1398
|
+
return [prettyPattern(patternName, pat, state)];
|
|
1399
|
+
}
|
|
1400
|
+
case "patterns":
|
|
1401
|
+
case "pats":
|
|
1402
|
+
return [listPatterns(state.patterns)];
|
|
1244
1403
|
case "codec":
|
|
1245
1404
|
case "codecs":
|
|
1246
1405
|
return loadCodec(arg, state);
|
|
@@ -1333,19 +1492,23 @@ function helpText() {
|
|
|
1333
1492
|
":engine [wasm|pkir|js] display or switch evaluation engine",
|
|
1334
1493
|
":rel name show relation definition",
|
|
1335
1494
|
":rels list relation aliases",
|
|
1495
|
+
":pattern name show named pattern definition (alias :pat)",
|
|
1496
|
+
":patterns list defined named patterns (alias :pats)",
|
|
1336
1497
|
":limit [num|none] set maximum characters for value output",
|
|
1337
|
-
":codec load file load a codec module from file
|
|
1498
|
+
":codec load file load a codec module from file",
|
|
1338
1499
|
":codec unload name unload a registered codec",
|
|
1339
1500
|
":codec list list loaded codecs (or simply :codecs)",
|
|
1340
|
-
":input <codec
|
|
1341
|
-
":load [--no-alias]
|
|
1342
|
-
" load .k source or .klib",
|
|
1501
|
+
":input <codec> [txt] parse input using specified codec",
|
|
1502
|
+
":load [--no-alias] f load .k source or .klib",
|
|
1343
1503
|
":klib file export state as a library",
|
|
1344
1504
|
":ko file expr export executable .ko using expr as main",
|
|
1345
1505
|
":reset clear state",
|
|
1346
1506
|
":help show this help",
|
|
1347
1507
|
"",
|
|
1348
|
-
"Raw k input
|
|
1508
|
+
"Raw k input:",
|
|
1509
|
+
" name = expr; define relation alias",
|
|
1510
|
+
" name[P1, ...] = filter; define named pattern template",
|
|
1511
|
+
" ? name[...] evaluate named pattern filter",
|
|
1349
1512
|
"A line ending with ';' plus only spaces closes the snippet.",
|
|
1350
1513
|
"Use '\\' to force continuation."
|
|
1351
1514
|
].join("\n");
|
|
@@ -1553,5 +1716,8 @@ export {
|
|
|
1553
1716
|
formatDuration,
|
|
1554
1717
|
codecNames,
|
|
1555
1718
|
ensureEnveloped,
|
|
1556
|
-
patternFromFilter
|
|
1719
|
+
patternFromFilter,
|
|
1720
|
+
prettyPattern,
|
|
1721
|
+
resolvePatternCanonicalName,
|
|
1722
|
+
listPatterns
|
|
1557
1723
|
};
|
|
@@ -78,8 +78,16 @@ if (fs.existsSync(coreKPath)) {
|
|
|
78
78
|
vfsFiles["core.k"] = fs.readFileSync(coreKPath, "utf8");
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
// Add verified k-code files
|
|
82
|
-
const verifiedExamples = [
|
|
81
|
+
// Add verified k-code files
|
|
82
|
+
const verifiedExamples = [
|
|
83
|
+
"arithmetics.k",
|
|
84
|
+
"ieee.k",
|
|
85
|
+
"poly.k",
|
|
86
|
+
"karatsuba-mult.k",
|
|
87
|
+
"djson.k",
|
|
88
|
+
"djson-btrie.k",
|
|
89
|
+
"djson-ptrie.k"
|
|
90
|
+
];
|
|
83
91
|
const examplesDir = path.join(projectRoot, "Examples");
|
|
84
92
|
for (const filename of verifiedExamples) {
|
|
85
93
|
const fullPath = path.join(examplesDir, filename);
|
|
@@ -94,6 +102,8 @@ for (const filename of verifiedExamples) {
|
|
|
94
102
|
const verifiedCodecs = [
|
|
95
103
|
"json.mjs",
|
|
96
104
|
"djson.mjs",
|
|
105
|
+
"djson-btrie.mjs",
|
|
106
|
+
"djson-ptrie.mjs",
|
|
97
107
|
"utf8.mjs",
|
|
98
108
|
"int.mjs",
|
|
99
109
|
"unit.mjs",
|
|
@@ -645,6 +655,12 @@ const htmlContent = `<!DOCTYPE html>
|
|
|
645
655
|
text-overflow: ellipsis;
|
|
646
656
|
white-space: nowrap;
|
|
647
657
|
flex: 1;
|
|
658
|
+
min-width: 0;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.k-btn-copy {
|
|
662
|
+
flex-shrink: 0;
|
|
663
|
+
margin-left: auto;
|
|
648
664
|
}
|
|
649
665
|
|
|
650
666
|
.k-tree-section-body {
|
|
@@ -1681,6 +1697,9 @@ const htmlContent = `<!DOCTYPE html>
|
|
|
1681
1697
|
<option value="ieee.k">ieee.k</option>
|
|
1682
1698
|
<option value="poly.k">poly.k</option>
|
|
1683
1699
|
<option value="karatsuba-mult.k">karatsuba-mult.k</option>
|
|
1700
|
+
<option value="djson.k">djson.k</option>
|
|
1701
|
+
<option value="djson-btrie.k">djson-btrie.k</option>
|
|
1702
|
+
<option value="djson-ptrie.k">djson-ptrie.k</option>
|
|
1684
1703
|
</optgroup>
|
|
1685
1704
|
<optgroup label="Quick Expressions">
|
|
1686
1705
|
<option value="expr:{} | ok">{} | ok</option>
|
|
@@ -1700,9 +1719,15 @@ const htmlContent = `<!DOCTYPE html>
|
|
|
1700
1719
|
<option value="expr::codec load int.mjs">:codec load int.mjs</option>
|
|
1701
1720
|
<option value="expr::codec load utf8.mjs">:codec load utf8.mjs</option>
|
|
1702
1721
|
<option value="expr::codec load json.mjs">:codec load json.mjs</option>
|
|
1722
|
+
<option value="expr::codec load djson.mjs">:codec load djson.mjs</option>
|
|
1723
|
+
<option value="expr::codec load djson-btrie.mjs">:codec load djson-btrie.mjs</option>
|
|
1724
|
+
<option value="expr::codec load djson-ptrie.mjs">:codec load djson-ptrie.mjs</option>
|
|
1703
1725
|
<option value="expr::codec load ieee.mjs">:codec load ieee.mjs</option>
|
|
1704
1726
|
<option value="expr::codec load unit.mjs">:codec load unit.mjs</option>
|
|
1705
1727
|
<option value="expr::input json.mjs {"a":12,"b":"hello"}">:input json.mjs {"a":12,"b":"hello"}</option>
|
|
1728
|
+
<option value="expr::input djson.mjs {"a":12,"b":"hello"}">:input djson.mjs {"a":12,"b":"hello"}</option>
|
|
1729
|
+
<option value="expr::input djson-btrie.mjs {"a":12,"b":"hello"}">:input djson-btrie.mjs {"a":12,"b":"hello"}</option>
|
|
1730
|
+
<option value="expr::input djson-ptrie.mjs {"a":12,"b":"hello"}">:input djson-ptrie.mjs {"a":12,"b":"hello"}</option>
|
|
1706
1731
|
<option value="expr::input int.mjs [0,1,2]">:input int.mjs [0,1,2]</option>
|
|
1707
1732
|
</optgroup>
|
|
1708
1733
|
</select>
|
|
@@ -1837,6 +1862,16 @@ const htmlContent = `<!DOCTYPE html>
|
|
|
1837
1862
|
<td><code>name = relExpr;</code></td>
|
|
1838
1863
|
<td><b>Relation Alias:</b> Defines a local alias for a relation expression.<br><i>e.g.</i> <code>swap = { . y x, . x y };</code></td>
|
|
1839
1864
|
</tr>
|
|
1865
|
+
<tr>
|
|
1866
|
+
<td><code>name[P1, ..., Pn] = filter;</code></td>
|
|
1867
|
+
<td>
|
|
1868
|
+
<b>Named Pattern Template:</b> Defines a reusable
|
|
1869
|
+
pattern template.<br>
|
|
1870
|
+
<i>e.g.</i><br>
|
|
1871
|
+
<code>bit[] = < {} 0, {} 1 >;</code> or<br>
|
|
1872
|
+
<code>list[X] = < {} nil, ... > = Y;</code>
|
|
1873
|
+
</td>
|
|
1874
|
+
</tr>
|
|
1840
1875
|
</tbody>
|
|
1841
1876
|
</table>
|
|
1842
1877
|
|
|
@@ -1872,8 +1907,15 @@ const htmlContent = `<!DOCTYPE html>
|
|
|
1872
1907
|
<td><b>Variant Constructor:</b> Wraps document into variant <code>tag</code></td>
|
|
1873
1908
|
</tr>
|
|
1874
1909
|
<tr>
|
|
1875
|
-
<td
|
|
1876
|
-
|
|
1910
|
+
<td>
|
|
1911
|
+
<code>? filterExpr</code> /
|
|
1912
|
+
<code>? name[...]</code>
|
|
1913
|
+
</td>
|
|
1914
|
+
<td>
|
|
1915
|
+
<b>Pattern Filter:</b> Asserts input matches pattern;
|
|
1916
|
+
acts as partial identity and inductive witness
|
|
1917
|
+
(<i>e.g.</i> <code>? list[X]</code>)
|
|
1918
|
+
</td>
|
|
1877
1919
|
</tr>
|
|
1878
1920
|
<tr>
|
|
1879
1921
|
<td><code>name</code> / <code>@hash</code></td>
|
|
@@ -1888,6 +1930,20 @@ const htmlContent = `<!DOCTYPE html>
|
|
|
1888
1930
|
<table class="help-table">
|
|
1889
1931
|
<tr><td><code>:engine [wasm|pkir|js]</code></td><td>Display or switch evaluation engine (<code>wasm</code>, <code>pkir</code>, or <code>js</code>)</td></tr>
|
|
1890
1932
|
<tr><td><code>:load <file></code></td><td>Load a <code>.k</code> source or <code>.klib</code> library into current state</td></tr>
|
|
1933
|
+
<tr>
|
|
1934
|
+
<td><code>:pattern <name></code></td>
|
|
1935
|
+
<td>
|
|
1936
|
+
Display definition of named pattern
|
|
1937
|
+
<code><name></code> (alias <code>:pat</code>)
|
|
1938
|
+
</td>
|
|
1939
|
+
</tr>
|
|
1940
|
+
<tr>
|
|
1941
|
+
<td><code>:patterns</code></td>
|
|
1942
|
+
<td>
|
|
1943
|
+
List defined named pattern templates
|
|
1944
|
+
(alias <code>:pats</code>)
|
|
1945
|
+
</td>
|
|
1946
|
+
</tr>
|
|
1891
1947
|
<tr><td><code>:rel <name></code></td><td>Display definition of relation <code><name></code></td></tr>
|
|
1892
1948
|
<tr><td><code>:rels</code></td><td>List all relation aliases</td></tr>
|
|
1893
1949
|
<tr><td><code>:codecs</code></td><td>List all loaded format codecs</td></tr>
|
|
@@ -1908,6 +1964,14 @@ const htmlContent = `<!DOCTYPE html>
|
|
|
1908
1964
|
<li><code>not = < / true | false, / false | true >;</code> — Polymorphic negation via branch projections and ordered choice</li>
|
|
1909
1965
|
<li><code>{} | true not</code> — Compose constant relation <code>{} | true</code> with <code>not</code> (evaluates to <code>{} | false</code>)</li>
|
|
1910
1966
|
<li><code>bool? = ?< {} true, {} false >;</code> — Define a boolean pattern filter relation</li>
|
|
1967
|
+
<li>
|
|
1968
|
+
<code>bit[] = < {} 0, {} 1 >;</code>
|
|
1969
|
+
— Define a 0-arity bit pattern
|
|
1970
|
+
</li>
|
|
1971
|
+
<li>
|
|
1972
|
+
<code>? list[bool[]]</code>
|
|
1973
|
+
— Instantiated pattern filter matching booleans
|
|
1974
|
+
</li>
|
|
1911
1975
|
<li><code>not = bool? ?X < / true | false, {} | true > ?X;</code> — Filtered boolean negation: guarded by <code>bool?</code>, defaulting to <code>{} | true</code></li>
|
|
1912
1976
|
<li><code>swap = { . y x, . x y };</code> — Define a product field-swapping relation</li>
|
|
1913
1977
|
<li><code>{ {} | ok x, {} | nil y } swap</code> — Construct a product and pass it through <code>swap</code></li>
|