@fraczak/k 7.0.2 → 7.2.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 +75 -0
- package/DOCS/CODECS.md +37 -2
- package/DOCS/CODEC_ARCHITECTURE.md +12 -5
- package/DOCS/FILE_FORMATS.md +238 -15
- package/DOCS/POLYMORPHIC_IR.md +104 -0
- package/DOCS/REPL.md +11 -3
- package/DOCS/WEB_REPL_REQUIREMENTS.md +1 -1
- package/JOURNAL.md +288 -0
- package/README.md +12 -3
- package/Value.mjs +28 -3
- package/access-table.mjs +343 -0
- package/backend-api.mjs +23 -1
- package/backends/llvm/README.md +20 -21
- package/backends/llvm/bin/k-llvm-build.mjs +105 -32
- package/backends/llvm/bin/k-llvm-compile.mjs +63 -24
- package/backends/llvm/bin/k-llvm.mjs +292 -0
- package/backends/llvm/runtime/krt.c +8 -0
- package/backends/llvm/runtime/krt.h +1 -0
- package/backends/llvm/src/cli.mjs +95 -17
- package/backends/llvm/src/executable.mjs +128 -11
- package/backends/llvm/src/kvm2llvm.mjs +10 -5
- package/backends/llvm/src/llvm.mjs +121 -9
- package/backends/llvm/tests/integration.sh +11 -11
- package/backends/llvm/{bin → tests}/k-llvm-run.mjs +48 -22
- package/backends/llvm/tests/perf-support.mjs +24 -3
- package/backends/llvm/tests/test-llvm.mjs +22 -1
- package/backends/wasm/bin/k-wasm-compile.mjs +46 -20
- package/backends/wasm/bin/k-wasm-run.mjs +61 -20
- package/backends/wasm/bin/k-wasm.mjs +47 -13
- package/backends/wasm/src/cli.mjs +141 -19
- package/backends/wasm/src/wasm.mjs +130 -23
- package/browser/repl-browser.mjs +16 -5
- package/browser/tree-view.mjs +47 -8
- package/browser/vfs-data.mjs +6 -5
- package/codecs/README.md +1 -0
- package/codecs/djson.mjs +270 -0
- package/codecs/int.mjs +2 -1
- package/codecs/json.mjs +7 -2
- package/codecs/k-parse.mjs +36 -9
- package/codecs/k-print.mjs +26 -6
- package/codecs/runtime/codec-sdk.mjs +24 -6
- package/codecs/runtime/pattern-json.mjs +80 -1
- package/codecs/runtime/prefix-codec.mjs +629 -67
- package/codecs/runtime/show-value.mjs +93 -51
- package/codecs/runtime/unicode-string.mjs +29 -6
- package/codecs/show.mjs +24 -6
- package/codecs/utf16.mjs +2 -1
- package/k.mjs +56 -16
- package/kir.mjs +58 -19
- package/kvm.mjs +49 -12
- package/objects/compile.mjs +37 -23
- package/objects/decompile.mjs +40 -10
- package/objects/extract-aliases.mjs +44 -14
- package/objects/inspect.mjs +19 -14
- package/objects/validate.mjs +18 -11
- package/package.json +11 -3
- package/pkir.mjs +772 -0
- package/repl.mjs +92 -23
- package/scripts/build-repl-html.mjs +22 -3
- package/scripts/perf-ieee.mjs +264 -13
- package/scripts/perf-int.mjs +315 -22
- package/scripts/perf-multiplication.mjs +58 -7
- package/scripts/perf-poly.mjs +306 -24
- package/scripts/run-tests.mjs +3 -0
- package/tests/test-access-table.mjs +213 -0
- package/tests/test-codecs.mjs +168 -0
- package/tests/test-pkir.mjs +530 -0
- package/tests/test-polymorphic-tdd.mjs +196 -0
- package/tests/test-repl-html.mjs +16 -2
- package/tests/test-repl.mjs +63 -1
- package/backends/llvm/bin/k-llvm-jit.mjs +0 -160
|
@@ -6,7 +6,11 @@ function pLabel(label) {
|
|
|
6
6
|
return nameRE.test(label) ? ` ${label}` : ` ${JSON.stringify(label)}`;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
function propertyListToFilter(
|
|
9
|
+
function propertyListToFilter(
|
|
10
|
+
propertyList,
|
|
11
|
+
varPrefix = "X",
|
|
12
|
+
limit = Infinity
|
|
13
|
+
) {
|
|
10
14
|
if (!propertyList || propertyList.length === 0) return "(...)";
|
|
11
15
|
|
|
12
16
|
const refCount = new Array(propertyList.length).fill(0);
|
|
@@ -22,9 +26,15 @@ function propertyListToFilter(propertyList, varPrefix = "X") {
|
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
const defined = new Set();
|
|
29
|
+
let curLen = 0;
|
|
25
30
|
|
|
26
31
|
function fmt(nodeId) {
|
|
27
|
-
if (
|
|
32
|
+
if (curLen >= limit) return "...";
|
|
33
|
+
if (varNames.has(nodeId) && defined.has(nodeId)) {
|
|
34
|
+
const name = varNames.get(nodeId);
|
|
35
|
+
curLen += name.length;
|
|
36
|
+
return name;
|
|
37
|
+
}
|
|
28
38
|
|
|
29
39
|
const [kind, edges] = propertyList[nodeId];
|
|
30
40
|
const hasVar = varNames.has(nodeId);
|
|
@@ -32,16 +42,35 @@ function propertyListToFilter(propertyList, varPrefix = "X") {
|
|
|
32
42
|
|
|
33
43
|
const suffix = hasVar ? `=${varNames.get(nodeId)}` : "";
|
|
34
44
|
|
|
35
|
-
if (kind === "any")
|
|
45
|
+
if (kind === "any") {
|
|
46
|
+
const s = (hasVar ? varNames.get(nodeId) : "(...)") + suffix;
|
|
47
|
+
curLen += s.length;
|
|
48
|
+
return s;
|
|
49
|
+
}
|
|
36
50
|
|
|
37
51
|
const isOpen = kind.startsWith("open-");
|
|
38
52
|
const isProduct = kind.endsWith("product");
|
|
39
53
|
const open = isProduct ? "{" : "<";
|
|
40
54
|
const close = isProduct ? "}" : ">";
|
|
41
55
|
|
|
42
|
-
if (edges.length === 0 && !isOpen)
|
|
56
|
+
if (edges.length === 0 && !isOpen) {
|
|
57
|
+
const s = `${open}${close}${suffix}`;
|
|
58
|
+
curLen += s.length;
|
|
59
|
+
return s;
|
|
60
|
+
}
|
|
43
61
|
|
|
44
|
-
const fields =
|
|
62
|
+
const fields = [];
|
|
63
|
+
for (let i = 0; i < edges.length; i++) {
|
|
64
|
+
if (curLen >= limit) {
|
|
65
|
+
fields.push("...");
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
const [label, target] = edges[i];
|
|
69
|
+
const targetStr = fmt(target);
|
|
70
|
+
const labelStr = pLabel(label);
|
|
71
|
+
fields.push(`${targetStr}${labelStr}`);
|
|
72
|
+
curLen += targetStr.length + labelStr.length + 2;
|
|
73
|
+
}
|
|
45
74
|
if (isOpen) fields.push("...");
|
|
46
75
|
return `${open}${fields.join(", ")}${close}${suffix}`;
|
|
47
76
|
}
|
|
@@ -49,81 +78,94 @@ function propertyListToFilter(propertyList, varPrefix = "X") {
|
|
|
49
78
|
return fmt(0);
|
|
50
79
|
}
|
|
51
80
|
|
|
52
|
-
function valueToK(root) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
assign(s) { result = s; }
|
|
57
|
-
}];
|
|
81
|
+
function valueToK(root, limit = Infinity) {
|
|
82
|
+
const out = [];
|
|
83
|
+
let curLen = 0;
|
|
84
|
+
const stack = [root];
|
|
58
85
|
|
|
59
86
|
while (stack.length > 0) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
87
|
+
if (curLen >= limit) {
|
|
88
|
+
out.push("...");
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
const item = stack.pop();
|
|
92
|
+
if (typeof item === "string") {
|
|
93
|
+
if (curLen + item.length > limit) {
|
|
94
|
+
out.push(item.slice(0, Math.max(0, limit - curLen)));
|
|
95
|
+
out.push("...");
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
out.push(item);
|
|
99
|
+
curLen += item.length;
|
|
63
100
|
continue;
|
|
64
101
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
102
|
+
|
|
103
|
+
if (item == null) {
|
|
104
|
+
const s = String(item);
|
|
105
|
+
if (curLen + s.length > limit) {
|
|
106
|
+
out.push(s.slice(0, Math.max(0, limit - curLen)));
|
|
107
|
+
out.push("...");
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
out.push(s);
|
|
111
|
+
curLen += s.length;
|
|
69
112
|
continue;
|
|
70
113
|
}
|
|
71
114
|
|
|
72
|
-
|
|
73
|
-
if (isVariant(v)) {
|
|
115
|
+
if (isVariant(item)) {
|
|
74
116
|
const tags = [];
|
|
75
|
-
let curr =
|
|
117
|
+
let curr = item;
|
|
76
118
|
while (isVariant(curr)) {
|
|
77
119
|
tags.push(pLabel(curr.tag).trimStart());
|
|
78
120
|
curr = curr.value;
|
|
121
|
+
if (tags.length > limit) break;
|
|
79
122
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
assign: frame.assign
|
|
85
|
-
};
|
|
86
|
-
stack.push(finishFrame);
|
|
87
|
-
stack.push({
|
|
88
|
-
val: curr,
|
|
89
|
-
assign(s) { finishFrame.base = s; }
|
|
90
|
-
});
|
|
123
|
+
if (tags.length > 0) {
|
|
124
|
+
stack.push("|" + tags.reverse().join("|"));
|
|
125
|
+
}
|
|
126
|
+
stack.push(curr);
|
|
91
127
|
continue;
|
|
92
128
|
}
|
|
93
129
|
|
|
94
|
-
if (isProduct(
|
|
95
|
-
const keys = Object.keys(
|
|
130
|
+
if (isProduct(item)) {
|
|
131
|
+
const keys = Object.keys(item.product);
|
|
96
132
|
if (keys.length === 0) {
|
|
97
|
-
|
|
133
|
+
out.push("{}");
|
|
134
|
+
curLen += 2;
|
|
98
135
|
continue;
|
|
99
136
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
parts,
|
|
104
|
-
assign: frame.assign
|
|
105
|
-
};
|
|
106
|
-
stack.push(finishFrame);
|
|
137
|
+
out.push("{");
|
|
138
|
+
curLen += 1;
|
|
139
|
+
stack.push("}");
|
|
107
140
|
for (let i = keys.length - 1; i >= 0; i--) {
|
|
108
141
|
const k = keys[i];
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
142
|
+
if (i < keys.length - 1) {
|
|
143
|
+
stack.push(", ");
|
|
144
|
+
}
|
|
145
|
+
stack.push(pLabel(k));
|
|
146
|
+
stack.push(item.product[k]);
|
|
114
147
|
}
|
|
115
148
|
continue;
|
|
116
149
|
}
|
|
117
150
|
|
|
118
|
-
|
|
151
|
+
const s = String(item);
|
|
152
|
+
if (curLen + s.length > limit) {
|
|
153
|
+
out.push(s.slice(0, Math.max(0, limit - curLen)));
|
|
154
|
+
out.push("...");
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
out.push(s);
|
|
158
|
+
curLen += s.length;
|
|
119
159
|
}
|
|
120
160
|
|
|
121
|
-
return
|
|
161
|
+
return out.join("");
|
|
122
162
|
}
|
|
123
163
|
|
|
124
|
-
function valueWithEnvelopeToK(value) {
|
|
164
|
+
function valueWithEnvelopeToK(value, limit = Infinity) {
|
|
125
165
|
if (value === undefined) return "... undefined";
|
|
126
|
-
|
|
166
|
+
const valStr = valueToK(value, limit);
|
|
167
|
+
const patStr = propertyListToFilter(value.pattern, "X", limit);
|
|
168
|
+
return `${valStr} ?${patStr}`;
|
|
127
169
|
}
|
|
128
170
|
|
|
129
171
|
export { propertyListToFilter, valueToK, valueWithEnvelopeToK };
|
|
@@ -3,6 +3,15 @@ import { Value, isProduct, isVariant } from "../../Value.mjs";
|
|
|
3
3
|
const UNIT = Value.product({});
|
|
4
4
|
const BIT0 = Value.variant("0", UNIT);
|
|
5
5
|
const BIT1 = Value.variant("1", UNIT);
|
|
6
|
+
const BIT_KEYS = [
|
|
7
|
+
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
let lazyStringDecoder = null;
|
|
11
|
+
|
|
12
|
+
function setLazyStringDecoder(fn) {
|
|
13
|
+
lazyStringDecoder = fn;
|
|
14
|
+
}
|
|
6
15
|
|
|
7
16
|
function bitValue(bit) {
|
|
8
17
|
return bit === 0 ? BIT0 : BIT1;
|
|
@@ -25,7 +34,8 @@ function requireVariant(value, where) {
|
|
|
25
34
|
function bitsProduct(width, n) {
|
|
26
35
|
const product = {};
|
|
27
36
|
for (let i = width - 1; i >= 0; i--) {
|
|
28
|
-
|
|
37
|
+
const key = i < BIT_KEYS.length ? BIT_KEYS[i] : String(i);
|
|
38
|
+
product[key] = bitValue((n >> i) & 1);
|
|
29
39
|
}
|
|
30
40
|
return Value.product(product);
|
|
31
41
|
}
|
|
@@ -34,7 +44,8 @@ function parseBitsProduct(value, maxBit, where) {
|
|
|
34
44
|
const product = requireProduct(value, where);
|
|
35
45
|
let n = 0;
|
|
36
46
|
for (let i = maxBit; i >= 0; i--) {
|
|
37
|
-
const
|
|
47
|
+
const key = i < BIT_KEYS.length ? BIT_KEYS[i] : String(i);
|
|
48
|
+
const entry = requireVariant(product[key], `${where}.bit${i}`);
|
|
38
49
|
if (entry.tag !== "0" && entry.tag !== "1") {
|
|
39
50
|
throw new Error(`${where}.bit${i}: expected tag 0 or 1`);
|
|
40
51
|
}
|
|
@@ -194,20 +205,31 @@ function textToStringValue(text) {
|
|
|
194
205
|
}
|
|
195
206
|
|
|
196
207
|
function stringValueToText(value) {
|
|
197
|
-
|
|
208
|
+
if (lazyStringDecoder) {
|
|
209
|
+
const fast = lazyStringDecoder(value);
|
|
210
|
+
if (fast !== null) return fast;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const chunks = [];
|
|
214
|
+
let chunk = "";
|
|
198
215
|
let cursor = value;
|
|
199
216
|
|
|
200
217
|
while (true) {
|
|
201
218
|
const list = requireVariant(cursor, "string");
|
|
202
219
|
if (list.tag === "nil") {
|
|
203
220
|
requireProduct(list.value, "string.nil");
|
|
204
|
-
|
|
221
|
+
if (chunk.length > 0) chunks.push(chunk);
|
|
222
|
+
return chunks.join("");
|
|
205
223
|
}
|
|
206
224
|
if (list.tag !== "cons") {
|
|
207
225
|
throw new Error(`Unsupported string list tag: ${list.tag}`);
|
|
208
226
|
}
|
|
209
227
|
const pair = requireProduct(list.value, "string.cons");
|
|
210
|
-
|
|
228
|
+
chunk += String.fromCodePoint(unicodeValueToCodePoint(pair.car));
|
|
229
|
+
if (chunk.length >= 8192) {
|
|
230
|
+
chunks.push(chunk);
|
|
231
|
+
chunk = "";
|
|
232
|
+
}
|
|
211
233
|
cursor = pair.cdr;
|
|
212
234
|
}
|
|
213
235
|
}
|
|
@@ -216,5 +238,6 @@ export {
|
|
|
216
238
|
codePointToUnicodeValue,
|
|
217
239
|
unicodeValueToCodePoint,
|
|
218
240
|
textToStringValue,
|
|
219
|
-
stringValueToText
|
|
241
|
+
stringValueToText,
|
|
242
|
+
setLazyStringDecoder
|
|
220
243
|
};
|
package/codecs/show.mjs
CHANGED
|
@@ -6,13 +6,27 @@ import { isMainEntrypoint } from "./runtime/cli-entry.mjs";
|
|
|
6
6
|
import { decodeWire } from "./runtime/prefix-codec.mjs";
|
|
7
7
|
import { propertyListToFilter, valueToK } from "./runtime/show-value.mjs";
|
|
8
8
|
|
|
9
|
+
function helpText() {
|
|
10
|
+
const prog = argv[1] || "show.mjs";
|
|
11
|
+
return [
|
|
12
|
+
"Pass a binary wire stream through unchanged on stdout while",
|
|
13
|
+
"printing the decoded value and filter to stderr.",
|
|
14
|
+
"",
|
|
15
|
+
`Usage: ${prog} [wire-file]`,
|
|
16
|
+
"",
|
|
17
|
+
"Arguments:",
|
|
18
|
+
" wire-file Input binary wire file (default: stdin).",
|
|
19
|
+
"",
|
|
20
|
+
"Options:",
|
|
21
|
+
" -h, --help Show this help.",
|
|
22
|
+
"",
|
|
23
|
+
"Examples:",
|
|
24
|
+
` echo '"hello"' | k-parse | ${prog} | k-print`
|
|
25
|
+
].join("\n");
|
|
26
|
+
}
|
|
27
|
+
|
|
9
28
|
function usage(stream = console.error) {
|
|
10
|
-
stream(
|
|
11
|
-
stream(" Pass the wire stream through unchanged on stdout.");
|
|
12
|
-
stream(" Print the decoded value and filter to stderr.");
|
|
13
|
-
stream("");
|
|
14
|
-
stream("Options:");
|
|
15
|
-
stream(" -h, --help Show this help.");
|
|
29
|
+
stream(helpText());
|
|
16
30
|
}
|
|
17
31
|
|
|
18
32
|
function readAll(stream) {
|
|
@@ -37,6 +51,10 @@ async function main() {
|
|
|
37
51
|
else { usage(); process.exit(1); }
|
|
38
52
|
}
|
|
39
53
|
|
|
54
|
+
stdout.on("error", (err) => {
|
|
55
|
+
if (err.code === "EPIPE") process.exit(0);
|
|
56
|
+
});
|
|
57
|
+
|
|
40
58
|
const buffer = fileArg ? fs.readFileSync(fileArg) : await readAll(stdin);
|
|
41
59
|
|
|
42
60
|
// forward unchanged to stdout
|
package/codecs/utf16.mjs
CHANGED
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
export const doc = `
|
|
11
11
|
UTF-16 text codec (BOM-aware).
|
|
12
12
|
|
|
13
|
-
Reads UTF-16 text (LE/BE with BOM or LE without BOM),
|
|
13
|
+
Reads UTF-16 text (LE/BE with BOM or LE without BOM),
|
|
14
|
+
outputs UTF-16LE with BOM.
|
|
14
15
|
`;
|
|
15
16
|
|
|
16
17
|
function decodeUtf16Input(buf) {
|
package/k.mjs
CHANGED
|
@@ -4,27 +4,58 @@
|
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import { argv, stdin, exit, stdout } from "node:process";
|
|
6
6
|
import k from "./index.mjs";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
import {
|
|
8
|
+
decodeWire,
|
|
9
|
+
encodeToWire
|
|
10
|
+
} from "./codecs/runtime/prefix-codec.mjs";
|
|
11
|
+
import {
|
|
12
|
+
compileLibrary,
|
|
13
|
+
decodeObject,
|
|
14
|
+
objectToFunction,
|
|
15
|
+
loadLibrary
|
|
16
|
+
} from "./object.mjs";
|
|
11
17
|
|
|
12
18
|
let kScript, inputStream;
|
|
13
19
|
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
function helpText() {
|
|
21
|
+
const prog = argv[1] || "k.mjs";
|
|
22
|
+
return [
|
|
23
|
+
"Compile and execute a k expression or file over a binary",
|
|
24
|
+
"pattern+value wire stream using the JavaScript interpreter.",
|
|
25
|
+
"",
|
|
26
|
+
`Usage: ${prog} [options]`,
|
|
27
|
+
" ( source-snippet | input-file ) [ input-wire-file ]",
|
|
28
|
+
"",
|
|
29
|
+
"Arguments:",
|
|
30
|
+
" source-snippet Inline k source snippet.",
|
|
31
|
+
" input-file Source .k, .ko, or .klib file.",
|
|
32
|
+
" input-wire-file Optional binary wire input (default: stdin).",
|
|
33
|
+
"",
|
|
34
|
+
"Options:",
|
|
35
|
+
" --lib file Load one .klib or .k library before compiling.",
|
|
36
|
+
" --export spec Export library alias into scope. Repeatable.",
|
|
37
|
+
" spec is 'name' or 'libname:localname'.",
|
|
38
|
+
" -h, --help Show this help.",
|
|
39
|
+
"",
|
|
40
|
+
"Examples:",
|
|
41
|
+
` echo '"abc"' | k-parse | ${prog} '{.1 0}' | k-print`,
|
|
42
|
+
` echo '{"x":1,"y":2}' | k-json --parse | \\`,
|
|
43
|
+
` ${prog} --lib Examples/poly.k --export concat \\`,
|
|
44
|
+
` 's={()xs,()ys}concat; s' | k-json --print`
|
|
45
|
+
].join("\n");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function usage(stream = console.error) {
|
|
49
|
+
stream(helpText());
|
|
21
50
|
}
|
|
22
51
|
|
|
23
52
|
function isFile(filePath) {
|
|
24
53
|
try {
|
|
25
54
|
return fs.statSync(filePath).isFile();
|
|
26
55
|
} catch (error) {
|
|
27
|
-
if (error?.code === "ENOENT" || error?.code === "ENOTDIR")
|
|
56
|
+
if (error?.code === "ENOENT" || error?.code === "ENOTDIR") {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
28
59
|
throw error;
|
|
29
60
|
}
|
|
30
61
|
}
|
|
@@ -41,7 +72,7 @@ function compileFile(filePath, libraries, preamble) {
|
|
|
41
72
|
({ kScript, inputStream } = ((args) => {
|
|
42
73
|
try {
|
|
43
74
|
if (args.includes("-h") || args.includes("--help")) {
|
|
44
|
-
usage();
|
|
75
|
+
usage(console.log);
|
|
45
76
|
return exit(0);
|
|
46
77
|
}
|
|
47
78
|
|
|
@@ -53,9 +84,18 @@ function compileFile(filePath, libraries, preamble) {
|
|
|
53
84
|
args.shift();
|
|
54
85
|
const libPath = args.shift();
|
|
55
86
|
if (!libPath) throw new Error("--lib requires a file argument");
|
|
56
|
-
if (libraries.length > 0)
|
|
57
|
-
|
|
58
|
-
|
|
87
|
+
if (libraries.length > 0) {
|
|
88
|
+
throw new Error("--lib may be specified at most once");
|
|
89
|
+
}
|
|
90
|
+
if (libPath.endsWith(".k")) {
|
|
91
|
+
const raw = fs.readFileSync(libPath, "utf8");
|
|
92
|
+
libraries.push(
|
|
93
|
+
loadLibrary(compileLibrary(raw, { source: libPath }))
|
|
94
|
+
);
|
|
95
|
+
} else {
|
|
96
|
+
const libBuffer = fs.readFileSync(libPath);
|
|
97
|
+
libraries.push(loadLibrary(decodeObject(libBuffer)));
|
|
98
|
+
}
|
|
59
99
|
} else if (args[0] === "--export") {
|
|
60
100
|
args.shift();
|
|
61
101
|
const spec = args.shift();
|
package/kir.mjs
CHANGED
|
@@ -601,20 +601,27 @@ export default {
|
|
|
601
601
|
};
|
|
602
602
|
|
|
603
603
|
function helpText() {
|
|
604
|
+
const prog = argv[1] || "kir.mjs";
|
|
604
605
|
return [
|
|
605
606
|
"Export the KIR-P JSON view from a k .ko or .klib object.",
|
|
606
607
|
"",
|
|
607
|
-
`Usage: ${
|
|
608
|
+
`Usage: ${prog} [options] [object-file]`,
|
|
608
609
|
"",
|
|
609
610
|
"Arguments:",
|
|
610
|
-
" object-file
|
|
611
|
+
" object-file Input .ko or .klib file (default: stdin).",
|
|
611
612
|
"",
|
|
612
613
|
"Options:",
|
|
614
|
+
" -o, --output path Specify output file path explicitly.",
|
|
613
615
|
" --retype rel Export retyped KIR-P for relation rel.",
|
|
614
|
-
" --input-pattern json Input pattern
|
|
615
|
-
" -h, --help
|
|
616
|
+
" --input-pattern json Input pattern JSON or file for spec.",
|
|
617
|
+
" -h, --help Show this help.",
|
|
616
618
|
"",
|
|
617
|
-
"KIR-P is an inspection/export view; retyping also emits KIR-P."
|
|
619
|
+
"KIR-P is an inspection/export view; retyping also emits KIR-P.",
|
|
620
|
+
"",
|
|
621
|
+
"Examples:",
|
|
622
|
+
` ${prog} program.ko`,
|
|
623
|
+
` ${prog} program.ko -o program.kir.json`,
|
|
624
|
+
` ${prog} --retype main --input-pattern pattern.json program.ko`
|
|
618
625
|
].join("\n");
|
|
619
626
|
}
|
|
620
627
|
|
|
@@ -643,32 +650,64 @@ async function main() {
|
|
|
643
650
|
|
|
644
651
|
let retypeRelation = null;
|
|
645
652
|
let inputPatternArg = null;
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
653
|
+
let explicitOutput = null;
|
|
654
|
+
const remainingArgs = [];
|
|
655
|
+
while (args.length > 0) {
|
|
656
|
+
const arg = args[0];
|
|
657
|
+
if (arg === "-o" || arg === "--output") {
|
|
658
|
+
args.shift();
|
|
659
|
+
explicitOutput = args.shift();
|
|
660
|
+
if (!explicitOutput) {
|
|
661
|
+
throw new Error("-o/--output requires a file argument");
|
|
662
|
+
}
|
|
663
|
+
} else if (arg === "--retype") {
|
|
664
|
+
args.shift();
|
|
649
665
|
retypeRelation = args.shift();
|
|
650
666
|
if (!retypeRelation) throw new Error("--retype requires a relation name");
|
|
651
|
-
} else if (
|
|
667
|
+
} else if (arg === "--input-pattern") {
|
|
668
|
+
args.shift();
|
|
652
669
|
inputPatternArg = args.shift();
|
|
653
|
-
if (!inputPatternArg)
|
|
670
|
+
if (!inputPatternArg) {
|
|
671
|
+
throw new Error("--input-pattern requires JSON or a file path");
|
|
672
|
+
}
|
|
673
|
+
} else if (arg.startsWith("-")) {
|
|
674
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
654
675
|
} else {
|
|
655
|
-
|
|
676
|
+
remainingArgs.push(args.shift());
|
|
656
677
|
}
|
|
657
678
|
}
|
|
658
679
|
|
|
659
|
-
const inputPath =
|
|
660
|
-
if (
|
|
661
|
-
throw new Error(`Unexpected argument: ${
|
|
680
|
+
const inputPath = remainingArgs.shift() || null;
|
|
681
|
+
if (remainingArgs.length > 0) {
|
|
682
|
+
throw new Error(`Unexpected argument: ${remainingArgs[0]}`);
|
|
662
683
|
}
|
|
663
684
|
|
|
664
|
-
const buffer = inputPath == null
|
|
685
|
+
const buffer = inputPath == null
|
|
686
|
+
? await readStdinBytes()
|
|
687
|
+
: fs.readFileSync(inputPath);
|
|
665
688
|
const object = decodeObject(buffer);
|
|
689
|
+
let outputData;
|
|
666
690
|
if (retypeRelation != null) {
|
|
667
|
-
if (inputPatternArg == null)
|
|
668
|
-
|
|
669
|
-
|
|
691
|
+
if (inputPatternArg == null) {
|
|
692
|
+
throw new Error("--retype requires --input-pattern");
|
|
693
|
+
}
|
|
694
|
+
const inputPatternText = fs.existsSync(inputPatternArg)
|
|
695
|
+
? fs.readFileSync(inputPatternArg, "utf8")
|
|
696
|
+
: inputPatternArg;
|
|
697
|
+
outputData = retypeObjectRelation(
|
|
698
|
+
object,
|
|
699
|
+
retypeRelation,
|
|
700
|
+
JSON.parse(inputPatternText)
|
|
701
|
+
);
|
|
702
|
+
} else {
|
|
703
|
+
outputData = objectToKIRP(object);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
const json = JSON.stringify(outputData, null, 2) + "\n";
|
|
707
|
+
if (explicitOutput) {
|
|
708
|
+
fs.writeFileSync(explicitOutput, json, "utf8");
|
|
670
709
|
} else {
|
|
671
|
-
stdout.write(
|
|
710
|
+
stdout.write(json);
|
|
672
711
|
}
|
|
673
712
|
}
|
|
674
713
|
|
package/kvm.mjs
CHANGED
|
@@ -9,7 +9,12 @@ import {
|
|
|
9
9
|
} from "./run.mjs";
|
|
10
10
|
import { decodeWire, encodeToWire } from "./codecs/runtime/prefix-codec.mjs";
|
|
11
11
|
import { intersectPropertyListPatterns } from "./codecs/runtime/codec.mjs";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
compileLibrary,
|
|
14
|
+
compileObjectBuffer,
|
|
15
|
+
decodeObject,
|
|
16
|
+
loadLibrary
|
|
17
|
+
} from "./object.mjs";
|
|
13
18
|
import codes from "./codes.mjs";
|
|
14
19
|
import { isMainEntrypoint } from "./codecs/runtime/cli-entry.mjs";
|
|
15
20
|
import { isIntrinsic, unsupportedIntrinsic } from "./intrinsics.mjs";
|
|
@@ -964,20 +969,43 @@ export default {
|
|
|
964
969
|
specializeKVM
|
|
965
970
|
};
|
|
966
971
|
|
|
967
|
-
function
|
|
972
|
+
function helpText() {
|
|
968
973
|
const prog = argv[1] || "kvm.mjs";
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
974
|
+
return [
|
|
975
|
+
"Execute a k expression or file via the kVM bytecode interpreter",
|
|
976
|
+
"over a binary pattern+value wire stream.",
|
|
977
|
+
"",
|
|
978
|
+
`Usage: ${prog} [options]`,
|
|
979
|
+
" ( source-snippet | input-file ) [ input-wire-file ]",
|
|
980
|
+
"",
|
|
981
|
+
"Arguments:",
|
|
982
|
+
" source-snippet Inline k source snippet.",
|
|
983
|
+
" input-file Source .k, .ko, or .klib file.",
|
|
984
|
+
" input-wire-file Optional binary wire input (default: stdin).",
|
|
985
|
+
"",
|
|
986
|
+
"Options:",
|
|
987
|
+
" --lib file Load one .klib or .k library before compiling.",
|
|
988
|
+
" --export spec Export library alias into scope. Repeatable.",
|
|
989
|
+
" spec is 'name' or 'libname:localname'.",
|
|
990
|
+
" --envelope-free Run the interpreter in envelope-free mode.",
|
|
991
|
+
" -h, --help Show this help.",
|
|
992
|
+
"",
|
|
993
|
+
"Examples:",
|
|
994
|
+
` echo '"abc"' | k-parse | ${prog} '{.1 0}' | k-print`,
|
|
995
|
+
` echo '{"x":1,"y":2}' | k-json --parse | \\`,
|
|
996
|
+
` ${prog} --lib Examples/poly.k --export concat \\`,
|
|
997
|
+
` 's={()xs,()ys}concat; s' | k-json --print`
|
|
998
|
+
].join("\n");
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
function usage(stream = console.error) {
|
|
1002
|
+
stream(helpText());
|
|
975
1003
|
}
|
|
976
1004
|
|
|
977
1005
|
async function main() {
|
|
978
1006
|
const args = argv.slice(2);
|
|
979
1007
|
if (args.includes("-h") || args.includes("--help")) {
|
|
980
|
-
usage();
|
|
1008
|
+
usage(console.log);
|
|
981
1009
|
return exit(0);
|
|
982
1010
|
}
|
|
983
1011
|
|
|
@@ -994,9 +1022,18 @@ async function main() {
|
|
|
994
1022
|
args.shift();
|
|
995
1023
|
const libPath = args.shift();
|
|
996
1024
|
if (!libPath) throw new Error("--lib requires a file argument");
|
|
997
|
-
if (libraries.length > 0)
|
|
998
|
-
|
|
999
|
-
|
|
1025
|
+
if (libraries.length > 0) {
|
|
1026
|
+
throw new Error("--lib may be specified at most once");
|
|
1027
|
+
}
|
|
1028
|
+
if (libPath.endsWith(".k")) {
|
|
1029
|
+
const raw = fs.readFileSync(libPath, "utf8");
|
|
1030
|
+
libraries.push(
|
|
1031
|
+
loadLibrary(compileLibrary(raw, { source: libPath }))
|
|
1032
|
+
);
|
|
1033
|
+
} else {
|
|
1034
|
+
const libBuffer = fs.readFileSync(libPath);
|
|
1035
|
+
libraries.push(loadLibrary(decodeObject(libBuffer)));
|
|
1036
|
+
}
|
|
1000
1037
|
} else if (args[0] === "--export") {
|
|
1001
1038
|
args.shift();
|
|
1002
1039
|
const spec = args.shift();
|