@fraczak/k 5.1.2 → 6.0.1
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/.codex +0 -0
- package/Code-derivation-tests/blowup.mjs +3 -3
- package/Code-derivation-tests/bnat.mjs +2 -2
- package/Code-derivation-tests/codec-witness-pattern.mjs +50 -0
- package/Code-derivation-tests/convergence-strategy.mjs +24 -0
- package/Code-derivation-tests/dot.mjs +12 -9
- package/Code-derivation-tests/filter-syntax.mjs +21 -0
- package/Code-derivation-tests/loop.mjs +8 -2
- package/Code-derivation-tests/nat.mjs +1 -1
- package/Code-derivation-tests/not-not.mjs +3 -3
- package/Code-derivation-tests/pattern-envelope.mjs +68 -0
- package/Code-derivation-tests/rlz.mjs +2 -2
- package/{BIG_PICTURE.md → DOCS/BIG_PICTURE.md} +103 -50
- package/DOCS/REPL.md +191 -0
- package/DOCS/a.html +398 -0
- package/DOCS/book/01-introduction.md +51 -0
- package/DOCS/book/02-syntax-and-values.md +111 -0
- package/DOCS/book/03-types-as-finite-automata.md +156 -0
- package/DOCS/book/04-partial-functions-and-composition.md +146 -0
- package/DOCS/book/05-typing-filters-and-normalization.md +111 -0
- package/DOCS/book-combined.html +3798 -0
- package/DOCS/book-combined.md +3745 -0
- package/DOCS/book-combined.pdf +0 -0
- package/DOCS/book-combined.tex +5682 -0
- package/DOCS/book.html +65 -0
- package/DOCS/book.md +54 -0
- package/DOCS/book.pdf +0 -0
- package/DOCS/book.tex +150 -0
- package/NAT.k~ +452 -0
- package/README.md +204 -508
- package/TypeGraph.mjs +43 -0
- package/TypePatternGraph.mjs +251 -0
- package/Value.mjs +192 -0
- package/augmentation.mjs +198 -0
- package/codecs/BINARY_FORMAT.html +471 -0
- package/codecs/BINARY_FORMAT.md +53 -0
- package/codecs/POLYMORPHIC_BINARY_FORMAT.html +355 -0
- package/codecs/POLYMORPHIC_BINARY_FORMAT.md +303 -0
- package/codecs/README.md +215 -0
- package/codecs/example-pipeline.mjs +149 -0
- package/codecs/ieee.mjs +140 -0
- package/codecs/int.mjs +104 -0
- package/codecs/json-codec.mjs +215 -0
- package/codecs/json.mjs +40 -0
- package/codecs/k-parse.mjs +90 -0
- package/codecs/k-pattern.mjs +75 -0
- package/codecs/k-print.mjs +46 -0
- package/codecs/runtime/codec.mjs +768 -0
- package/codecs/runtime/ieee-pattern.mjs +30 -0
- package/codecs/runtime/pattern-json.mjs +96 -0
- package/codecs/runtime/prefix-codec.mjs +425 -0
- package/codecs/runtime/show-value.mjs +68 -0
- package/codecs/runtime/typeFromValue.mjs +34 -0
- package/codecs/runtime/unicode-string.mjs +220 -0
- package/codecs/show.mjs +41 -0
- package/codecs/string-codec.mjs +80 -0
- package/codecs/unit.mjs +51 -0
- package/codecs/utf16.mjs +66 -0
- package/codecs/utf8.mjs +37 -0
- package/codes.mjs +146 -44
- package/compiler.mjs +111 -0
- package/convergence.mjs +197 -0
- package/core.k +197 -0
- package/export.mjs +22 -32
- package/hash.mjs +29 -31
- package/ieee.klib +0 -0
- package/index.mjs +41 -15
- package/k-vscode/.vscode/launch.json +14 -0
- package/k-vscode/README.md +65 -0
- package/k-vscode/language-configuration.json +42 -0
- package/k-vscode/package-lock.json +4176 -0
- package/k-vscode/package.json +57 -0
- package/k-vscode/snippets/k.json +92 -0
- package/k-vscode/syntaxes/k.tmLanguage.json +243 -0
- package/k.mjs +56 -54
- package/object.mjs +517 -0
- package/objects/README.md +38 -0
- package/objects/compile-lib.mjs +42 -0
- package/objects/compile.mjs +42 -0
- package/objects/decompile.mjs +32 -0
- package/package.json +13 -6
- package/parser.jison +27 -46
- package/parser.mjs +68 -100
- package/pretty.mjs +21 -40
- package/repl2.mjs +662 -0
- package/run.mjs +264 -231
- package/symbol-table.mjs +3 -17
- package/test-fingerprint.mjs +7 -7
- package/test-hash-fuzz.mjs +107 -0
- package/test-hash-normalization.mjs +134 -0
- package/test-k-object.mjs +74 -0
- package/test-repl2.mjs +106 -0
- package/test.mjs +45 -70
- package/tests.sh +10 -1
- package/type_registry/registry.mjs~ +105 -0
- package/type_registry/typeParser.jison~ +132 -0
- package/typing.mjs +129 -676
- package/unification.mjs +157 -0
- package/valueIO.mjs +54 -0
- package/valueParser.jison +143 -0
- package/valueParser.mjs +713 -0
- package/Code-derivation-tests/built-in.mjs +0 -19
- package/Code-derivation-tests/vector.mjs +0 -19
- package/Filters/bug.k +0 -3
- package/Filters/composing.k +0 -15
- package/Filters/filter.k +0 -9
- package/TODO.md +0 -53
- package/TYPING.md +0 -365
- package/k-repl.cast +0 -1913
- package/k.cast +0 -618
- package/my-objects.json +0 -6
- package/patterns.mjs +0 -543
- package/repl.mjs +0 -213
- package/test-filters.mjs +0 -45
- package/typing-test.mjs +0 -40
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { Product, Variant } from "../Value.mjs";
|
|
2
|
+
import { STRING_PATTERN_PROPERTY_LIST, textToStringValue, stringValueToText } from "./string-codec.mjs";
|
|
3
|
+
import { FLOAT64_PATTERN } from "./runtime/ieee-pattern.mjs";
|
|
4
|
+
|
|
5
|
+
const UNIT = new Product({});
|
|
6
|
+
const BOOL_PATTERN = [
|
|
7
|
+
["closed-union", [["false", 1], ["true", 1]]],
|
|
8
|
+
["closed-product", []]
|
|
9
|
+
];
|
|
10
|
+
const NULL_PATTERN = [
|
|
11
|
+
["closed-union", [["null", 1]]],
|
|
12
|
+
["closed-product", []]
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
function bitValue(bit) {
|
|
16
|
+
return new Variant(bit === 0 ? "0" : "1", UNIT);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function bitsProduct(width, value) {
|
|
20
|
+
const big = BigInt(value);
|
|
21
|
+
const product = {};
|
|
22
|
+
for (let i = width - 1; i >= 0; i--) {
|
|
23
|
+
product[String(i)] = bitValue(Number((big >> BigInt(i)) & 1n));
|
|
24
|
+
}
|
|
25
|
+
return new Product(product);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function encodeNumberToValue(number) {
|
|
29
|
+
const buf = Buffer.alloc(8);
|
|
30
|
+
buf.writeDoubleBE(number, 0);
|
|
31
|
+
const bits = buf.readBigUInt64BE(0);
|
|
32
|
+
const sign = Number((bits >> 63n) & 1n);
|
|
33
|
+
const exponent = Number((bits >> 52n) & 0x7ffn);
|
|
34
|
+
const fraction = bits & ((1n << 52n) - 1n);
|
|
35
|
+
|
|
36
|
+
return new Product({
|
|
37
|
+
sign: new Variant(sign === 0 ? "+" : "-", UNIT),
|
|
38
|
+
exponent: bitsProduct(11, exponent),
|
|
39
|
+
fraction: bitsProduct(52, fraction)
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function requireProduct(value, where) {
|
|
44
|
+
if (!(value instanceof Product)) {
|
|
45
|
+
throw new Error(`${where}: expected Product`);
|
|
46
|
+
}
|
|
47
|
+
return value.product;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function requireVariant(value, where) {
|
|
51
|
+
if (!(value instanceof Variant)) {
|
|
52
|
+
throw new Error(`${where}: expected Variant`);
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function parseBitsProduct(value, maxBit, where) {
|
|
58
|
+
const product = requireProduct(value, where);
|
|
59
|
+
let n = 0n;
|
|
60
|
+
for (let i = maxBit; i >= 0; i--) {
|
|
61
|
+
const entry = requireVariant(product[String(i)], `${where}.bit${i}`);
|
|
62
|
+
if (entry.tag !== "0" && entry.tag !== "1") {
|
|
63
|
+
throw new Error(`${where}.bit${i}: expected tag 0 or 1`);
|
|
64
|
+
}
|
|
65
|
+
n = (n << 1n) | BigInt(entry.tag === "1" ? 1 : 0);
|
|
66
|
+
}
|
|
67
|
+
return n;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function decodeValueToNumber(value) {
|
|
71
|
+
const product = requireProduct(value, "json.number");
|
|
72
|
+
const sign = requireVariant(product.sign, "json.number.sign");
|
|
73
|
+
if (sign.tag !== "+" && sign.tag !== "-") {
|
|
74
|
+
throw new Error(`json.number.sign: expected + or -, got ${sign.tag}`);
|
|
75
|
+
}
|
|
76
|
+
const exponent = parseBitsProduct(product.exponent, 10, "json.number.exponent");
|
|
77
|
+
const fraction = parseBitsProduct(product.fraction, 51, "json.number.fraction");
|
|
78
|
+
|
|
79
|
+
const bits =
|
|
80
|
+
(BigInt(sign.tag === "-" ? 1 : 0) << 63n) |
|
|
81
|
+
(exponent << 52n) |
|
|
82
|
+
fraction;
|
|
83
|
+
|
|
84
|
+
const buf = Buffer.alloc(8);
|
|
85
|
+
buf.writeBigUInt64BE(bits, 0);
|
|
86
|
+
return buf.readDoubleBE(0);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function fromJsonValue(value) {
|
|
90
|
+
if (value === null) {
|
|
91
|
+
return new Variant("null", UNIT);
|
|
92
|
+
}
|
|
93
|
+
if (typeof value === "boolean") {
|
|
94
|
+
return new Variant(value ? "true" : "false", UNIT);
|
|
95
|
+
}
|
|
96
|
+
if (typeof value === "number") {
|
|
97
|
+
if (!Number.isFinite(value)) {
|
|
98
|
+
throw new Error("JSON numbers must be finite");
|
|
99
|
+
}
|
|
100
|
+
return encodeNumberToValue(value);
|
|
101
|
+
}
|
|
102
|
+
if (typeof value === "string") {
|
|
103
|
+
return textToStringValue(value);
|
|
104
|
+
}
|
|
105
|
+
if (Array.isArray(value)) {
|
|
106
|
+
return new Product(
|
|
107
|
+
value.reduce((product, item, index) => {
|
|
108
|
+
product[String(index)] = fromJsonValue(item);
|
|
109
|
+
return product;
|
|
110
|
+
}, {})
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
if (value && typeof value === "object") {
|
|
114
|
+
return new Product(
|
|
115
|
+
Object.keys(value).reduce((product, key) => {
|
|
116
|
+
product[key] = fromJsonValue(value[key]);
|
|
117
|
+
return product;
|
|
118
|
+
}, {})
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
throw new Error(`Unsupported JSON value: ${value}`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function composePattern(kind, entries) {
|
|
125
|
+
const result = [[kind, []]];
|
|
126
|
+
|
|
127
|
+
for (const [label, childPattern] of entries) {
|
|
128
|
+
const offset = result.length;
|
|
129
|
+
result[0][1].push([label, offset]);
|
|
130
|
+
for (const [childKind, childEdges] of childPattern) {
|
|
131
|
+
result.push([
|
|
132
|
+
childKind,
|
|
133
|
+
childEdges.map(([edgeLabel, target]) => [edgeLabel, target + offset])
|
|
134
|
+
]);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function patternFromJsonValue(value) {
|
|
142
|
+
if (value === null) return NULL_PATTERN;
|
|
143
|
+
if (typeof value === "boolean") return BOOL_PATTERN;
|
|
144
|
+
if (typeof value === "number") return FLOAT64_PATTERN;
|
|
145
|
+
if (typeof value === "string") return STRING_PATTERN_PROPERTY_LIST;
|
|
146
|
+
if (Array.isArray(value)) {
|
|
147
|
+
return composePattern(
|
|
148
|
+
"closed-product",
|
|
149
|
+
value.map((item, index) => [String(index), patternFromJsonValue(item)])
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
if (value && typeof value === "object") {
|
|
153
|
+
return composePattern(
|
|
154
|
+
"closed-product",
|
|
155
|
+
Object.keys(value)
|
|
156
|
+
.sort((a, b) => Buffer.compare(Buffer.from(a, "utf8"), Buffer.from(b, "utf8")))
|
|
157
|
+
.map((key) => [key, patternFromJsonValue(value[key])])
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
throw new Error(`Unsupported JSON value: ${value}`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function toJsonValue(value) {
|
|
164
|
+
if (value instanceof Variant) {
|
|
165
|
+
if (value.tag === "null") {
|
|
166
|
+
requireProduct(value.value, "json.null");
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
if (value.tag === "true") {
|
|
170
|
+
requireProduct(value.value, "json.true");
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
if (value.tag === "false") {
|
|
174
|
+
requireProduct(value.value, "json.false");
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
return stringValueToText(value);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const product = requireProduct(value, "json.value");
|
|
181
|
+
const keys = Object.keys(product);
|
|
182
|
+
const isArray = keys.every((key, index) => key === String(index));
|
|
183
|
+
|
|
184
|
+
if (isArray) {
|
|
185
|
+
return keys.map((key) => {
|
|
186
|
+
const child = product[key];
|
|
187
|
+
if (child instanceof Variant) return toJsonValue(child);
|
|
188
|
+
if (child instanceof Product) {
|
|
189
|
+
try {
|
|
190
|
+
return decodeValueToNumber(child);
|
|
191
|
+
} catch {}
|
|
192
|
+
}
|
|
193
|
+
return toJsonValue(child);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Distinguish object from number by shape first.
|
|
198
|
+
const numberKeys = ["exponent", "fraction", "sign"];
|
|
199
|
+
if (keys.length === numberKeys.length && numberKeys.every((key) => key in product)) {
|
|
200
|
+
return decodeValueToNumber(value);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Distinguish object from string list by trying the string decoder.
|
|
204
|
+
try {
|
|
205
|
+
return stringValueToText(value);
|
|
206
|
+
} catch {}
|
|
207
|
+
|
|
208
|
+
return keys.reduce((result, key) => {
|
|
209
|
+
result[key] = toJsonValue(product[key]);
|
|
210
|
+
return result;
|
|
211
|
+
}, {});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export { fromJsonValue, toJsonValue, patternFromJsonValue, encodeNumberToValue, decodeValueToNumber, BOOL_PATTERN, NULL_PATTERN };
|
|
215
|
+
export default { fromJsonValue, toJsonValue, patternFromJsonValue, encodeNumberToValue, decodeValueToNumber, BOOL_PATTERN, NULL_PATTERN };
|
package/codecs/json.mjs
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { stdin, stdout, argv, exit } from "node:process";
|
|
4
|
+
import { decodeWire, encodeToWire } from "./runtime/prefix-codec.mjs";
|
|
5
|
+
import { fromJsonValue, toJsonValue, patternFromJsonValue } from "./json-codec.mjs";
|
|
6
|
+
|
|
7
|
+
function readAll(stream) {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
const chunks = [];
|
|
10
|
+
stream.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
|
|
11
|
+
stream.on("end", () => resolve(Buffer.concat(chunks)));
|
|
12
|
+
stream.on("error", reject);
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function main() {
|
|
17
|
+
const args = argv.slice(2);
|
|
18
|
+
if (args.length !== 1 || (args[0] !== "--parse" && args[0] !== "--print")) {
|
|
19
|
+
console.error("Usage: json.mjs --parse | --print");
|
|
20
|
+
console.error(" --parse read JSON from stdin, write binary pattern+value stream");
|
|
21
|
+
console.error(" --print read binary pattern+value stream from stdin, write JSON");
|
|
22
|
+
exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const buf = await readAll(stdin);
|
|
26
|
+
|
|
27
|
+
if (args[0] === "--parse") {
|
|
28
|
+
const json = JSON.parse(buf.toString("utf8"));
|
|
29
|
+
const value = fromJsonValue(json);
|
|
30
|
+
stdout.write(encodeToWire(value, patternFromJsonValue(json)));
|
|
31
|
+
} else {
|
|
32
|
+
const { value } = decodeWire(buf);
|
|
33
|
+
stdout.write(`${JSON.stringify(toJsonValue(value))}\n`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
main().catch((error) => {
|
|
38
|
+
console.error(error.stack || error.message || String(error));
|
|
39
|
+
exit(1);
|
|
40
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import { argv, stdin, exit, stdout } from "node:process";
|
|
5
|
+
import k from "../index.mjs";
|
|
6
|
+
import { parseValue } from "../valueIO.mjs";
|
|
7
|
+
import { exportPatternGraph } from "./runtime/codec.mjs";
|
|
8
|
+
import { patternToPropertyList } from "./runtime/pattern-json.mjs";
|
|
9
|
+
import { encodeToWire } from "./runtime/prefix-codec.mjs";
|
|
10
|
+
|
|
11
|
+
function usage(prog) {
|
|
12
|
+
console.error(`Usage: ${prog} [--input-type <type-script|type-file> | --input-pattern <pattern-script|pattern-file>] [value-file]`);
|
|
13
|
+
console.error(" Parse a textual k value and emit the self-hosted binary pattern+value stream.");
|
|
14
|
+
console.error(" If no pattern or type is provided, derive a closed pattern from the value.");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function maybeReadFile(s) {
|
|
18
|
+
if (!s) return s;
|
|
19
|
+
if (fs.existsSync(s) && fs.statSync(s).isFile()) {
|
|
20
|
+
return fs.readFileSync(s, "utf8");
|
|
21
|
+
}
|
|
22
|
+
return s;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function readAll(stream) {
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
const chunks = [];
|
|
28
|
+
stream.on("data", (chunk) => chunks.push(chunk));
|
|
29
|
+
stream.on("end", () => resolve(Buffer.concat(chunks.map((c) => Buffer.isBuffer(c) ? c : Buffer.from(c)))));
|
|
30
|
+
stream.on("error", reject);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function propertyListFromScript(script) {
|
|
35
|
+
const annotated = k.annotate(script);
|
|
36
|
+
const mainRel = annotated.rels.__main__;
|
|
37
|
+
if (!mainRel || !mainRel.typePatternGraph) {
|
|
38
|
+
throw new Error("Could not resolve __main__ relation");
|
|
39
|
+
}
|
|
40
|
+
if (mainRel.def.op !== "filter" && mainRel.def.op !== "code") {
|
|
41
|
+
throw new Error("Input script must end with a filter or a type name");
|
|
42
|
+
}
|
|
43
|
+
const rootPatternId = mainRel.typePatternGraph.find(mainRel.def.patterns[0]);
|
|
44
|
+
const pattern = exportPatternGraph(mainRel.typePatternGraph, rootPatternId);
|
|
45
|
+
return patternToPropertyList(pattern);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function main() {
|
|
49
|
+
const prog = argv[1];
|
|
50
|
+
const args = argv.slice(2);
|
|
51
|
+
|
|
52
|
+
let inputTypeArg = null;
|
|
53
|
+
let inputPatternArg = null;
|
|
54
|
+
let valueFile = null;
|
|
55
|
+
|
|
56
|
+
for (let i = 0; i < args.length; i++) {
|
|
57
|
+
if (args[i] === "--input-type") {
|
|
58
|
+
inputTypeArg = args[++i];
|
|
59
|
+
} else if (args[i] === "--input-pattern") {
|
|
60
|
+
inputPatternArg = args[++i];
|
|
61
|
+
} else if (valueFile == null) {
|
|
62
|
+
valueFile = args[i];
|
|
63
|
+
} else {
|
|
64
|
+
usage(prog);
|
|
65
|
+
return exit(1);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (inputTypeArg != null && inputPatternArg != null) {
|
|
70
|
+
usage(prog);
|
|
71
|
+
return exit(1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const inputBuffer = valueFile ? fs.readFileSync(valueFile) : await readAll(stdin);
|
|
75
|
+
const inputText = inputBuffer.toString("utf8");
|
|
76
|
+
const value = parseValue(inputText, null, null);
|
|
77
|
+
|
|
78
|
+
const propertyList = (() => {
|
|
79
|
+
if (inputTypeArg != null) return propertyListFromScript(maybeReadFile(inputTypeArg));
|
|
80
|
+
if (inputPatternArg != null) return propertyListFromScript(maybeReadFile(inputPatternArg));
|
|
81
|
+
return null;
|
|
82
|
+
})();
|
|
83
|
+
|
|
84
|
+
stdout.write(encodeToWire(value, propertyList));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
main().catch((error) => {
|
|
88
|
+
console.error(error.stack || error.message || String(error));
|
|
89
|
+
process.exit(1);
|
|
90
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import { argv, exit, stdin, stdout } from "node:process";
|
|
5
|
+
import k from "../index.mjs";
|
|
6
|
+
import { exportPatternGraph } from "./runtime/codec.mjs";
|
|
7
|
+
import { patternToPropertyList } from "./runtime/pattern-json.mjs";
|
|
8
|
+
|
|
9
|
+
function usage(prog) {
|
|
10
|
+
console.error(`Usage: ${prog} [script-or-file]`);
|
|
11
|
+
console.error(" Read a k script from a file argument or stdin.");
|
|
12
|
+
console.error(" The main expression must be a filter or a type name.");
|
|
13
|
+
console.error(" Output is the canonical JSON pattern array.");
|
|
14
|
+
console.error(" Example:");
|
|
15
|
+
console.error(` cat pattern.k | ${prog}`);
|
|
16
|
+
console.error(` ${prog} '$ bits = < {} _, bits 0, bits 1 >; ?< {} nil, { $bits car, X cdr } cons > = X'`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function maybeReadFile(s) {
|
|
20
|
+
if (!s) return s;
|
|
21
|
+
if (fs.existsSync(s) && fs.statSync(s).isFile()) {
|
|
22
|
+
return fs.readFileSync(s, "utf8");
|
|
23
|
+
}
|
|
24
|
+
return s;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function readAll(stream) {
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
const chunks = [];
|
|
30
|
+
stream.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
|
|
31
|
+
stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
32
|
+
stream.on("error", reject);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function rootPatternIdFromMainRel(mainRel) {
|
|
37
|
+
if (!mainRel || !mainRel.typePatternGraph) {
|
|
38
|
+
throw new Error("Could not resolve __main__ relation");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
switch (mainRel.def.op) {
|
|
42
|
+
case "filter":
|
|
43
|
+
case "code":
|
|
44
|
+
return mainRel.typePatternGraph.find(mainRel.def.patterns[0]);
|
|
45
|
+
default:
|
|
46
|
+
throw new Error("Main expression must be a filter or a type name");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function main() {
|
|
51
|
+
const prog = argv[1];
|
|
52
|
+
const args = argv.slice(2);
|
|
53
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
54
|
+
usage(prog);
|
|
55
|
+
return exit(0);
|
|
56
|
+
}
|
|
57
|
+
if (args.length > 1) {
|
|
58
|
+
usage(prog);
|
|
59
|
+
return exit(1);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const script = args.length === 1 ? maybeReadFile(args[0]) : await readAll(stdin);
|
|
63
|
+
const annotated = k.annotate(script);
|
|
64
|
+
const mainRel = annotated.rels.__main__;
|
|
65
|
+
const rootPatternId = rootPatternIdFromMainRel(mainRel);
|
|
66
|
+
const pattern = exportPatternGraph(mainRel.typePatternGraph, rootPatternId);
|
|
67
|
+
const propertyList = patternToPropertyList(pattern);
|
|
68
|
+
|
|
69
|
+
stdout.write(`${JSON.stringify(propertyList)}\n`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
main().catch((error) => {
|
|
73
|
+
console.error(error.stack || error.message || String(error));
|
|
74
|
+
process.exit(1);
|
|
75
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import { argv, stdin, stdout } from "node:process";
|
|
5
|
+
import { decodeWire } from "./runtime/prefix-codec.mjs";
|
|
6
|
+
|
|
7
|
+
function readAll(stream) {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
const chunks = [];
|
|
10
|
+
stream.on("data", (chunk) => chunks.push(chunk));
|
|
11
|
+
stream.on("end", () => resolve(Buffer.concat(chunks.map((c) => Buffer.isBuffer(c) ? c : Buffer.from(c)))));
|
|
12
|
+
stream.on("error", reject);
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function main() {
|
|
17
|
+
const args = argv.slice(2);
|
|
18
|
+
let debug = false;
|
|
19
|
+
let fileArg = null;
|
|
20
|
+
|
|
21
|
+
for (const arg of args) {
|
|
22
|
+
if (arg === "--debug") {
|
|
23
|
+
debug = true;
|
|
24
|
+
} else if (fileArg == null) {
|
|
25
|
+
fileArg = arg;
|
|
26
|
+
} else {
|
|
27
|
+
throw new Error("Usage: k-print [--debug] [file]");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const input = fileArg ? fs.createReadStream(fileArg) : stdin;
|
|
32
|
+
const buffer = await readAll(input);
|
|
33
|
+
const { pattern, value } = decodeWire(buffer);
|
|
34
|
+
|
|
35
|
+
if (debug) {
|
|
36
|
+
stdout.write(`${JSON.stringify({ pattern, value })}\n`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
stdout.write(`${JSON.stringify(value)}\n`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
main().catch((error) => {
|
|
44
|
+
console.error(error.stack || error.message || String(error));
|
|
45
|
+
process.exit(1);
|
|
46
|
+
});
|