@fraczak/k 7.0.1 → 7.1.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.
Files changed (89) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/DOCS/BIG_PICTURE.md +5 -5
  3. package/DOCS/FILE_FORMATS.md +241 -18
  4. package/DOCS/OBJECT_FILE_AND_PATTERN.md +9 -9
  5. package/DOCS/PATTERNS.md +3 -3
  6. package/DOCS/POLYMORPHIC_IR.md +104 -0
  7. package/DOCS/PROFILING_AND_TRACING.md +60 -72
  8. package/DOCS/REPL.md +3 -3
  9. package/DOCS/book/03-types-as-finite-automata.md +4 -4
  10. package/DOCS/book/06-values-in-memory.md +9 -9
  11. package/DOCS/book/08-operational-semantics-and-execution.md +1 -1
  12. package/DOCS/book/09-compiler-architecture.md +2 -2
  13. package/DOCS/book/10-from-ast-to-intermediate-representation.md +2 -2
  14. package/DOCS/book/14-canonical-serialization.md +1 -1
  15. package/Examples/arithmetics.k +2 -2
  16. package/Examples/bnat.k +1 -1
  17. package/Examples/karatsuba-mult.k +2 -2
  18. package/JOURNAL.md +288 -0
  19. package/README.md +13 -10
  20. package/access-table.mjs +343 -0
  21. package/backend-api.mjs +18 -0
  22. package/backends/llvm/README.md +20 -21
  23. package/backends/llvm/bin/k-llvm-build.mjs +105 -32
  24. package/backends/llvm/bin/k-llvm-compile.mjs +63 -24
  25. package/backends/llvm/bin/k-llvm.mjs +292 -0
  26. package/backends/llvm/runtime/krt.c +41 -0
  27. package/backends/llvm/runtime/krt.h +2 -0
  28. package/backends/llvm/src/cli.mjs +95 -17
  29. package/backends/llvm/src/executable.mjs +132 -15
  30. package/backends/llvm/src/kvm2llvm.mjs +50 -23
  31. package/backends/llvm/src/llvm.mjs +133 -20
  32. package/backends/llvm/tests/integration.sh +11 -11
  33. package/backends/llvm/{bin → tests}/k-llvm-run.mjs +48 -22
  34. package/backends/llvm/tests/perf-support.mjs +25 -58
  35. package/backends/llvm/tests/test-llvm.mjs +25 -4
  36. package/backends/wasm/bin/k-wasm-compile.mjs +46 -20
  37. package/backends/wasm/bin/k-wasm-run.mjs +61 -20
  38. package/backends/wasm/bin/k-wasm.mjs +47 -13
  39. package/backends/wasm/src/cli.mjs +141 -19
  40. package/backends/wasm/src/wasm.mjs +132 -24
  41. package/backends/wasm/tests/test-wasm.mjs +5 -5
  42. package/browser/repl-browser.mjs +16 -5
  43. package/browser/vfs-data.mjs +5 -5
  44. package/codecs/k-parse.mjs +29 -8
  45. package/codecs/k-print.mjs +22 -6
  46. package/codecs/runtime/codec-sdk.mjs +8 -4
  47. package/codecs/show.mjs +20 -6
  48. package/core.k +8 -8
  49. package/harness/format.mjs +2 -2
  50. package/harness/registry.mjs +0 -2
  51. package/k.mjs +56 -16
  52. package/kir.mjs +200 -75
  53. package/kvm.mjs +49 -12
  54. package/objects/compile.mjs +37 -23
  55. package/objects/decompile.mjs +40 -10
  56. package/objects/extract-aliases.mjs +44 -14
  57. package/objects/inspect.mjs +19 -14
  58. package/objects/validate.mjs +18 -11
  59. package/package.json +10 -7
  60. package/pkir.mjs +772 -0
  61. package/repl.mjs +36 -18
  62. package/scripts/benchmark-idempotency.mjs +12 -8
  63. package/scripts/benchmark.mjs +5 -9
  64. package/scripts/build-repl-html.mjs +16 -4
  65. package/scripts/perf-ieee.mjs +253 -103
  66. package/scripts/perf-int.mjs +585 -297
  67. package/scripts/perf-multiplication.mjs +66 -25
  68. package/scripts/perf-poly.mjs +292 -164
  69. package/scripts/run-tests.mjs +3 -0
  70. package/tests/code-derivation/pattern-envelope.mjs +4 -4
  71. package/tests/test-access-table.mjs +213 -0
  72. package/tests/test-kvm-polymorphic.mjs +2 -2
  73. package/tests/test-pkir.mjs +530 -0
  74. package/tests/test-polymorphic-tdd.mjs +196 -0
  75. package/tests/test-repl-html.mjs +15 -2
  76. package/tests/test-repl.mjs +30 -1
  77. package/backends/arm64/README.md +0 -103
  78. package/backends/arm64/bin/k-arm64-compile.mjs +0 -93
  79. package/backends/arm64/bin/k-arm64-run.mjs +0 -58
  80. package/backends/arm64/bin/k-arm64.mjs +0 -88
  81. package/backends/arm64/scripts/run-tests.mjs +0 -57
  82. package/backends/arm64/src/arm64.mjs +0 -229
  83. package/backends/arm64/src/cli.mjs +0 -155
  84. package/backends/arm64/src/kvm2arm64.mjs +0 -906
  85. package/backends/arm64/src/runtime.c +0 -744
  86. package/backends/arm64/tests/integration.sh +0 -112
  87. package/backends/arm64/tests/test-arm64.mjs +0 -240
  88. package/backends/llvm/bin/k-llvm-jit.mjs +0 -160
  89. package/harness/adapters/arm64.mjs +0 -105
@@ -1,229 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import os from "node:os";
4
- import { execFileSync, spawnSync } from "node:child_process";
5
- import { fileURLToPath } from "node:url";
6
-
7
- import {
8
- decodeObject,
9
- decodeWire,
10
- objectToKVMArtifact,
11
- specializeKVM
12
- } from "../../../backend-api.mjs";
13
- import { compileLibrary, compileObjectBuffer, loadLibrary } from "../../../object.mjs";
14
-
15
- import {
16
- compileKVMModuleToARM64,
17
- emitMetadataC,
18
- getTagEntries,
19
- resetTagIds
20
- } from "./kvm2arm64.mjs";
21
-
22
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
23
- const RUNTIME_C_PATH = path.resolve(__dirname, "runtime.c");
24
- const KRT_C_PATH = path.resolve(__dirname, "../../llvm/runtime/krt.c");
25
- const KRT_H_DIR = path.resolve(__dirname, "../../llvm/runtime");
26
-
27
- export const ARTIFACT_FORMAT = "k-arm64";
28
- export const ARTIFACT_VERSION = 1;
29
-
30
- function buildExportPreamble(exports = [], libraries = []) {
31
- if (exports.length === 0) return "";
32
- const aliasMap = {};
33
- for (const lib of libraries) {
34
- for (const [name, hash] of Object.entries(lib.relAlias || {})) {
35
- if (name !== "__main__") aliasMap[name] = hash;
36
- }
37
- for (const [hash, entry] of Object.entries(lib.meta || {})) {
38
- if (entry?.type !== "rel") continue;
39
- for (const origin of entry?.origins || []) {
40
- if (origin?.name && origin.name !== "__main__") {
41
- aliasMap[origin.name] = hash;
42
- }
43
- }
44
- }
45
- }
46
- const lines = [];
47
- for (const spec of exports) {
48
- const [libName, localName] = spec.includes(":") ? spec.split(":", 2) : [spec, spec];
49
- const hash = aliasMap[libName];
50
- if (!hash) throw new Error(`--export: '${libName}' not found in loaded libraries`);
51
- const body = hash.startsWith("@") ? hash.slice(1) : hash;
52
- lines.push(`${localName} = @${body};`);
53
- }
54
- return lines.join("\n") + "\n";
55
- }
56
-
57
- export function compileARM64ArtifactFromKVM(kvmInput, options = {}) {
58
- let kvm = kvmInput;
59
- if (kvm?.format === "k-vm") {
60
- if (kvm.layer === "KVM-P" && options.inputEnvelopePattern) {
61
- kvm = specializeKVM(kvm, options.inputEnvelopePattern);
62
- }
63
- }
64
-
65
- const functions = kvm.functions || (typeof kvm === "object" && !Array.isArray(kvm) ? kvm : null);
66
- if (!functions || typeof functions !== "object") {
67
- throw new Error("Expected .kvm input to contain a functions object");
68
- }
69
-
70
- const entry = options.entry || kvm.entry || "__main__";
71
- const entryFunc = functions[entry];
72
- if (!entryFunc) {
73
- throw new Error(`kVM entry relation '${entry}' not found in program`);
74
- }
75
-
76
- const inputPattern = options.inputPattern || entryFunc.inputPattern || [];
77
- const outputPattern = options.outputPattern || entryFunc.outputPattern || [];
78
-
79
- resetTagIds();
80
- const profile = Boolean(options.profile ?? (process.env.K_PROFILE === "1" || process.env.PROFILE === "1"));
81
- const { assembly, entryName, profileFunctions } = compileKVMModuleToARM64(entry, functions, {
82
- inputPattern,
83
- outputPattern,
84
- profile
85
- });
86
- const tags = getTagEntries();
87
- const metadataC = emitMetadataC(tags, inputPattern, outputPattern, profileFunctions);
88
-
89
- if (options.emit === "assembly" || options.assembly) {
90
- return {
91
- assembly,
92
- metadataC,
93
- entryName,
94
- tags,
95
- inputPattern,
96
- outputPattern
97
- };
98
- }
99
-
100
- // Compile to native ELF executable using gcc
101
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "k-arm64-"));
102
- const asmPath = path.join(tmpDir, "prog.s");
103
- const metaPath = path.join(tmpDir, "meta.c");
104
- const outPath = options.outputPath || path.join(tmpDir, "prog");
105
-
106
- try {
107
- fs.writeFileSync(asmPath, assembly, "utf8");
108
- fs.writeFileSync(metaPath, metadataC, "utf8");
109
-
110
- const gcc = options.gcc || process.env.CC || "gcc";
111
- const optLevel = options.optLevel ?? "-O2";
112
- const args = [
113
- optLevel,
114
- `-DENTRY_NAME=${entryName}`,
115
- asmPath,
116
- metaPath,
117
- RUNTIME_C_PATH,
118
- KRT_C_PATH,
119
- `-I${KRT_H_DIR}`,
120
- "-o",
121
- outPath
122
- ];
123
-
124
- execFileSync(gcc, args, { stdio: "pipe" });
125
-
126
- if (options.outputPath) {
127
- return outPath;
128
- }
129
-
130
- const binaryBuffer = fs.readFileSync(outPath);
131
- return binaryBuffer;
132
- } finally {
133
- try {
134
- if (fs.existsSync(asmPath)) fs.unlinkSync(asmPath);
135
- if (fs.existsSync(metaPath)) fs.unlinkSync(metaPath);
136
- if (!options.outputPath && fs.existsSync(outPath)) fs.unlinkSync(outPath);
137
- if (!options.outputPath) fs.rmdirSync(tmpDir);
138
- } catch {
139
- // Ignore cleanup errors in temporary directory
140
- }
141
- }
142
- }
143
-
144
- export function compileARM64ArtifactFromObject(object, options = {}) {
145
- const kvm = objectToKVMArtifact(object, options.entry, null, options);
146
- return compileARM64ArtifactFromKVM(kvm, options);
147
- }
148
-
149
- export function compileARM64Artifact(source, options = {}) {
150
- const libraries = (options.libraries || []).map((lib) => {
151
- if (lib?.rels || lib?.meta || lib?.relAlias) return lib;
152
- if (typeof lib === "string") {
153
- const ext = path.extname(lib).toLowerCase();
154
- if (ext === ".k") {
155
- return loadLibrary(compileLibrary(fs.readFileSync(lib, "utf8"), { source: lib }));
156
- }
157
- return loadLibrary(decodeObject(fs.readFileSync(lib)));
158
- }
159
- if (Buffer.isBuffer(lib)) {
160
- return loadLibrary(decodeObject(lib));
161
- }
162
- return lib;
163
- });
164
- const preamble = buildExportPreamble(options.exports || options.exportSpecs || [], libraries);
165
- const fullSource = preamble + source;
166
-
167
- const objBuffer = compileObjectBuffer(fullSource, {
168
- libraries,
169
- source: options.source || null
170
- });
171
- const object = decodeObject(objBuffer);
172
- return compileARM64ArtifactFromObject(object, options);
173
- }
174
-
175
- export function runARM64Artifact(executablePathOrBuffer, inputBuffer, options = {}) {
176
- let execPath = executablePathOrBuffer;
177
- let tmpFile = null;
178
-
179
- if (Buffer.isBuffer(executablePathOrBuffer)) {
180
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "k-arm64-run-"));
181
- tmpFile = path.join(tmpDir, "k-exec");
182
- fs.writeFileSync(tmpFile, executablePathOrBuffer, { mode: 0o755 });
183
- execPath = tmpFile;
184
- }
185
-
186
- try {
187
- const args = [];
188
- if (options.json) {
189
- args.push("--json");
190
- }
191
-
192
- const result = spawnSync(execPath, args, {
193
- input: inputBuffer,
194
- maxBuffer: options.maxBuffer || 64 * 1024 * 1024
195
- });
196
-
197
- if (result.error) {
198
- throw result.error;
199
- }
200
-
201
- if (result.status !== 0) {
202
- const stderr = result.stderr?.toString("utf8") || "";
203
- throw new Error(`ARM64 executable failed with exit status ${result.status}: ${stderr}`);
204
- }
205
-
206
- if (options.json) {
207
- return result.stdout.toString("utf8");
208
- }
209
- return result.stdout;
210
- } finally {
211
- if (tmpFile) {
212
- try {
213
- fs.unlinkSync(tmpFile);
214
- fs.rmdirSync(path.dirname(tmpFile));
215
- } catch {
216
- // Ignore temporary cleanup errors
217
- }
218
- }
219
- }
220
- }
221
-
222
- export default {
223
- ARTIFACT_FORMAT,
224
- ARTIFACT_VERSION,
225
- compileARM64ArtifactFromKVM,
226
- compileARM64ArtifactFromObject,
227
- compileARM64Artifact,
228
- runARM64Artifact
229
- };
@@ -1,155 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
-
4
- import { compileLibrary, decodeObject, loadLibrary } from "../../../backend-api.mjs";
5
- import {
6
- compileARM64Artifact,
7
- compileARM64ArtifactFromKVM,
8
- compileARM64ArtifactFromObject
9
- } from "./arm64.mjs";
10
-
11
- export function readAll(stream) {
12
- return new Promise((resolve, reject) => {
13
- const chunks = [];
14
- stream.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
15
- stream.on("end", () => resolve(Buffer.concat(chunks)));
16
- stream.on("error", reject);
17
- });
18
- }
19
-
20
- export function parseCompileOptions(args) {
21
- const libraries = [];
22
- const exportSpecs = [];
23
- let loadedLibrary = false;
24
-
25
- while (args.length > 0) {
26
- if (args[0] === "--") {
27
- args.shift();
28
- break;
29
- }
30
- if (args[0] === "--lib") {
31
- if (loadedLibrary) throw new Error("--lib may only be specified once");
32
- args.shift();
33
- const libPath = args.shift();
34
- if (!libPath) throw new Error("--lib requires a file argument");
35
- const ext = path.extname(libPath).toLowerCase();
36
- if (ext === ".k") {
37
- libraries.push(loadLibrary(compileLibrary(fs.readFileSync(libPath, "utf8"), { source: libPath })));
38
- } else {
39
- libraries.push(loadLibrary(decodeObject(fs.readFileSync(libPath))));
40
- }
41
- loadedLibrary = true;
42
- } else if (args[0] === "--export") {
43
- args.shift();
44
- const spec = args.shift();
45
- if (!spec) throw new Error("--export requires a spec argument (name or libname:localname)");
46
- exportSpecs.push(spec);
47
- } else if (args[0].startsWith("--")) {
48
- break;
49
- } else {
50
- break;
51
- }
52
- }
53
-
54
- return { libraries, exportSpecs };
55
- }
56
-
57
- export function fileInputType(filePath) {
58
- const ext = path.extname(filePath).toLowerCase();
59
- if (ext === ".ko") return "ko";
60
- if (ext === ".kvm") return "kvm";
61
- if (ext === ".klib") return "klib";
62
- return "source-file";
63
- }
64
-
65
- export function resolveProgramInput(args, { allowStdinSource = false } = {}) {
66
- const inputArg = args.shift() ?? null;
67
- if (inputArg == null) {
68
- if (!allowStdinSource) throw new Error("Missing script argument");
69
- return { kind: "stdin-source", sourceName: "<stdin>" };
70
- }
71
-
72
- const ext = path.extname(inputArg).toLowerCase();
73
- if (fs.existsSync(inputArg)) {
74
- const kind = fileInputType(inputArg);
75
- if (kind === "klib") {
76
- throw new Error("Cannot compile a .klib library to ARM64 without a main relation; load it with --lib.");
77
- }
78
- return { kind, path: inputArg, sourceName: inputArg };
79
- }
80
-
81
- if ([".k", ".ko", ".kvm", ".klib"].includes(ext)) {
82
- throw new Error(`Input file not found: ${inputArg}`);
83
- }
84
-
85
- return { kind: "inline-source", source: inputArg, sourceName: "<inline>" };
86
- }
87
-
88
- export async function compileProgramInput(
89
- input,
90
- {
91
- libraries = [],
92
- exportSpecs = [],
93
- stdin = null,
94
- inputEnvelopePattern = null,
95
- entry = null,
96
- emit = null,
97
- outputPath = null
98
- } = {}
99
- ) {
100
- const compileOptions = {
101
- libraries,
102
- exports: exportSpecs,
103
- inputEnvelopePattern,
104
- entry,
105
- emit,
106
- outputPath
107
- };
108
-
109
- if (input.kind === "inline-source") {
110
- return compileARM64Artifact(input.source, {
111
- ...compileOptions,
112
- source: input.sourceName
113
- });
114
- }
115
-
116
- if (input.kind === "stdin-source") {
117
- if (!stdin) throw new Error("stdin source requested without a stdin stream");
118
- const source = (await readAll(stdin)).toString("utf8");
119
- return compileARM64Artifact(source, {
120
- ...compileOptions,
121
- source: input.sourceName
122
- });
123
- }
124
-
125
- if (input.kind === "source-file") {
126
- return compileARM64Artifact(fs.readFileSync(input.path, "utf8"), {
127
- ...compileOptions,
128
- source: input.sourceName
129
- });
130
- }
131
-
132
- if (input.kind === "ko") {
133
- return compileARM64ArtifactFromObject(
134
- decodeObject(fs.readFileSync(input.path)),
135
- compileOptions
136
- );
137
- }
138
-
139
- if (input.kind === "kvm") {
140
- return compileARM64ArtifactFromKVM(
141
- JSON.parse(fs.readFileSync(input.path, "utf8")),
142
- compileOptions
143
- );
144
- }
145
-
146
- throw new Error(`Unsupported input kind: ${input.kind}`);
147
- }
148
-
149
- export default {
150
- compileProgramInput,
151
- fileInputType,
152
- parseCompileOptions,
153
- readAll,
154
- resolveProgramInput
155
- };