@fraczak/k 6.2.2 → 6.2.3
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 +11 -0
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +6 -3
- package/README.md +5 -4
- package/a.klib +1 -0
- package/k.mjs +51 -15
- package/objects/README.md +7 -17
- package/objects/compile.mjs +213 -24
- package/package.json +1 -2
- package/scripts/benchmark-idempotency.mjs +3 -3
- package/tests/integration.sh +18 -1
- package/objects/compile-lib.mjs +0 -67
package/k.mjs
CHANGED
|
@@ -12,19 +12,20 @@ const prog = argv[1];
|
|
|
12
12
|
let kScript, inputStream;
|
|
13
13
|
|
|
14
14
|
function usage() {
|
|
15
|
-
console.error(`Usage: ${prog} [ --lib lib-file ]... ( k-expr | -k file ) [ input-file ]`);
|
|
15
|
+
console.error(`Usage: ${prog} [ --lib lib-file ]... [ --export spec ]... ( k-expr | -k file ) [ input-file ]`);
|
|
16
16
|
console.error(` E.g., echo '["zebara","ela"]' | k-parse --input-type '$x=<{} zebara, {} ela>; $v={x 0, x 1}; $v' | ${prog} '{.1 0}'`);
|
|
17
17
|
console.error("Options:");
|
|
18
|
-
console.error(" --lib file
|
|
19
|
-
console.error("
|
|
18
|
+
console.error(" --lib file Load a .klib dependency before compiling. May be repeated.");
|
|
19
|
+
console.error(" --export spec Export a library alias into scope. 'name' or 'libname:localname'. May be repeated.");
|
|
20
|
+
console.error(" -h, --help Show this help.");
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
function compileFile(
|
|
23
|
-
const buffer = fs.readFileSync(
|
|
23
|
+
function compileFile(filePath, libraries, preamble) {
|
|
24
|
+
const buffer = fs.readFileSync(filePath);
|
|
24
25
|
try {
|
|
25
26
|
return objectToFunction(decodeObject(buffer));
|
|
26
27
|
} catch {
|
|
27
|
-
return k.compile(buffer.toString("utf8"), { libraries });
|
|
28
|
+
return k.compile(preamble + buffer.toString("utf8"), { libraries });
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -36,13 +37,48 @@ function compileFile(path, libraries) {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
const libraries = [];
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
const exports = [];
|
|
41
|
+
// Parse --lib and --export flags
|
|
42
|
+
while (args.length > 0 && args[0].startsWith("--")) {
|
|
43
|
+
if (args[0] === "--lib") {
|
|
44
|
+
args.shift();
|
|
45
|
+
const libPath = args.shift();
|
|
46
|
+
if (!libPath) throw new Error("--lib requires a file argument");
|
|
47
|
+
const libBuffer = fs.readFileSync(libPath);
|
|
48
|
+
libraries.push(loadLibrary(decodeObject(libBuffer)));
|
|
49
|
+
} else if (args[0] === "--export") {
|
|
50
|
+
args.shift();
|
|
51
|
+
const spec = args.shift();
|
|
52
|
+
if (!spec) throw new Error("--export requires a spec argument");
|
|
53
|
+
exports.push(spec);
|
|
54
|
+
} else {
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function buildExportPreamble() {
|
|
60
|
+
if (exports.length === 0) return "";
|
|
61
|
+
const aliasMap = {};
|
|
62
|
+
for (const lib of libraries) {
|
|
63
|
+
for (const [name, hash] of Object.entries(lib.relAlias || {})) {
|
|
64
|
+
if (name !== "__main__") aliasMap[name] = hash;
|
|
65
|
+
}
|
|
66
|
+
for (const [hash, entry] of Object.entries(lib.meta || {})) {
|
|
67
|
+
if (entry?.type !== "rel") continue;
|
|
68
|
+
for (const origin of entry?.origins || []) {
|
|
69
|
+
if (origin?.name && origin.name !== "__main__") aliasMap[origin.name] = hash;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const lines = [];
|
|
74
|
+
for (const spec of exports) {
|
|
75
|
+
const [libName, localName] = spec.includes(":") ? spec.split(":", 2) : [spec, spec];
|
|
76
|
+
const hash = aliasMap[libName];
|
|
77
|
+
if (!hash) throw new Error(`--export: '${libName}' not found in loaded libraries`);
|
|
78
|
+
const body = hash.startsWith("@") ? hash.slice(1) : hash;
|
|
79
|
+
lines.push(`${localName} = @${body};`);
|
|
80
|
+
}
|
|
81
|
+
return lines.join("\n") + "\n";
|
|
46
82
|
}
|
|
47
83
|
|
|
48
84
|
let kScriptStr = (function (arg) {
|
|
@@ -50,9 +86,9 @@ function compileFile(path, libraries) {
|
|
|
50
86
|
throw new Error("Missing script argument");
|
|
51
87
|
}
|
|
52
88
|
if (arg === "-k") {
|
|
53
|
-
return compileFile(args.shift(), libraries);
|
|
89
|
+
return compileFile(args.shift(), libraries, buildExportPreamble());
|
|
54
90
|
} else {
|
|
55
|
-
return arg;
|
|
91
|
+
return buildExportPreamble() + arg;
|
|
56
92
|
}
|
|
57
93
|
})(args.shift());
|
|
58
94
|
let kScript = typeof kScriptStr === "function" ? kScriptStr : k.compile(kScriptStr, { libraries });
|
package/objects/README.md
CHANGED
|
@@ -6,27 +6,17 @@ CLI tools for compiling and inspecting k object files (`.ko`) and library files
|
|
|
6
6
|
|
|
7
7
|
### `k-compile`
|
|
8
8
|
|
|
9
|
-
Compiles
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
Compiles `.k` source into an executable object file (`.ko`), library file
|
|
10
|
+
(`.klib`), or kVM JSON (`.kvm`). Output format is inferred from the output
|
|
11
|
+
extension, or from `--format`.
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
k-compile [--lib lib-file]... [
|
|
14
|
+
k-compile [--lib lib-file]... [--format ko|klib|kvm] [source-snippet | input-file [output-file]]
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
The output is plain JSON with no binary header. It contains the library closure
|
|
21
|
-
formed from loaded `--lib` dependencies plus the compiled source definitions,
|
|
22
|
-
with `main: null`.
|
|
23
|
-
Use `--lib` to build on top of existing libraries.
|
|
24
|
-
Each stored relation includes `typeDerivation.status`; libraries may contain a
|
|
25
|
-
mix of converged and non-converged relations.
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
k-compile-lib [--lib lib-file]... [k-file [lib-file]]
|
|
29
|
-
```
|
|
17
|
+
Existing input paths are read as files. A non-existing input with `.k`, `.ko`,
|
|
18
|
+
or `.klib` extension is reported as a missing file; otherwise it is compiled as
|
|
19
|
+
inline k source, in the same style as `k.mjs`.
|
|
30
20
|
|
|
31
21
|
### `k-decompile`
|
|
32
22
|
|
package/objects/compile.mjs
CHANGED
|
@@ -1,26 +1,50 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
4
5
|
import { argv, exit, stdin, stdout } from "node:process";
|
|
5
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
compileObjectBuffer,
|
|
8
|
+
compileLibraryBuffer,
|
|
9
|
+
decodeObject,
|
|
10
|
+
loadLibrary
|
|
11
|
+
} from "../object.mjs";
|
|
12
|
+
import { lowerToKVM } from "../kvm.mjs";
|
|
13
|
+
import { annotate } from "../index.mjs";
|
|
6
14
|
|
|
7
15
|
function helpText() {
|
|
8
16
|
return [
|
|
9
|
-
"Compile a k source
|
|
10
|
-
"
|
|
17
|
+
"Compile a k source, .ko, or .klib into .ko, .klib, or .kvm output.",
|
|
18
|
+
"Output format is inferred from the output file extension, or from --format.",
|
|
11
19
|
"",
|
|
12
|
-
`Usage: ${argv[1]} [
|
|
20
|
+
`Usage: ${argv[1]} [options] [source-snippet | input-file [output-file]]`,
|
|
13
21
|
"",
|
|
14
22
|
"Arguments:",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
23
|
+
" source-snippet Inline k source, in the same style as k.mjs.",
|
|
24
|
+
" input-file Source .k, .ko, or .klib file. Reads UTF-8 source from stdin when omitted.",
|
|
25
|
+
" output-file Output path (.ko, .klib, or .kvm). Writes to stdout when omitted.",
|
|
17
26
|
"",
|
|
18
27
|
"Options:",
|
|
19
|
-
" --lib file
|
|
20
|
-
"
|
|
28
|
+
" --lib file Load a .klib dependency before compiling. May be repeated.",
|
|
29
|
+
" --export spec Export a library alias into the source scope. May be repeated.",
|
|
30
|
+
" spec is 'name' or 'libname:localname'.",
|
|
31
|
+
" --format fmt Output format: ko, klib, or kvm. Overrides extension detection.",
|
|
32
|
+
" -h, --help Show this help.",
|
|
21
33
|
"",
|
|
22
|
-
"
|
|
23
|
-
|
|
34
|
+
"Existing input paths are read as files. A non-existing input with .k, .ko,",
|
|
35
|
+
"or .klib extension is reported as a missing file; otherwise it is compiled",
|
|
36
|
+
"as inline k source.",
|
|
37
|
+
"",
|
|
38
|
+
"When input is .ko and output is .kvm, the object's relations are lowered",
|
|
39
|
+
"to kVM. A .klib input can only be copied to .klib output.",
|
|
40
|
+
"",
|
|
41
|
+
"Examples:",
|
|
42
|
+
` ${argv[1]} 'x = |x; x x'`,
|
|
43
|
+
` ${argv[1]} program.k program.ko`,
|
|
44
|
+
` ${argv[1]} program.k program.klib`,
|
|
45
|
+
` ${argv[1]} program.k program.kvm`,
|
|
46
|
+
` ${argv[1]} program.ko program.kvm`,
|
|
47
|
+
` ${argv[1]} --lib core.klib --export add --export mul:times program.k program.ko`
|
|
24
48
|
].join("\n");
|
|
25
49
|
}
|
|
26
50
|
|
|
@@ -28,12 +52,100 @@ function usage(stream = console.error) {
|
|
|
28
52
|
stream(helpText());
|
|
29
53
|
}
|
|
30
54
|
|
|
31
|
-
async function
|
|
55
|
+
async function readStdinBytes() {
|
|
32
56
|
const chunks = [];
|
|
33
57
|
for await (const chunk of stdin) {
|
|
34
58
|
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
35
59
|
}
|
|
36
|
-
return Buffer.concat(chunks)
|
|
60
|
+
return Buffer.concat(chunks);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function inferFormat(outputPath) {
|
|
64
|
+
if (!outputPath) return "ko";
|
|
65
|
+
const ext = path.extname(outputPath).toLowerCase();
|
|
66
|
+
if (ext === ".klib") return "klib";
|
|
67
|
+
if (ext === ".kvm") return "kvm";
|
|
68
|
+
return "ko";
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function inferInputType(inputPath) {
|
|
72
|
+
if (!inputPath) return "k";
|
|
73
|
+
const ext = path.extname(inputPath).toLowerCase();
|
|
74
|
+
if (ext === ".ko") return "ko";
|
|
75
|
+
if (ext === ".klib") return "klib";
|
|
76
|
+
return "k";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function resolveInput(inputArg) {
|
|
80
|
+
if (inputArg == null) {
|
|
81
|
+
return { kind: "stdin", type: "k", sourceName: "<stdin>" };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const ext = path.extname(inputArg).toLowerCase();
|
|
85
|
+
if (fs.existsSync(inputArg)) {
|
|
86
|
+
return {
|
|
87
|
+
kind: "file",
|
|
88
|
+
type: inferInputType(inputArg),
|
|
89
|
+
path: inputArg,
|
|
90
|
+
sourceName: inputArg
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (ext === ".k" || ext === ".ko" || ext === ".klib") {
|
|
95
|
+
throw new Error(`Input file not found: ${inputArg}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
kind: "inline",
|
|
100
|
+
type: "k",
|
|
101
|
+
source: inputArg,
|
|
102
|
+
sourceName: "<inline>"
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function buildExportPreamble(exports, libraries) {
|
|
107
|
+
if (exports.length === 0) return "";
|
|
108
|
+
// Build a combined alias map from all libraries: name -> @hash
|
|
109
|
+
const aliasMap = {};
|
|
110
|
+
for (const lib of libraries) {
|
|
111
|
+
for (const [name, hash] of Object.entries(lib.relAlias || {})) {
|
|
112
|
+
if (name !== "__main__") aliasMap[name] = hash;
|
|
113
|
+
}
|
|
114
|
+
for (const [hash, entry] of Object.entries(lib.meta || {})) {
|
|
115
|
+
if (entry?.type !== "rel") continue;
|
|
116
|
+
for (const origin of entry?.origins || []) {
|
|
117
|
+
if (origin?.name && origin.name !== "__main__") {
|
|
118
|
+
aliasMap[origin.name] = hash;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const lines = [];
|
|
124
|
+
for (const spec of exports) {
|
|
125
|
+
const [libName, localName] = spec.includes(":") ? spec.split(":", 2) : [spec, spec];
|
|
126
|
+
const hash = aliasMap[libName];
|
|
127
|
+
if (!hash) throw new Error(`--export: '${libName}' not found in loaded libraries`);
|
|
128
|
+
const body = hash.startsWith("@") ? hash.slice(1) : hash;
|
|
129
|
+
lines.push(`${localName} = @${body};`);
|
|
130
|
+
}
|
|
131
|
+
return lines.join("\n") + "\n";
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function compileToKVM(source, options) {
|
|
135
|
+
const defs = annotate(source, options);
|
|
136
|
+
const kvmProgram = {};
|
|
137
|
+
for (const [name, relDef] of Object.entries(defs.rels)) {
|
|
138
|
+
kvmProgram[name] = lowerToKVM(relDef, name);
|
|
139
|
+
}
|
|
140
|
+
return JSON.stringify(kvmProgram, null, 2) + "\n";
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function objectToKVM(object) {
|
|
144
|
+
const kvmProgram = {};
|
|
145
|
+
for (const [name, relDef] of Object.entries(object.rels)) {
|
|
146
|
+
kvmProgram[name] = lowerToKVM(relDef, name);
|
|
147
|
+
}
|
|
148
|
+
return JSON.stringify(kvmProgram, null, 2) + "\n";
|
|
37
149
|
}
|
|
38
150
|
|
|
39
151
|
try {
|
|
@@ -44,24 +156,101 @@ try {
|
|
|
44
156
|
}
|
|
45
157
|
|
|
46
158
|
const libraries = [];
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
159
|
+
let format = null;
|
|
160
|
+
const exports = [];
|
|
161
|
+
|
|
162
|
+
while (args.length > 0) {
|
|
163
|
+
if (args[0] === "--") {
|
|
164
|
+
args.shift();
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
if (args[0] === "--lib") {
|
|
168
|
+
args.shift();
|
|
169
|
+
const libPath = args.shift();
|
|
170
|
+
if (!libPath) throw new Error("--lib requires a file argument");
|
|
171
|
+
libraries.push(loadLibrary(decodeObject(fs.readFileSync(libPath))));
|
|
172
|
+
} else if (args[0] === "--export") {
|
|
173
|
+
args.shift();
|
|
174
|
+
const spec = args.shift();
|
|
175
|
+
if (!spec) throw new Error("--export requires a spec argument (name or libname:localname)");
|
|
176
|
+
exports.push(spec);
|
|
177
|
+
} else if (args[0] === "--format") {
|
|
178
|
+
args.shift();
|
|
179
|
+
format = args.shift();
|
|
180
|
+
if (!["ko", "klib", "kvm"].includes(format))
|
|
181
|
+
throw new Error(`Unknown format: ${format}. Use ko, klib, or kvm.`);
|
|
182
|
+
} else if (args[0].startsWith("--")) {
|
|
183
|
+
throw new Error(`Unknown option: ${args[0]}`);
|
|
184
|
+
} else {
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const inputArg = args.shift() || null;
|
|
190
|
+
const outputPath = args.shift() || null;
|
|
191
|
+
if (args.length > 0) {
|
|
192
|
+
throw new Error(`Unexpected argument: ${args[0]}`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const outputFormat = format || inferFormat(outputPath);
|
|
196
|
+
const input = resolveInput(inputArg);
|
|
197
|
+
const inputType = input.type;
|
|
198
|
+
|
|
199
|
+
let output;
|
|
200
|
+
|
|
201
|
+
if (inputType === "ko" || inputType === "klib") {
|
|
202
|
+
const buffer = input.kind === "stdin" ? await readStdinBytes() : fs.readFileSync(input.path);
|
|
203
|
+
const object = decodeObject(buffer);
|
|
204
|
+
if (inputType === "klib") {
|
|
205
|
+
libraries.push(loadLibrary(object));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (outputFormat === "kvm") {
|
|
209
|
+
if (inputType === "klib") {
|
|
210
|
+
throw new Error("Cannot produce .kvm from .klib alone; use a .ko or .k input.");
|
|
211
|
+
}
|
|
212
|
+
output = objectToKVM(object);
|
|
213
|
+
} else if (outputFormat === "ko") {
|
|
214
|
+
if (inputType === "ko") {
|
|
215
|
+
// already a .ko, just copy
|
|
216
|
+
output = buffer;
|
|
217
|
+
} else {
|
|
218
|
+
throw new Error("Cannot produce .ko from .klib without a main expression; provide .k source instead.");
|
|
219
|
+
}
|
|
220
|
+
} else if (outputFormat === "klib") {
|
|
221
|
+
if (inputType === "klib") {
|
|
222
|
+
output = buffer;
|
|
223
|
+
} else {
|
|
224
|
+
throw new Error("Cannot produce .klib from .ko; provide .k source instead.");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
} else {
|
|
228
|
+
// Input is .k source
|
|
229
|
+
const rawSource = input.kind === "stdin"
|
|
230
|
+
? (await readStdinBytes()).toString("utf8")
|
|
231
|
+
: input.kind === "inline"
|
|
232
|
+
? input.source
|
|
233
|
+
: fs.readFileSync(input.path, "utf8");
|
|
234
|
+
const preamble = buildExportPreamble(exports, libraries);
|
|
235
|
+
const source = preamble + rawSource;
|
|
236
|
+
const opts = { source: input.sourceName, libraries };
|
|
237
|
+
|
|
238
|
+
if (outputFormat === "ko") {
|
|
239
|
+
output = compileObjectBuffer(source, opts);
|
|
240
|
+
} else if (outputFormat === "klib") {
|
|
241
|
+
output = compileLibraryBuffer(source, opts);
|
|
242
|
+
} else if (outputFormat === "kvm") {
|
|
243
|
+
output = compileToKVM(source, opts);
|
|
244
|
+
}
|
|
52
245
|
}
|
|
53
246
|
|
|
54
|
-
const sourcePath = args.shift();
|
|
55
|
-
const outputPath = args.shift();
|
|
56
|
-
const source = sourcePath == null ? await readStdinText() : fs.readFileSync(sourcePath, "utf8");
|
|
57
|
-
const objectBuffer = compileObjectBuffer(source, { source: sourcePath || "<stdin>", libraries });
|
|
58
247
|
if (outputPath == null) {
|
|
59
|
-
stdout.write(
|
|
248
|
+
stdout.write(output);
|
|
60
249
|
} else {
|
|
61
|
-
fs.writeFileSync(outputPath,
|
|
250
|
+
fs.writeFileSync(outputPath, output);
|
|
62
251
|
}
|
|
63
252
|
} catch (error) {
|
|
64
|
-
console.error(error);
|
|
253
|
+
console.error(error.message || String(error));
|
|
65
254
|
usage();
|
|
66
255
|
exit(1);
|
|
67
256
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fraczak/k",
|
|
3
|
-
"version": "6.2.
|
|
3
|
+
"version": "6.2.3",
|
|
4
4
|
"description": "k — a language for composing first-order partial functions over algebraic data types (products and tagged unions); includes runtime, type derivation, REPL, and codec toolchain",
|
|
5
5
|
"main": "index.mjs",
|
|
6
6
|
"scripts": {
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
"bin": {
|
|
19
19
|
"k": "./k.mjs",
|
|
20
20
|
"k-compile": "./objects/compile.mjs",
|
|
21
|
-
"k-compile-lib": "./objects/compile-lib.mjs",
|
|
22
21
|
"k-decompile": "./objects/decompile.mjs",
|
|
23
22
|
"k-extract-aliases": "./objects/extract-aliases.mjs",
|
|
24
23
|
"k-ieee": "./codecs/ieee.mjs",
|
|
@@ -44,7 +44,7 @@ function formatBytes(value) {
|
|
|
44
44
|
return `${value} B`;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
console.log(`compile
|
|
47
|
+
console.log(`compile/decompile .klib round-trip benchmark (${iterations} iterations)`);
|
|
48
48
|
console.log("example, median, min, max, object");
|
|
49
49
|
|
|
50
50
|
for (const example of benchmarkExamples) {
|
|
@@ -54,9 +54,9 @@ for (const example of benchmarkExamples) {
|
|
|
54
54
|
for (let i = 0; i < iterations; i++) {
|
|
55
55
|
const out = mkdtempSync(join(tmpdir(), `k-idempotency-bench-${example.replaceAll("/", "_")}-`));
|
|
56
56
|
const t0 = performance.now();
|
|
57
|
-
run(["objects/compile
|
|
57
|
+
run(["objects/compile.mjs", example, join(out, "1.klib")]);
|
|
58
58
|
run(["objects/decompile.mjs", join(out, "1.klib"), join(out, "1.k")]);
|
|
59
|
-
run(["objects/compile
|
|
59
|
+
run(["objects/compile.mjs", join(out, "1.k"), join(out, "2.klib")]);
|
|
60
60
|
run(["objects/decompile.mjs", join(out, "2.klib"), join(out, "2.k")]);
|
|
61
61
|
times.push(performance.now() - t0);
|
|
62
62
|
size = statSync(join(out, "1.klib")).size;
|
package/tests/integration.sh
CHANGED
|
@@ -8,6 +8,23 @@ echo "Running './tests/integration.sh' ..."
|
|
|
8
8
|
TMP_DIR=`mktemp -d`
|
|
9
9
|
trap 'rm -rf "$TMP_DIR"' EXIT
|
|
10
10
|
|
|
11
|
+
./objects/compile.mjs 'x = |x; x x' "$TMP_DIR/inline.ko"
|
|
12
|
+
./objects/decompile.mjs "$TMP_DIR/inline.ko" | grep -q '^----- main -----$'
|
|
13
|
+
printf '()' | ./objects/compile.mjs > "$TMP_DIR/stdin.ko"
|
|
14
|
+
./objects/decompile.mjs "$TMP_DIR/stdin.ko" | grep -q '^----- main -----$'
|
|
15
|
+
./objects/compile.mjs --format kvm '()' | grep -q '"__main__"'
|
|
16
|
+
./objects/compile.mjs "$TMP_DIR/stdin.ko" "$TMP_DIR/stdin.kvm"
|
|
17
|
+
grep -q '"__main__"' "$TMP_DIR/stdin.kvm"
|
|
18
|
+
./objects/compile.mjs 'id = ();' "$TMP_DIR/export.klib"
|
|
19
|
+
./objects/compile.mjs --lib "$TMP_DIR/export.klib" --export id:alias 'alias' "$TMP_DIR/export.ko"
|
|
20
|
+
./objects/decompile.mjs "$TMP_DIR/export.ko" | grep -q '^----- main -----$'
|
|
21
|
+
node ./codecs/unit.mjs --parse | ./k.mjs --lib "$TMP_DIR/export.klib" --export id:alias 'alias' | node ./codecs/unit.mjs --print | grep -qx '{}'
|
|
22
|
+
if ./objects/compile.mjs "$TMP_DIR/missing.k" > "$TMP_DIR/missing.out" 2> "$TMP_DIR/missing.err"; then
|
|
23
|
+
echo "expected missing .k input to fail" >&2
|
|
24
|
+
exit 1
|
|
25
|
+
fi
|
|
26
|
+
grep -q 'Input file not found:' "$TMP_DIR/missing.err"
|
|
27
|
+
|
|
11
28
|
echo '["zebara", "ela", "kupa", ala, owca]' | node ./codecs/k-parse.mjs | ./k.mjs '{.1 0,.3 1}' | node ./codecs/k-print.mjs
|
|
12
29
|
echo
|
|
13
30
|
echo '-21' | node ./codecs/int.mjs --parse | node ./codecs/int.mjs --print | grep -qx -- '-21'
|
|
@@ -16,7 +33,7 @@ node ./codecs/unit.mjs --parse | node ./codecs/unit.mjs --print | grep -qx '{}'
|
|
|
16
33
|
echo
|
|
17
34
|
printf 'A🙂\nBé~\t' | ./codecs/utf8.mjs --parse | ./k.mjs -k Examples/byte.k |./codecs/utf8.mjs --print
|
|
18
35
|
echo
|
|
19
|
-
./objects/compile
|
|
36
|
+
./objects/compile.mjs Examples/ieee.k "$TMP_DIR/ieee.klib"
|
|
20
37
|
MUL=`./objects/extract-aliases.mjs "$TMP_DIR/ieee.klib" | grep '^mul = @' | sed 's/^mul = \(@[^;]*\);.*$/\1/'`
|
|
21
38
|
DIV=`./objects/extract-aliases.mjs "$TMP_DIR/ieee.klib" | grep '^div = @' | sed 's/^div = \(@[^;]*\);.*$/\1/'`
|
|
22
39
|
ARG=0.12
|
package/objects/compile-lib.mjs
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import fs from "node:fs";
|
|
4
|
-
import { argv, exit, stdin, stdout } from "node:process";
|
|
5
|
-
import { compileLibraryBuffer, decodeObject, loadLibrary } from "../object.mjs";
|
|
6
|
-
|
|
7
|
-
function helpText() {
|
|
8
|
-
return [
|
|
9
|
-
"Compile a k source file into a plain-JSON .klib library object.",
|
|
10
|
-
"The library records type-derivation convergence for each stored relation.",
|
|
11
|
-
"",
|
|
12
|
-
`Usage: ${argv[1]} [ --lib lib-file ]... [ k-file [ lib-file ] ]`,
|
|
13
|
-
"",
|
|
14
|
-
"Arguments:",
|
|
15
|
-
" k-file Source .k file to compile. Reads UTF-8 source from stdin when omitted.",
|
|
16
|
-
" lib-file Output .klib path. Writes plain JSON library data to stdout when omitted.",
|
|
17
|
-
"",
|
|
18
|
-
"Options:",
|
|
19
|
-
" --lib file Load a .klib dependency before compiling. May be repeated.",
|
|
20
|
-
" -h, --help Show this help.",
|
|
21
|
-
"",
|
|
22
|
-
"Example:",
|
|
23
|
-
` ${argv[1]} --lib core.klib library.k library.klib`
|
|
24
|
-
].join("\n");
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function usage(stream = console.error) {
|
|
28
|
-
stream(helpText());
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async function readStdinText() {
|
|
32
|
-
const chunks = [];
|
|
33
|
-
for await (const chunk of stdin) {
|
|
34
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
35
|
-
}
|
|
36
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
try {
|
|
40
|
-
const args = argv.slice(2);
|
|
41
|
-
if (args.includes("-h") || args.includes("--help")) {
|
|
42
|
-
usage(console.log);
|
|
43
|
-
exit(0);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const libraries = [];
|
|
47
|
-
while (args.length > 0 && args[0] === "--lib") {
|
|
48
|
-
args.shift();
|
|
49
|
-
const libPath = args.shift();
|
|
50
|
-
if (!libPath) throw new Error("--lib requires a file argument");
|
|
51
|
-
libraries.push(loadLibrary(decodeObject(fs.readFileSync(libPath))));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const sourcePath = args.shift();
|
|
55
|
-
const outputPath = args.shift();
|
|
56
|
-
const source = sourcePath == null ? await readStdinText() : fs.readFileSync(sourcePath, "utf8");
|
|
57
|
-
const objectBuffer = compileLibraryBuffer(source, { source: sourcePath || "<stdin>", libraries });
|
|
58
|
-
if (outputPath == null) {
|
|
59
|
-
stdout.write(objectBuffer);
|
|
60
|
-
} else {
|
|
61
|
-
fs.writeFileSync(outputPath, objectBuffer);
|
|
62
|
-
}
|
|
63
|
-
} catch (error) {
|
|
64
|
-
console.error(error);
|
|
65
|
-
usage();
|
|
66
|
-
exit(1);
|
|
67
|
-
}
|