@fraczak/k 6.0.1 → 6.0.2
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/AGENTS.md +35 -0
- package/CHANGELOG.md +48 -0
- package/CLAUDE.md +64 -0
- package/DOCS/BIG_PICTURE.md +4 -8
- package/DOCS/BINARY_CODEC_STATUS_AND_TODO.md +74 -0
- package/DOCS/CONVERGENCE.md +92 -0
- package/DOCS/DIVERGENCE_DETECTION.md +24 -0
- package/DOCS/Makefile +99 -0
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +217 -0
- package/DOCS/PATTERNS.md +114 -0
- package/DOCS/PATTERNS_AND_TYPED_VALUES.md +665 -0
- package/DOCS/REPL.md +125 -125
- package/DOCS/TEXTUAL_VALUES.md +108 -0
- package/DOCS/TYPE_DERIVATION.md +230 -0
- package/DOCS/book/06-values-in-memory.md +1085 -0
- package/DOCS/book/07-the-partial-function-abi.md +143 -0
- package/DOCS/book/08-operational-semantics-and-execution.md +201 -0
- package/DOCS/book/09-compiler-architecture.md +160 -0
- package/DOCS/book/10-from-ast-to-intermediate-representation.md +167 -0
- package/DOCS/book/14-canonical-serialization.md +176 -0
- package/DOCS/book/appendix-b-incorporating-external-predefined-types-and-functions.md +155 -0
- package/DOCS/book/overview.txt +68 -0
- package/README.md +71 -27
- package/codecs/README.md +8 -0
- package/codecs/pandoc.css +71 -0
- package/codecs/runtime/test-codec.mjs +89 -0
- package/package.json +2 -2
- package/{codecs/k-pattern.mjs → patterns/from-k.mjs} +3 -3
- package/repl2.mjs +259 -50
- package/scripts/generate-dependency-graph.mjs +121 -0
- package/test-repl2.mjs +55 -8
- package/DOCS/book-combined.html +0 -3798
- package/DOCS/book-combined.md +0 -3745
- package/DOCS/book-combined.pdf +0 -0
- package/DOCS/book-combined.tex +0 -5682
- package/DOCS/book.html +0 -65
- package/DOCS/book.pdf +0 -0
- package/DOCS/book.tex +0 -150
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { execSync } from "node:child_process";
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
const root = path.resolve(__dirname, "..");
|
|
11
|
+
const outPath = path.join(root, "DOCS", "dependency-graph.md");
|
|
12
|
+
|
|
13
|
+
function getTrackedMjsFiles() {
|
|
14
|
+
const raw = execSync("git ls-files '*.mjs'", {
|
|
15
|
+
cwd: root,
|
|
16
|
+
encoding: "utf8"
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const all = raw
|
|
20
|
+
.split("\n")
|
|
21
|
+
.map((s) => s.trim())
|
|
22
|
+
.filter(Boolean);
|
|
23
|
+
|
|
24
|
+
return all.filter((relPath) => {
|
|
25
|
+
if (relPath.startsWith("codecs/")) return true;
|
|
26
|
+
if (relPath.includes("/")) return false;
|
|
27
|
+
if (relPath.startsWith("test")) return false;
|
|
28
|
+
if (relPath.includes("-test")) return false;
|
|
29
|
+
return true;
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function parseLocalImports(absPath) {
|
|
34
|
+
const source = fs.readFileSync(absPath, "utf8");
|
|
35
|
+
const regex = /^\s*import\s+[^;]*?from\s+["']([^"']+)["'];?\s*$/gm;
|
|
36
|
+
const imports = [];
|
|
37
|
+
let match;
|
|
38
|
+
while ((match = regex.exec(source)) !== null) {
|
|
39
|
+
const specifier = match[1];
|
|
40
|
+
if (specifier.startsWith("./") || specifier.startsWith("../")) {
|
|
41
|
+
imports.push(specifier);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return imports;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function toNodeId(relPath) {
|
|
48
|
+
return relPath.replace(/[^a-zA-Z0-9]/g, "_");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function makeBar(sizeKb) {
|
|
52
|
+
const units = Math.max(1, Math.min(20, Math.round(sizeKb)));
|
|
53
|
+
return "█".repeat(units);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function renderGraph(files, sizesKb, edges) {
|
|
57
|
+
const lines = [];
|
|
58
|
+
lines.push("# Project Dependency Graph");
|
|
59
|
+
lines.push("");
|
|
60
|
+
lines.push("_Auto-generated by scripts/generate-dependency-graph.mjs._");
|
|
61
|
+
lines.push("");
|
|
62
|
+
lines.push("```mermaid");
|
|
63
|
+
lines.push("graph TD");
|
|
64
|
+
lines.push(" classDef default fill:#fff,stroke:#333,stroke-width:2px,color:#000;");
|
|
65
|
+
lines.push("");
|
|
66
|
+
|
|
67
|
+
for (const relPath of files) {
|
|
68
|
+
const id = toNodeId(relPath);
|
|
69
|
+
const sizeKb = sizesKb[relPath];
|
|
70
|
+
const bar = makeBar(sizeKb);
|
|
71
|
+
lines.push(` ${id}[\"${relPath} (${sizeKb.toFixed(1)} KB)<br/>${bar}\"]`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (edges.length > 0) {
|
|
75
|
+
lines.push("");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
for (const { src, dst } of edges) {
|
|
79
|
+
lines.push(` ${toNodeId(src)} --> ${toNodeId(dst)}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
lines.push("```");
|
|
83
|
+
lines.push("");
|
|
84
|
+
return lines.join("\n");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function main() {
|
|
88
|
+
const files = getTrackedMjsFiles().sort();
|
|
89
|
+
const fileSet = new Set(files);
|
|
90
|
+
|
|
91
|
+
const sizesKb = {};
|
|
92
|
+
for (const relPath of files) {
|
|
93
|
+
const absPath = path.join(root, relPath);
|
|
94
|
+
const bytes = fs.statSync(absPath).size;
|
|
95
|
+
sizesKb[relPath] = bytes / 1024;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const edgeKeys = new Set();
|
|
99
|
+
const edges = [];
|
|
100
|
+
for (const relPath of files) {
|
|
101
|
+
const absPath = path.join(root, relPath);
|
|
102
|
+
const imports = parseLocalImports(absPath);
|
|
103
|
+
|
|
104
|
+
for (const specifier of imports) {
|
|
105
|
+
const resolved = path.normalize(path.join(path.dirname(relPath), specifier));
|
|
106
|
+
if (!resolved.endsWith(".mjs")) continue;
|
|
107
|
+
if (!fileSet.has(resolved)) continue;
|
|
108
|
+
const key = `${relPath}->${resolved}`;
|
|
109
|
+
if (edgeKeys.has(key)) continue;
|
|
110
|
+
edgeKeys.add(key);
|
|
111
|
+
edges.push({ src: relPath, dst: resolved });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const graph = renderGraph(files, sizesKb, edges);
|
|
116
|
+
fs.writeFileSync(outPath, graph, "utf8");
|
|
117
|
+
console.log(`Wrote ${path.relative(root, outPath)}`);
|
|
118
|
+
console.log(`Nodes: ${files.length}, Edges: ${edges.length}`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
main();
|
package/test-repl2.mjs
CHANGED
|
@@ -4,7 +4,18 @@ import os from "node:os";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
aliasNames,
|
|
9
|
+
analyzeAcceptedSnippet,
|
|
10
|
+
analyzeRawSnippet,
|
|
11
|
+
completeInput,
|
|
12
|
+
createState,
|
|
13
|
+
evaluateInput,
|
|
14
|
+
explicitSnippetTerminated,
|
|
15
|
+
isMainEntrypoint,
|
|
16
|
+
lineHasExplicitContinuation,
|
|
17
|
+
lineTerminatesSnippet
|
|
18
|
+
} from "./repl2.mjs";
|
|
8
19
|
import { decodeObject, objectToFunction } from "./object.mjs";
|
|
9
20
|
import { Product } from "./Value.mjs";
|
|
10
21
|
|
|
@@ -41,12 +52,38 @@ assert(completions.some((line) => line.endsWith(state.typeAliases.nat)));
|
|
|
41
52
|
completions = completeInput(`(${canonicalPartial}`, state)[0];
|
|
42
53
|
assert(completions.includes(`(${state.typeAliases.nat}`));
|
|
43
54
|
|
|
55
|
+
completions = completeInput(":run su", state)[0];
|
|
56
|
+
assert(completions.includes(":run succ"));
|
|
57
|
+
|
|
58
|
+
completions = completeInput("$na", state)[0];
|
|
59
|
+
assert(completions.includes("$nat"));
|
|
60
|
+
|
|
61
|
+
assert.deepEqual(aliasNames(state), ["nat", "succ"]);
|
|
62
|
+
assert.equal(lineTerminatesSnippet(";"), true);
|
|
63
|
+
assert.equal(lineTerminatesSnippet(" ; "), true);
|
|
64
|
+
assert.equal(lineTerminatesSnippet(" ; -- comment"), false);
|
|
65
|
+
assert.equal(lineTerminatesSnippet("succ"), false);
|
|
66
|
+
assert.equal(explicitSnippetTerminated("$ bool = <{} true, {} false>;"), true);
|
|
67
|
+
assert.equal(lineHasExplicitContinuation("succ \\"), true);
|
|
68
|
+
assert.equal(analyzeRawSnippet("$ bool = <{} true, {} false>").kind, "incomplete");
|
|
69
|
+
assert.equal(analyzeAcceptedSnippet("$ bool = <{} true, {} false>;", true).kind, "definitionsOnly");
|
|
70
|
+
assert.equal(analyzeRawSnippet("a =").kind, "incomplete");
|
|
71
|
+
assert.equal(analyzeRawSnippet("{} | succ").kind, "withMain");
|
|
72
|
+
|
|
73
|
+
const offsetState = createState();
|
|
74
|
+
await evaluateInput(":type ab = <{} 1, {} 2>", offsetState);
|
|
75
|
+
await evaluateInput(":type bool = <{} true, {} false>", offsetState);
|
|
76
|
+
await assert.rejects(
|
|
77
|
+
() => evaluateInput("$ab", offsetState),
|
|
78
|
+
/Type Error in 'filter' \(lines 1:1\.\.\.1:4\)/
|
|
79
|
+
);
|
|
80
|
+
|
|
44
81
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "k-repl2-"));
|
|
45
82
|
const libPath = path.join(tmpDir, "session.klib");
|
|
46
83
|
const koPath = path.join(tmpDir, "succ.ko");
|
|
47
84
|
const sourcePath = path.join(tmpDir, "session.k");
|
|
48
85
|
const symlinkPath = path.resolve(".test-k-repl2-link");
|
|
49
|
-
output = await evaluateInput(`:
|
|
86
|
+
output = await evaluateInput(`:klib ${libPath}`, state);
|
|
50
87
|
assert.equal(output[0], `saved ${libPath}`);
|
|
51
88
|
|
|
52
89
|
completions = completeInput(`:load ${tmpDir}/ses`, state)[0];
|
|
@@ -89,12 +126,22 @@ output = await evaluateInput("succ", reloaded);
|
|
|
89
126
|
assert.equal(output[0], "{}|succ ?<{} succ, ...>");
|
|
90
127
|
|
|
91
128
|
const shorthand = createState();
|
|
92
|
-
output = await evaluateInput("$ nat = <{} zero, nat succ
|
|
93
|
-
assert.
|
|
94
|
-
output = await evaluateInput("
|
|
95
|
-
assert.match(output[0], /^
|
|
96
|
-
output = await evaluateInput("
|
|
97
|
-
assert.
|
|
129
|
+
output = await evaluateInput("$ nat = <{} zero, nat succ>\n; succ = |succ\n;", shorthand);
|
|
130
|
+
assert.deepEqual(output, []);
|
|
131
|
+
output = await evaluateInput(":codes", shorthand);
|
|
132
|
+
assert.match(output[0], /^nat = @/m);
|
|
133
|
+
output = await evaluateInput(":rels", shorthand);
|
|
134
|
+
assert.match(output[0], /^succ = @/m);
|
|
135
|
+
output = await evaluateInput("$ bool = <{} true, {} false>\n; not = $bool </true | false, {} | true >\n; {} | true not", shorthand);
|
|
136
|
+
assert.match(output[0], /^\{\}\|false \?</);
|
|
137
|
+
assert.match(output[0], / false/);
|
|
138
|
+
assert.match(output[0], / true/);
|
|
139
|
+
output = await evaluateInput("$ maybe = <{} none, {} some>;", shorthand);
|
|
140
|
+
assert.deepEqual(output, []);
|
|
141
|
+
output = await evaluateInput(":codes", shorthand);
|
|
142
|
+
assert.match(output[0], /^maybe = @/m);
|
|
143
|
+
output = await evaluateInput("{} | true not", shorthand);
|
|
144
|
+
assert.match(output[0], /^\{\}\|false \?</);
|
|
98
145
|
|
|
99
146
|
await assert.rejects(
|
|
100
147
|
() => evaluateInput("/type", createState()),
|