@fraczak/k 6.3.3 → 6.4.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/DOCS/CODECS.md +258 -0
- package/DOCS/DICTIONARY.md +1172 -0
- package/DOCS/KIR_SPECIALIZATION_DESIGN.md +51 -46
- package/DOCS/KIR_V1.md +221 -0
- package/DOCS/KVM_EXECUTION_MODEL.md +56 -19
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +2 -1
- package/DOCS/PROFILING_AND_TRACING.md +196 -0
- package/DOCS/REPL.md +61 -4
- package/DOCS/WEB_REPL_REQUIREMENTS.md +135 -0
- package/DOCS/dependency-graph.md +144 -0
- package/Examples/arithmetics.k +51 -48
- package/Examples/bnat.k +1 -1
- package/Examples/buda.k +44 -0
- package/Examples/ieee.k +300 -8671
- package/Examples/poly.k +67 -0
- package/README.md +68 -19
- package/augmentation.mjs +9 -7
- package/backend-api.mjs +11 -2
- package/backends/arm64/README.md +104 -0
- package/backends/arm64/bin/k-arm64-compile.mjs +101 -0
- package/backends/arm64/bin/k-arm64-run.mjs +58 -0
- package/backends/arm64/bin/k-arm64.mjs +88 -0
- package/backends/arm64/scripts/run-tests.mjs +41 -0
- package/backends/arm64/src/arm64.mjs +229 -0
- package/backends/arm64/src/cli.mjs +155 -0
- package/backends/arm64/src/kvm2arm64.mjs +906 -0
- package/backends/arm64/src/runtime.c +728 -0
- package/backends/arm64/tests/integration.sh +112 -0
- package/backends/arm64/tests/test-arm64.mjs +240 -0
- package/backends/llvm/README.md +135 -0
- package/backends/llvm/bin/k-llvm-build.mjs +71 -0
- package/backends/llvm/bin/k-llvm-compile.mjs +68 -0
- package/backends/llvm/bin/k-llvm-jit.mjs +160 -0
- package/backends/llvm/bin/k-llvm-run.mjs +90 -0
- package/backends/llvm/runtime/krt.c +1508 -0
- package/backends/llvm/runtime/krt.h +109 -0
- package/backends/llvm/scripts/conformance.mjs +76 -0
- package/backends/llvm/scripts/run-tests.mjs +28 -0
- package/backends/llvm/src/executable.mjs +562 -0
- package/backends/llvm/src/kvm2llvm.mjs +998 -0
- package/backends/llvm/src/llvm.mjs +1092 -0
- package/backends/llvm/tests/composition-driver.c +22 -0
- package/backends/llvm/tests/identity-driver.c +27 -0
- package/backends/llvm/tests/integration.sh +153 -0
- package/backends/llvm/tests/perf-support.mjs +735 -0
- package/backends/llvm/tests/product-driver.c +23 -0
- package/backends/llvm/tests/projection-driver.c +19 -0
- package/backends/llvm/tests/relation-driver.c +29 -0
- package/backends/llvm/tests/test-llvm.mjs +240 -0
- package/backends/llvm/tests/union-driver.c +31 -0
- package/backends/llvm/tests/variant-driver.c +19 -0
- package/backends/llvm/tests/variant-projection-driver.c +21 -0
- package/backends/wasm/DOCS/USE-WEB-ASSEMBLY.md +233 -0
- package/backends/wasm/README.md +97 -0
- package/backends/wasm/TECHNICAL-DEBT.md +60 -0
- package/backends/wasm/bin/k-wasm-compile.mjs +50 -0
- package/backends/wasm/bin/k-wasm-run.mjs +140 -0
- package/backends/wasm/bin/k-wasm.mjs +49 -0
- package/backends/wasm/demo_ieee.mjs +319 -0
- package/backends/wasm/runtime.wat +102 -0
- package/backends/wasm/scripts/run-tests.mjs +41 -0
- package/backends/wasm/src/cli.mjs +133 -0
- package/backends/wasm/src/kvm2wasm.mjs +661 -0
- package/backends/wasm/src/wasm.mjs +1010 -0
- package/backends/wasm/tests/integration.sh +182 -0
- package/backends/wasm/tests/perf-support.mjs +336 -0
- package/backends/wasm/tests/test-wasm.mjs +617 -0
- package/browser/repl-browser.mjs +1584 -0
- package/browser/shims/assert.mjs +19 -0
- package/browser/shims/buffer.mjs +224 -0
- package/browser/shims/crypto.mjs +103 -0
- package/browser/shims/fs.mjs +159 -0
- package/browser/shims/os.mjs +17 -0
- package/browser/shims/path.mjs +54 -0
- package/browser/shims/process.mjs +44 -0
- package/browser/shims/readline.mjs +11 -0
- package/browser/shims/url.mjs +12 -0
- package/browser/vfs-data.mjs +19 -0
- package/codecs/README.md +3 -0
- package/codecs/runtime/show-value.mjs +2 -2
- package/conformance/helper-reuse/case.json +8 -0
- package/conformance/helper-reuse/expected.kv +1 -0
- package/conformance/helper-reuse/input.kv +1 -0
- package/conformance/helper-reuse/program.k +2 -0
- package/conformance/identity/case.json +8 -0
- package/conformance/identity/expected.kv +1 -0
- package/conformance/identity/input.kv +1 -0
- package/conformance/identity/program.k +1 -0
- package/conformance/product-projection/case.json +8 -0
- package/conformance/product-projection/expected.kv +1 -0
- package/conformance/product-projection/input.kv +1 -0
- package/conformance/product-projection/program.k +1 -0
- package/conformance/run.mjs +149 -0
- package/conformance/variant-construction/case.json +8 -0
- package/conformance/variant-construction/expected.kv +1 -0
- package/conformance/variant-construction/input.kv +1 -0
- package/conformance/variant-construction/program.k +1 -0
- package/harness/adapters/arm64.mjs +105 -0
- package/harness/adapters/kvm.mjs +144 -0
- package/harness/adapters/llvm.mjs +118 -0
- package/harness/adapters/native.mjs +77 -0
- package/harness/adapters/wasm.mjs +169 -0
- package/harness/backend.mjs +95 -0
- package/harness/cli.mjs +130 -0
- package/harness/format.mjs +95 -0
- package/harness/index.mjs +25 -0
- package/harness/persistent.mjs +121 -0
- package/harness/registry.mjs +44 -0
- package/harness/suite.mjs +257 -0
- package/harness/suites/poly.mjs +156 -0
- package/harness/trace.mjs +50 -0
- package/harness/util.mjs +92 -0
- package/intrinsics.mjs +41 -0
- package/kir.mjs +399 -0
- package/kvm.mjs +585 -81
- package/objects/README.md +37 -3
- package/objects/compile.mjs +15 -22
- package/objects/inspect.mjs +96 -0
- package/objects/validate.mjs +415 -0
- package/package.json +51 -19
- package/repl-codecs.mjs +105 -6
- package/repl.mjs +335 -49
- package/run.mjs +2 -7
- package/scripts/benchmark.mjs +406 -22
- package/scripts/build-repl-html.mjs +1784 -0
- package/scripts/perf-ieee.mjs +586 -0
- package/scripts/perf-int.mjs +531 -0
- package/scripts/perf-poly.mjs +945 -0
- package/scripts/render-benchmark.mjs +12 -8
- package/scripts/run-tests.mjs +6 -0
- package/tests/integration.sh +19 -2
- package/tests/test-arithmetics.mjs +54 -0
- package/tests/test-ieee-arithmetic.mjs +4 -0
- package/tests/test-kir.mjs +85 -0
- package/tests/test-kvm-polymorphic.mjs +278 -0
- package/tests/test-kvm.mjs +25 -6
- package/tests/test-poly.mjs +129 -0
- package/tests/test-repl-html.mjs +303 -0
- package/tests/test-repl.mjs +144 -1
- package/tests/test-validate-object.mjs +40 -0
- package/a.klib +0 -1
- package/a.kvm +0 -142676
- package/a.wasm +0 -0
- package/benchmark-results.html +0 -532
- package/benchmark-results.json +0 -480
- package/k-vscode/.vscode/launch.json +0 -14
- package/k-vscode/README.md +0 -75
- package/k-vscode/extension.js +0 -273
- package/k-vscode/language-configuration.json +0 -42
- package/k-vscode/package.json +0 -79
- package/k-vscode/snippets/k.json +0 -92
- package/k-vscode/syntaxes/k.tmLanguage.json +0 -599
- package/k-vscode/test/background-ranges.test.js +0 -50
- package/k-vscode/themes/k-contrast-color-theme.json +0 -104
- package/scripts/git-hooks/pre-commit +0 -10
package/repl.mjs
CHANGED
|
@@ -8,9 +8,17 @@ import { fileURLToPath } from "node:url";
|
|
|
8
8
|
import { argv, exit, stdin, stdout } from "node:process";
|
|
9
9
|
|
|
10
10
|
import { annotate, parse } from "./index.mjs";
|
|
11
|
-
import
|
|
11
|
+
import { constrainWithPattern } from "./run.mjs";
|
|
12
|
+
import { compileWasmArtifactFromObject, instantiateWasmArtifact } from "./backends/wasm/src/wasm.mjs";
|
|
13
|
+
import { exportPatternGraph } from "./codecs/runtime/codec.mjs";
|
|
14
|
+
import { patternToPropertyList } from "./codecs/runtime/pattern-json.mjs";
|
|
12
15
|
import codes from "./codes.mjs";
|
|
13
|
-
import { Value } from "./Value.mjs";
|
|
16
|
+
import { Value, isProduct, isVariant } from "./Value.mjs";
|
|
17
|
+
if (typeof globalThis !== "undefined") {
|
|
18
|
+
globalThis.Value = Value;
|
|
19
|
+
globalThis.isProduct = isProduct;
|
|
20
|
+
globalThis.isVariant = isVariant;
|
|
21
|
+
}
|
|
14
22
|
import { patterns2filters, prettyCode, prettyRel } from "./pretty.mjs";
|
|
15
23
|
import {
|
|
16
24
|
compileObject,
|
|
@@ -28,7 +36,11 @@ import {
|
|
|
28
36
|
codeHashToPattern,
|
|
29
37
|
listCodecs,
|
|
30
38
|
loadCodecModule,
|
|
39
|
+
normalizeCodecModule,
|
|
40
|
+
registerCodec,
|
|
31
41
|
resolveCodec,
|
|
42
|
+
unregisterCodec,
|
|
43
|
+
BUILTIN_CODECS,
|
|
32
44
|
closedPatternToCodeHash,
|
|
33
45
|
UNIVERSAL_CODE,
|
|
34
46
|
valueForCode
|
|
@@ -39,14 +51,22 @@ const TYPE_DEF_RE = /^\s*\$\s*([a-zA-Z0-9_+-][a-zA-Z0-9_?!+-]*)\s*=/;
|
|
|
39
51
|
const REL_DEF_RE = /^\s*([a-zA-Z0-9_+-][a-zA-Z0-9_?!+-]*)\s*=/;
|
|
40
52
|
const COMMAND_NAMES = [
|
|
41
53
|
"help", "type", "code", "rel", "def", "run", "eval", "t", "d", "C",
|
|
42
|
-
"codes", "rels", "val", "codec", "input", "reset", "klib", "ko", "load",
|
|
54
|
+
"codes", "codecs", "rels", "val", "codec", "input", "reset", "klib", "ko", "load",
|
|
55
|
+
"timing", "time",
|
|
43
56
|
"quit", "exit"
|
|
44
57
|
];
|
|
45
|
-
const CODEC_COMMAND_NAMES = ["load", "list"];
|
|
58
|
+
const CODEC_COMMAND_NAMES = ["load", "unload", "list", "define"];
|
|
46
59
|
const PATH_COMMANDS = new Set(["klib", "ko", "load"]);
|
|
47
60
|
const INPUT_TYPE_NAME = "__input__";
|
|
48
61
|
const initialCodes = codes.dump();
|
|
49
62
|
|
|
63
|
+
function formatDuration(ms) {
|
|
64
|
+
if (ms < 1000) {
|
|
65
|
+
return `${ms < 10 ? ms.toFixed(1) : Math.round(ms)}ms`;
|
|
66
|
+
}
|
|
67
|
+
return `${(ms / 1000).toFixed(2)}s`;
|
|
68
|
+
}
|
|
69
|
+
|
|
50
70
|
function cloneJSON(value) {
|
|
51
71
|
return JSON.parse(JSON.stringify(value));
|
|
52
72
|
}
|
|
@@ -63,10 +83,13 @@ function createState() {
|
|
|
63
83
|
relAliases: {},
|
|
64
84
|
typeAliases: {},
|
|
65
85
|
codecs: {},
|
|
86
|
+
loadedFiles: new Set(),
|
|
66
87
|
pendingInput: null,
|
|
67
88
|
meta: {},
|
|
68
89
|
value: emptyValue(),
|
|
69
|
-
lastMain: null
|
|
90
|
+
lastMain: null,
|
|
91
|
+
lastTiming: null,
|
|
92
|
+
showTiming: false
|
|
70
93
|
};
|
|
71
94
|
}
|
|
72
95
|
|
|
@@ -211,6 +234,16 @@ function mergeLibrary(state, lib, source = "<load>", options = {}) {
|
|
|
211
234
|
}
|
|
212
235
|
}
|
|
213
236
|
recoverAliasesFromMeta(state, lib);
|
|
237
|
+
if (state.typeAliases.string && !state.typeAliases.utf8) {
|
|
238
|
+
state.typeAliases.utf8 = state.typeAliases.string;
|
|
239
|
+
} else if (state.typeAliases.utf8 && !state.typeAliases.string) {
|
|
240
|
+
state.typeAliases.string = state.typeAliases.utf8;
|
|
241
|
+
}
|
|
242
|
+
if (state.typeAliases.float64 && !state.typeAliases.ieee) {
|
|
243
|
+
state.typeAliases.ieee = state.typeAliases.float64;
|
|
244
|
+
} else if (state.typeAliases.ieee && !state.typeAliases.float64) {
|
|
245
|
+
state.typeAliases.float64 = state.typeAliases.ieee;
|
|
246
|
+
}
|
|
214
247
|
}
|
|
215
248
|
restoreCodes(state);
|
|
216
249
|
}
|
|
@@ -597,15 +630,33 @@ function codecLoadPathCompletionStart(argStart, arg) {
|
|
|
597
630
|
return argStart + leading.length + "load".length + 1 + restLeadingWhitespace + completionTokenStart(rest.trimStart());
|
|
598
631
|
}
|
|
599
632
|
|
|
600
|
-
function completeCodecCommand(line, argStart, arg) {
|
|
633
|
+
function completeCodecCommand(line, argStart, arg, state) {
|
|
601
634
|
const trimmed = arg.trimStart();
|
|
602
635
|
if (trimmed === "" || !/\s/.test(trimmed)) {
|
|
603
636
|
return completeCommandWord(line, argStart, arg, CODEC_COMMAND_NAMES);
|
|
604
637
|
}
|
|
605
638
|
|
|
639
|
+
const unloadMatch = arg.match(/^(\s*)unload(?:\s+(.*))?$/);
|
|
640
|
+
if (unloadMatch) {
|
|
641
|
+
const [, leading, partial = ""] = unloadMatch;
|
|
642
|
+
const prefix = line.slice(0, argStart + leading.length + "unload".length + 1);
|
|
643
|
+
const names = state ? codecNames(state) : [];
|
|
644
|
+
const matches = names
|
|
645
|
+
.filter((name) => name.startsWith(partial.trim()))
|
|
646
|
+
.map((name) => `${prefix}${name}`);
|
|
647
|
+
return [matches, line];
|
|
648
|
+
}
|
|
649
|
+
|
|
606
650
|
const tokenStart = codecLoadPathCompletionStart(argStart, arg);
|
|
607
651
|
if (tokenStart == null) return [[], line];
|
|
608
|
-
|
|
652
|
+
const [pathMatches] = completePath(line, tokenStart);
|
|
653
|
+
const match = arg.match(/^(\s*)load(?:\s+(.*))?$/);
|
|
654
|
+
const partial = match && match[2] != null ? match[2].trim() : "";
|
|
655
|
+
const prefix = line.slice(0, tokenStart);
|
|
656
|
+
const builtinMatches = ["int", "utf8", "json", "ieee"]
|
|
657
|
+
.filter((name) => name.startsWith(partial))
|
|
658
|
+
.map((name) => `${prefix}${name}`);
|
|
659
|
+
return [[...builtinMatches, ...pathMatches], line];
|
|
609
660
|
}
|
|
610
661
|
|
|
611
662
|
function resolveTypeHash(state, rawName) {
|
|
@@ -689,8 +740,8 @@ function completeCommandArgument(line, state) {
|
|
|
689
740
|
const argStart = 1 + firstSpace + 1;
|
|
690
741
|
const arg = line.slice(argStart);
|
|
691
742
|
|
|
692
|
-
if (command === "codec") {
|
|
693
|
-
return completeCodecCommand(line, argStart, arg);
|
|
743
|
+
if (command === "codec" || command === "codecs") {
|
|
744
|
+
return completeCodecCommand(line, argStart, arg, state);
|
|
694
745
|
}
|
|
695
746
|
|
|
696
747
|
if (command === "input") {
|
|
@@ -766,6 +817,102 @@ function parseLoadArgs(arg, usagePrefix = ":") {
|
|
|
766
817
|
return { path: arg.trim(), loadAliases: true };
|
|
767
818
|
}
|
|
768
819
|
|
|
820
|
+
const CODEC_FILES = {
|
|
821
|
+
int: "arithmetics.k",
|
|
822
|
+
utf8: "core.k",
|
|
823
|
+
json: "core.k",
|
|
824
|
+
ieee: "ieee.k",
|
|
825
|
+
unit: "core.k"
|
|
826
|
+
};
|
|
827
|
+
|
|
828
|
+
function normalizeFilePath(p) {
|
|
829
|
+
return p.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
function resolveKFilePath(filePath) {
|
|
833
|
+
try {
|
|
834
|
+
if (fs.existsSync(filePath)) return filePath;
|
|
835
|
+
} catch {}
|
|
836
|
+
try {
|
|
837
|
+
const fromRepo = path.resolve(path.dirname(fileURLToPath(import.meta.url)), filePath);
|
|
838
|
+
if (fs.existsSync(fromRepo)) return fromRepo;
|
|
839
|
+
} catch {}
|
|
840
|
+
const withEx = filePath.startsWith("Examples/") ? filePath : `Examples/${filePath}`;
|
|
841
|
+
try {
|
|
842
|
+
if (fs.existsSync(withEx)) return withEx;
|
|
843
|
+
} catch {}
|
|
844
|
+
try {
|
|
845
|
+
const fromRepoEx = path.resolve(path.dirname(fileURLToPath(import.meta.url)), withEx);
|
|
846
|
+
if (fs.existsSync(fromRepoEx)) return fromRepoEx;
|
|
847
|
+
} catch {}
|
|
848
|
+
const strippedEx = filePath.startsWith("Examples/") ? filePath.slice("Examples/".length) : filePath;
|
|
849
|
+
try {
|
|
850
|
+
if (fs.existsSync(strippedEx)) return strippedEx;
|
|
851
|
+
} catch {}
|
|
852
|
+
try {
|
|
853
|
+
const fromRepoStripped = path.resolve(path.dirname(fileURLToPath(import.meta.url)), strippedEx);
|
|
854
|
+
if (fs.existsSync(fromRepoStripped)) return fromRepoStripped;
|
|
855
|
+
} catch {}
|
|
856
|
+
return filePath;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
function loadSourceOrKlib(state, targetPath, options = {}) {
|
|
860
|
+
const loadAliases = options.loadAliases ?? true;
|
|
861
|
+
const normKey = normalizeFilePath(targetPath);
|
|
862
|
+
if (!state.loadedFiles) state.loadedFiles = new Set();
|
|
863
|
+
|
|
864
|
+
// If loading poly.k, auto-load arithmetics.k first if not already loaded
|
|
865
|
+
if (normKey === "Examples/poly.k" || normKey.endsWith("/poly.k") || normKey === "poly.k") {
|
|
866
|
+
const arithKey = "arithmetics.k";
|
|
867
|
+
const alreadyHasArith = Array.from(state.loadedFiles).some(f => path.basename(f) === "arithmetics.k");
|
|
868
|
+
if (!alreadyHasArith) {
|
|
869
|
+
loadSourceOrKlib(state, arithKey, { loadAliases });
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
const loadPath = resolveKFilePath(targetPath);
|
|
874
|
+
if (loadPath.endsWith(".klib")) {
|
|
875
|
+
const lib = loadLibrary(decodeLibrary(fs.readFileSync(loadPath)));
|
|
876
|
+
mergeLibrary(state, lib, targetPath, { loadAliases });
|
|
877
|
+
} else {
|
|
878
|
+
restoreCodes(state);
|
|
879
|
+
const source = fs.readFileSync(loadPath, "utf8");
|
|
880
|
+
const preamble = aliasPreamble(state);
|
|
881
|
+
const fullSource = [preamble, source].filter(Boolean).join("\n");
|
|
882
|
+
const compileOptions = {
|
|
883
|
+
source: targetPath,
|
|
884
|
+
libraries: [stateLibrary(state)]
|
|
885
|
+
};
|
|
886
|
+
try {
|
|
887
|
+
const lib = compileWithOptionalIdentity(fullSource, compileOptions);
|
|
888
|
+
const { relAlias, meta } = libraryOriginsFromSource(source, fullSource, lib, compileOptions);
|
|
889
|
+
mergeLibrary(state, { ...lib, relAlias, meta }, targetPath, { loadAliases });
|
|
890
|
+
} catch (error) {
|
|
891
|
+
throw remapError(error, preambleLineCount(preamble));
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
state.loadedFiles.add(normKey);
|
|
895
|
+
return targetPath;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
function ensureCodecDependencies(state, codecTarget) {
|
|
899
|
+
const norm = normalizeFilePath(codecTarget).toLowerCase();
|
|
900
|
+
const base = path.basename(norm, path.extname(norm));
|
|
901
|
+
const depFile = CODEC_FILES[base] || CODEC_FILES[norm];
|
|
902
|
+
if (!depFile) return null;
|
|
903
|
+
if (!state.loadedFiles) state.loadedFiles = new Set();
|
|
904
|
+
const depNormKey = normalizeFilePath(depFile);
|
|
905
|
+
const baseName = path.basename(depNormKey);
|
|
906
|
+
const alreadyLoaded = state.loadedFiles.has(depNormKey) ||
|
|
907
|
+
state.loadedFiles.has(`Examples/${depNormKey}`) ||
|
|
908
|
+
Array.from(state.loadedFiles).some(f => path.basename(f) === baseName);
|
|
909
|
+
if (!alreadyLoaded) {
|
|
910
|
+
loadSourceOrKlib(state, depFile);
|
|
911
|
+
return depFile;
|
|
912
|
+
}
|
|
913
|
+
return null;
|
|
914
|
+
}
|
|
915
|
+
|
|
769
916
|
function lineForContinuation(line) {
|
|
770
917
|
return line.replace(/\\\s*$/, "");
|
|
771
918
|
}
|
|
@@ -883,29 +1030,82 @@ async function defineRelation(input, state) {
|
|
|
883
1030
|
return [`${name} = ${hash}`];
|
|
884
1031
|
}
|
|
885
1032
|
|
|
1033
|
+
async function executeExpressionWithWasm(annotated, state, lineOffset = 0) {
|
|
1034
|
+
const mainRel = annotated.rels.__main__;
|
|
1035
|
+
if (!mainRel) return { result: undefined, wasmCompileMs: 0, executeMs: 0 };
|
|
1036
|
+
|
|
1037
|
+
let inputValue = state.value ?? emptyValue();
|
|
1038
|
+
if (mainRel.typePatternGraph && mainRel.def.patterns) {
|
|
1039
|
+
const graph = mainRel.typePatternGraph;
|
|
1040
|
+
const nodeId = graph.find(mainRel.def.patterns[0]);
|
|
1041
|
+
const inputPattern = patternToPropertyList(exportPatternGraph(graph, nodeId));
|
|
1042
|
+
inputValue = constrainWithPattern(inputValue, inputPattern, mainRel.def);
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
const obj = {
|
|
1046
|
+
format: "k-object",
|
|
1047
|
+
codes: { ...state.codes, ...codes.dump() },
|
|
1048
|
+
rels: annotated.rels,
|
|
1049
|
+
relAlias: annotated.relAlias,
|
|
1050
|
+
compileStats: annotated.compileStats,
|
|
1051
|
+
main: "__main__"
|
|
1052
|
+
};
|
|
1053
|
+
|
|
1054
|
+
const wasmCompileStart = performance.now();
|
|
1055
|
+
const wasmBytes = await compileWasmArtifactFromObject(obj, {
|
|
1056
|
+
inputEnvelopePattern: inputValue?.pattern
|
|
1057
|
+
});
|
|
1058
|
+
const runner = await instantiateWasmArtifact(wasmBytes);
|
|
1059
|
+
const wasmCompileMs = performance.now() - wasmCompileStart;
|
|
1060
|
+
|
|
1061
|
+
const executeStart = performance.now();
|
|
1062
|
+
const result = runner.executeValue(inputValue);
|
|
1063
|
+
const executeMs = performance.now() - executeStart;
|
|
1064
|
+
|
|
1065
|
+
return { result, wasmCompileMs, executeMs };
|
|
1066
|
+
}
|
|
1067
|
+
|
|
886
1068
|
async function runExpression(input, state) {
|
|
887
1069
|
const expression = input.trim();
|
|
888
1070
|
if (!expression) throw new Error(":run requires an expression");
|
|
889
1071
|
|
|
890
1072
|
restoreCodes(state);
|
|
891
1073
|
const preamble = aliasPreamble(state);
|
|
1074
|
+
const lineOffset = preambleLineCount(preamble);
|
|
892
1075
|
const source = [preamble, expression].filter(Boolean).join("\n");
|
|
1076
|
+
const compileStart = performance.now();
|
|
893
1077
|
let annotated;
|
|
894
1078
|
try {
|
|
895
1079
|
annotated = annotate(source, { libraries: [stateLibrary(state)] });
|
|
896
1080
|
} catch (error) {
|
|
897
|
-
throw remapError(error,
|
|
1081
|
+
throw remapError(error, lineOffset);
|
|
898
1082
|
}
|
|
899
|
-
const
|
|
900
|
-
|
|
901
|
-
let
|
|
1083
|
+
const snippetCompileMs = performance.now() - compileStart;
|
|
1084
|
+
|
|
1085
|
+
let execRes;
|
|
902
1086
|
try {
|
|
903
|
-
|
|
1087
|
+
execRes = await executeExpressionWithWasm(annotated, state, lineOffset);
|
|
904
1088
|
} catch (error) {
|
|
905
|
-
throw remapError(error,
|
|
1089
|
+
throw remapError(error, lineOffset);
|
|
906
1090
|
}
|
|
1091
|
+
state.codes = codes.dump();
|
|
907
1092
|
restoreCodes(state);
|
|
908
|
-
|
|
1093
|
+
|
|
1094
|
+
const compileMs = snippetCompileMs + execRes.wasmCompileMs;
|
|
1095
|
+
const executeMs = execRes.executeMs;
|
|
1096
|
+
state.lastTiming = {
|
|
1097
|
+
compileMs,
|
|
1098
|
+
executeMs,
|
|
1099
|
+
totalMs: compileMs + executeMs,
|
|
1100
|
+
snippetCompileMs,
|
|
1101
|
+
wasmCompileMs: execRes.wasmCompileMs
|
|
1102
|
+
};
|
|
1103
|
+
|
|
1104
|
+
const committed = commitResult(state, execRes.result, expression);
|
|
1105
|
+
if (state.showTiming) {
|
|
1106
|
+
committed.push(`/* comp: ${formatDuration(compileMs)}, exec: ${formatDuration(executeMs)} */`);
|
|
1107
|
+
}
|
|
1108
|
+
return committed;
|
|
909
1109
|
}
|
|
910
1110
|
|
|
911
1111
|
async function runSnippet(input, state, options = {}) {
|
|
@@ -914,42 +1114,107 @@ async function runSnippet(input, state, options = {}) {
|
|
|
914
1114
|
|
|
915
1115
|
const explicitTerminated = options.explicitTerminated ?? explicitSnippetTerminated(input);
|
|
916
1116
|
const analysis = analyzeAcceptedSnippet(snippet, explicitTerminated);
|
|
1117
|
+
const compileStart = performance.now();
|
|
917
1118
|
const { annotated, lib, lineOffset } = compileSnippetArtifacts(snippet, state);
|
|
1119
|
+
const snippetCompileMs = performance.now() - compileStart;
|
|
918
1120
|
mergeLibrary(state, lib, "<repl>");
|
|
919
1121
|
|
|
920
1122
|
if (analysis.kind === "definitionsOnly") {
|
|
921
1123
|
restoreCodes(state);
|
|
1124
|
+
state.lastTiming = {
|
|
1125
|
+
compileMs: snippetCompileMs,
|
|
1126
|
+
executeMs: 0,
|
|
1127
|
+
totalMs: snippetCompileMs,
|
|
1128
|
+
snippetCompileMs,
|
|
1129
|
+
wasmCompileMs: 0
|
|
1130
|
+
};
|
|
1131
|
+
if (state.showTiming) {
|
|
1132
|
+
return [`/* comp: ${formatDuration(snippetCompileMs)} */`];
|
|
1133
|
+
}
|
|
922
1134
|
return [];
|
|
923
1135
|
}
|
|
924
1136
|
|
|
925
|
-
|
|
926
|
-
run.defs = annotated;
|
|
927
|
-
let result;
|
|
1137
|
+
let execRes;
|
|
928
1138
|
try {
|
|
929
|
-
|
|
1139
|
+
execRes = await executeExpressionWithWasm(annotated, state, lineOffset);
|
|
930
1140
|
} catch (error) {
|
|
931
1141
|
throw remapError(error, lineOffset);
|
|
932
1142
|
}
|
|
1143
|
+
state.codes = codes.dump();
|
|
933
1144
|
restoreCodes(state);
|
|
934
|
-
|
|
1145
|
+
|
|
1146
|
+
const compileMs = snippetCompileMs + execRes.wasmCompileMs;
|
|
1147
|
+
const executeMs = execRes.executeMs;
|
|
1148
|
+
state.lastTiming = {
|
|
1149
|
+
compileMs,
|
|
1150
|
+
executeMs,
|
|
1151
|
+
totalMs: compileMs + executeMs,
|
|
1152
|
+
snippetCompileMs,
|
|
1153
|
+
wasmCompileMs: execRes.wasmCompileMs
|
|
1154
|
+
};
|
|
1155
|
+
|
|
1156
|
+
const committed = commitResult(state, execRes.result, snippet);
|
|
1157
|
+
if (state.showTiming) {
|
|
1158
|
+
committed.push(`/* comp: ${formatDuration(compileMs)}, exec: ${formatDuration(executeMs)} */`);
|
|
1159
|
+
}
|
|
1160
|
+
return committed;
|
|
935
1161
|
}
|
|
936
1162
|
|
|
937
1163
|
async function loadCodec(input, state) {
|
|
938
|
-
const
|
|
1164
|
+
const trimmed = input.trim();
|
|
1165
|
+
if (!trimmed || trimmed === "list") {
|
|
1166
|
+
return [listCodecs(state)];
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
const [subcommand, ...rest] = trimmed.split(/\s+/);
|
|
939
1170
|
switch (subcommand) {
|
|
940
1171
|
case "load": {
|
|
941
1172
|
const filePath = rest.join(" ");
|
|
942
|
-
if (!filePath) throw new Error(":codec load requires a file path");
|
|
1173
|
+
if (!filePath) throw new Error(":codec load requires a file path or codec name");
|
|
1174
|
+
const autoLoaded = ensureCodecDependencies(state, filePath);
|
|
943
1175
|
const registered = await loadCodecModule(state, expandHome(filePath));
|
|
944
1176
|
return registered.map(({ name, codeHash }) =>
|
|
945
|
-
`loaded codec ${name} for ${codeHash === UNIVERSAL_CODE ? "all types" : codeHash}`
|
|
1177
|
+
`loaded codec ${name} for ${codeHash === UNIVERSAL_CODE ? "all types" : codeHash}${autoLoaded ? ` (auto-loaded ${autoLoaded})` : ""}`
|
|
1178
|
+
);
|
|
1179
|
+
}
|
|
1180
|
+
case "unload": {
|
|
1181
|
+
const codecName = rest.join(" ").trim();
|
|
1182
|
+
if (!codecName) throw new Error(":codec unload requires a codec name");
|
|
1183
|
+
const removed = unregisterCodec(state, codecName);
|
|
1184
|
+
if (removed === 0) throw new Error(`Codec '${codecName}' is not loaded`);
|
|
1185
|
+
return [`unloaded codec ${codecName}`];
|
|
1186
|
+
}
|
|
1187
|
+
case "define": {
|
|
1188
|
+
const match = rest.join(" ").match(/^([a-zA-Z0-9_+-]+)\s+(\S+)\s+([\s\S]+)$/);
|
|
1189
|
+
if (!match) {
|
|
1190
|
+
throw new Error(":codec define requires: name type { parse: ..., print: ... }");
|
|
1191
|
+
}
|
|
1192
|
+
const [, name, rawType, bodyStr] = match;
|
|
1193
|
+
const fn = new Function("Value", "isProduct", "isVariant", "state", `return (${bodyStr});`);
|
|
1194
|
+
const obj = fn(Value, isProduct, isVariant, state);
|
|
1195
|
+
const codeHash = rawType === "*" ? UNIVERSAL_CODE : resolveInputTypeHash(state, rawType);
|
|
1196
|
+
const codec = normalizeCodecModule({
|
|
1197
|
+
name,
|
|
1198
|
+
codes: [codeHash],
|
|
1199
|
+
universal: codeHash === UNIVERSAL_CODE,
|
|
1200
|
+
parse: obj.parse,
|
|
1201
|
+
print: obj.print
|
|
1202
|
+
}, name);
|
|
1203
|
+
const registered = registerCodec(state, codec, "<inline>");
|
|
1204
|
+
return registered.map(({ name, codeHash }) =>
|
|
1205
|
+
`defined codec ${name} for ${codeHash === UNIVERSAL_CODE ? "all types" : codeHash}`
|
|
946
1206
|
);
|
|
947
1207
|
}
|
|
948
1208
|
case "list":
|
|
949
1209
|
if (rest.length > 0) throw new Error(":codec list does not accept arguments");
|
|
950
1210
|
return [listCodecs(state)];
|
|
951
|
-
default:
|
|
952
|
-
|
|
1211
|
+
default: {
|
|
1212
|
+
const autoLoaded = ensureCodecDependencies(state, trimmed);
|
|
1213
|
+
const registered = await loadCodecModule(state, expandHome(trimmed));
|
|
1214
|
+
return registered.map(({ name, codeHash }) =>
|
|
1215
|
+
`loaded codec ${name} for ${codeHash === UNIVERSAL_CODE ? "all types" : codeHash}${autoLoaded ? ` (auto-loaded ${autoLoaded})` : ""}`
|
|
1216
|
+
);
|
|
1217
|
+
}
|
|
953
1218
|
}
|
|
954
1219
|
}
|
|
955
1220
|
|
|
@@ -998,6 +1263,7 @@ async function consumeCodecInput(input, state) {
|
|
|
998
1263
|
}
|
|
999
1264
|
|
|
1000
1265
|
async function evaluateInput(input, state) {
|
|
1266
|
+
state.lastTiming = null;
|
|
1001
1267
|
if (state.pendingInput) {
|
|
1002
1268
|
return consumeCodecInput(input, state);
|
|
1003
1269
|
}
|
|
@@ -1028,6 +1294,29 @@ async function evaluateCommand(line, state) {
|
|
|
1028
1294
|
exit(0);
|
|
1029
1295
|
case "help":
|
|
1030
1296
|
return [helpText()];
|
|
1297
|
+
case "timing": {
|
|
1298
|
+
const trimmed = arg.trim().toLowerCase();
|
|
1299
|
+
if (trimmed === "on" || trimmed === "true" || trimmed === "1") {
|
|
1300
|
+
state.showTiming = true;
|
|
1301
|
+
} else if (trimmed === "off" || trimmed === "false" || trimmed === "0") {
|
|
1302
|
+
state.showTiming = false;
|
|
1303
|
+
} else if (!trimmed) {
|
|
1304
|
+
state.showTiming = !state.showTiming;
|
|
1305
|
+
} else {
|
|
1306
|
+
throw new Error(":timing accepts 'on', 'off', or no arguments to toggle");
|
|
1307
|
+
}
|
|
1308
|
+
return [`timing reporting ${state.showTiming ? "enabled" : "disabled"}`];
|
|
1309
|
+
}
|
|
1310
|
+
case "time": {
|
|
1311
|
+
if (!arg) throw new Error(":time requires an expression");
|
|
1312
|
+
const wasTiming = state.showTiming;
|
|
1313
|
+
state.showTiming = true;
|
|
1314
|
+
try {
|
|
1315
|
+
return await evaluateInput(arg, state);
|
|
1316
|
+
} finally {
|
|
1317
|
+
state.showTiming = wasTiming;
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1031
1320
|
case "type": {
|
|
1032
1321
|
if (!arg) throw new Error(":type requires a name or definition");
|
|
1033
1322
|
if (arg.includes("=")) {
|
|
@@ -1055,6 +1344,7 @@ async function evaluateCommand(line, state) {
|
|
|
1055
1344
|
JSON.stringify(state.value, null, 2)
|
|
1056
1345
|
];
|
|
1057
1346
|
case "codec":
|
|
1347
|
+
case "codecs":
|
|
1058
1348
|
return loadCodec(arg, state);
|
|
1059
1349
|
case "input":
|
|
1060
1350
|
return requestCodecInput(arg, state);
|
|
@@ -1081,26 +1371,7 @@ async function evaluateCommand(line, state) {
|
|
|
1081
1371
|
}
|
|
1082
1372
|
case "load": {
|
|
1083
1373
|
const { path: loadPath, loadAliases } = parseLoadArgs(arg, usagePrefix);
|
|
1084
|
-
|
|
1085
|
-
const lib = loadLibrary(decodeLibrary(fs.readFileSync(loadPath)));
|
|
1086
|
-
mergeLibrary(state, lib, loadPath, { loadAliases });
|
|
1087
|
-
} else {
|
|
1088
|
-
restoreCodes(state);
|
|
1089
|
-
const source = fs.readFileSync(loadPath, "utf8");
|
|
1090
|
-
const preamble = aliasPreamble(state);
|
|
1091
|
-
const fullSource = [preamble, source].filter(Boolean).join("\n");
|
|
1092
|
-
const options = {
|
|
1093
|
-
source: loadPath,
|
|
1094
|
-
libraries: [stateLibrary(state)]
|
|
1095
|
-
};
|
|
1096
|
-
try {
|
|
1097
|
-
const lib = compileWithOptionalIdentity(fullSource, options);
|
|
1098
|
-
const { relAlias, meta } = libraryOriginsFromSource(source, fullSource, lib, options);
|
|
1099
|
-
mergeLibrary(state, { ...lib, relAlias, meta }, loadPath, { loadAliases });
|
|
1100
|
-
} catch (error) {
|
|
1101
|
-
throw remapError(error, preambleLineCount(preamble));
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1374
|
+
loadSourceOrKlib(state, loadPath, { loadAliases });
|
|
1104
1375
|
return [`loaded ${loadPath}`];
|
|
1105
1376
|
}
|
|
1106
1377
|
case "t": {
|
|
@@ -1131,13 +1402,17 @@ function helpText() {
|
|
|
1131
1402
|
":type name = <...> define a type",
|
|
1132
1403
|
":rel name = expr define a relation",
|
|
1133
1404
|
":run expr run an expression on the current value",
|
|
1405
|
+
":time expr run an expression and report compilation/execution time",
|
|
1406
|
+
":timing [on|off] toggle timing reporting after every evaluation",
|
|
1134
1407
|
":t name show relation type",
|
|
1135
1408
|
":d name show relation definition",
|
|
1136
1409
|
":type name show type definition",
|
|
1137
1410
|
":codes list type aliases",
|
|
1138
1411
|
":rels list relation aliases",
|
|
1139
|
-
":codec load file load a REPL codec module",
|
|
1140
|
-
":codec
|
|
1412
|
+
":codec load file load a REPL codec module (or built-in: int, utf8, json, ieee)",
|
|
1413
|
+
":codec define n t b define a custom codec: name type { parse: ..., print: ... }",
|
|
1414
|
+
":codec unload name unload a registered codec",
|
|
1415
|
+
":codec list list loaded codecs (or simply :codecs)",
|
|
1141
1416
|
":input type [codec] read next line as codec input",
|
|
1142
1417
|
":load [--no-alias] file",
|
|
1143
1418
|
" load .k source or .klib",
|
|
@@ -1284,8 +1559,19 @@ export {
|
|
|
1284
1559
|
isMainEntrypoint,
|
|
1285
1560
|
lineHasExplicitContinuation,
|
|
1286
1561
|
lineTerminatesSnippet,
|
|
1562
|
+
listCodecs,
|
|
1563
|
+
loadCodecModule,
|
|
1564
|
+
registerCodec,
|
|
1565
|
+
unregisterCodec,
|
|
1566
|
+
resolveCodec,
|
|
1567
|
+
codeHashToPattern,
|
|
1568
|
+
BUILTIN_CODECS,
|
|
1287
1569
|
printValue,
|
|
1288
1570
|
promptForState,
|
|
1289
1571
|
propertyListToFilter,
|
|
1290
|
-
|
|
1572
|
+
savedLibrary,
|
|
1573
|
+
loadSourceOrKlib,
|
|
1574
|
+
ensureCodecDependencies,
|
|
1575
|
+
valueToK,
|
|
1576
|
+
formatDuration
|
|
1291
1577
|
};
|
package/run.mjs
CHANGED
|
@@ -2,14 +2,9 @@ import assert from "assert";
|
|
|
2
2
|
import { Value, edgeSubpattern, composePattern, withPattern, isProduct, isVariant } from "./Value.mjs"
|
|
3
3
|
import { exportPatternGraph, intersectPropertyListPatterns } from "./codecs/runtime/codec.mjs";
|
|
4
4
|
import { patternToPropertyList } from "./codecs/runtime/pattern-json.mjs";
|
|
5
|
+
import { jsIntrinsicFunctions } from "./intrinsics.mjs";
|
|
5
6
|
|
|
6
|
-
const builtin =
|
|
7
|
-
"_log!": (arg) => {
|
|
8
|
-
console.error(`_log!: ${arg}`);
|
|
9
|
-
|
|
10
|
-
return arg;
|
|
11
|
-
}
|
|
12
|
-
};
|
|
7
|
+
const builtin = jsIntrinsicFunctions;
|
|
13
8
|
|
|
14
9
|
const codes = { };
|
|
15
10
|
const staticPatternCache = new WeakMap();
|