@fraczak/k 5.1.2 → 6.0.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 (99) hide show
  1. package/Code-derivation-tests/blowup.mjs +3 -3
  2. package/Code-derivation-tests/bnat.mjs +2 -2
  3. package/Code-derivation-tests/codec-witness-pattern.mjs +50 -0
  4. package/Code-derivation-tests/convergence-strategy.mjs +24 -0
  5. package/Code-derivation-tests/dot.mjs +12 -9
  6. package/Code-derivation-tests/filter-syntax.mjs +21 -0
  7. package/Code-derivation-tests/loop.mjs +8 -2
  8. package/Code-derivation-tests/nat.mjs +1 -1
  9. package/Code-derivation-tests/not-not.mjs +3 -3
  10. package/Code-derivation-tests/pattern-envelope.mjs +68 -0
  11. package/Code-derivation-tests/rlz.mjs +2 -2
  12. package/{BIG_PICTURE.md → DOCS/BIG_PICTURE.md} +103 -50
  13. package/DOCS/REPL.md +191 -0
  14. package/DOCS/book/01-introduction.md +51 -0
  15. package/DOCS/book/02-syntax-and-values.md +111 -0
  16. package/DOCS/book/03-types-as-finite-automata.md +156 -0
  17. package/DOCS/book/04-partial-functions-and-composition.md +146 -0
  18. package/DOCS/book/05-typing-filters-and-normalization.md +111 -0
  19. package/DOCS/book.md +54 -0
  20. package/README.md +204 -508
  21. package/TypeGraph.mjs +43 -0
  22. package/TypePatternGraph.mjs +251 -0
  23. package/Value.mjs +192 -0
  24. package/augmentation.mjs +198 -0
  25. package/codecs/BINARY_FORMAT.md +53 -0
  26. package/codecs/POLYMORPHIC_BINARY_FORMAT.md +303 -0
  27. package/codecs/README.md +215 -0
  28. package/codecs/example-pipeline.mjs +149 -0
  29. package/codecs/ieee.mjs +140 -0
  30. package/codecs/int.mjs +104 -0
  31. package/codecs/json-codec.mjs +215 -0
  32. package/codecs/json.mjs +40 -0
  33. package/codecs/k-parse.mjs +90 -0
  34. package/codecs/k-pattern.mjs +75 -0
  35. package/codecs/k-print.mjs +46 -0
  36. package/codecs/runtime/codec.mjs +768 -0
  37. package/codecs/runtime/ieee-pattern.mjs +30 -0
  38. package/codecs/runtime/pattern-json.mjs +96 -0
  39. package/codecs/runtime/prefix-codec.mjs +425 -0
  40. package/codecs/runtime/show-value.mjs +68 -0
  41. package/codecs/runtime/typeFromValue.mjs +34 -0
  42. package/codecs/runtime/unicode-string.mjs +220 -0
  43. package/codecs/show.mjs +41 -0
  44. package/codecs/string-codec.mjs +80 -0
  45. package/codecs/unit.mjs +51 -0
  46. package/codecs/utf16.mjs +66 -0
  47. package/codecs/utf8.mjs +37 -0
  48. package/codes.mjs +146 -44
  49. package/compiler.mjs +111 -0
  50. package/convergence.mjs +197 -0
  51. package/core.k +197 -0
  52. package/export.mjs +22 -32
  53. package/hash.mjs +29 -31
  54. package/index.mjs +41 -15
  55. package/k-vscode/.vscode/launch.json +14 -0
  56. package/k-vscode/README.md +65 -0
  57. package/k-vscode/language-configuration.json +42 -0
  58. package/k-vscode/package.json +57 -0
  59. package/k-vscode/snippets/k.json +92 -0
  60. package/k-vscode/syntaxes/k.tmLanguage.json +243 -0
  61. package/k.mjs +56 -54
  62. package/object.mjs +517 -0
  63. package/objects/README.md +38 -0
  64. package/objects/compile-lib.mjs +42 -0
  65. package/objects/compile.mjs +42 -0
  66. package/objects/decompile.mjs +32 -0
  67. package/package.json +18 -8
  68. package/parser.jison +27 -46
  69. package/parser.mjs +68 -100
  70. package/pretty.mjs +21 -40
  71. package/repl2.mjs +652 -0
  72. package/run.mjs +264 -231
  73. package/symbol-table.mjs +3 -17
  74. package/test-fingerprint.mjs +7 -7
  75. package/test-hash-fuzz.mjs +107 -0
  76. package/test-hash-normalization.mjs +134 -0
  77. package/test-k-object.mjs +74 -0
  78. package/test-repl2.mjs +95 -0
  79. package/test.mjs +45 -70
  80. package/tests.sh +10 -1
  81. package/typing.mjs +129 -676
  82. package/unification.mjs +157 -0
  83. package/valueIO.mjs +54 -0
  84. package/valueParser.jison +143 -0
  85. package/valueParser.mjs +713 -0
  86. package/Code-derivation-tests/built-in.mjs +0 -19
  87. package/Code-derivation-tests/vector.mjs +0 -19
  88. package/Filters/bug.k +0 -3
  89. package/Filters/composing.k +0 -15
  90. package/Filters/filter.k +0 -9
  91. package/TODO.md +0 -53
  92. package/TYPING.md +0 -365
  93. package/k-repl.cast +0 -1913
  94. package/k.cast +0 -618
  95. package/my-objects.json +0 -6
  96. package/patterns.mjs +0 -543
  97. package/repl.mjs +0 -213
  98. package/test-filters.mjs +0 -45
  99. package/typing-test.mjs +0 -40
@@ -0,0 +1,140 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { stdin, stdout, argv, exit } from "node:process";
4
+ import { Product, Variant } from "../Value.mjs";
5
+ import { decodeWire, encodeToWire } from "./runtime/prefix-codec.mjs";
6
+ import { FLOAT64_PATTERN } from "./runtime/ieee-pattern.mjs";
7
+ const UNIT = new Product({});
8
+
9
+ function bitValue(bit) {
10
+ return new Variant(bit === 0 ? "0" : "1", UNIT);
11
+ }
12
+
13
+ function bitsProduct(width, value) {
14
+ const big = BigInt(value);
15
+ const product = {};
16
+ for (let i = width - 1; i >= 0; i--) {
17
+ product[String(i)] = bitValue(Number((big >> BigInt(i)) & 1n));
18
+ }
19
+ return new Product(product);
20
+ }
21
+
22
+ function encodeNumberToValue(number) {
23
+ const buf = Buffer.alloc(8);
24
+ buf.writeDoubleBE(number, 0);
25
+ const bits = buf.readBigUInt64BE(0);
26
+ const sign = Number((bits >> 63n) & 1n);
27
+ const exponent = Number((bits >> 52n) & 0x7ffn);
28
+ const fraction = bits & ((1n << 52n) - 1n);
29
+
30
+ return new Product({
31
+ sign: new Variant(sign === 0 ? "+" : "-", UNIT),
32
+ exponent: bitsProduct(11, exponent),
33
+ fraction: bitsProduct(52, fraction)
34
+ });
35
+ }
36
+
37
+ function requireProduct(value, where) {
38
+ if (!(value instanceof Product)) {
39
+ throw new Error(`${where}: expected Product`);
40
+ }
41
+ return value.product;
42
+ }
43
+
44
+ function requireVariant(value, where) {
45
+ if (!(value instanceof Variant)) {
46
+ throw new Error(`${where}: expected Variant`);
47
+ }
48
+ return value;
49
+ }
50
+
51
+ function parseBitsProduct(value, maxBit, where) {
52
+ const product = requireProduct(value, where);
53
+ let n = 0n;
54
+ for (let i = maxBit; i >= 0; i--) {
55
+ const entry = requireVariant(product[String(i)], `${where}.bit${i}`);
56
+ if (entry.tag !== "0" && entry.tag !== "1") {
57
+ throw new Error(`${where}.bit${i}: expected tag 0 or 1`);
58
+ }
59
+ n = (n << 1n) | BigInt(entry.tag === "1" ? 1 : 0);
60
+ }
61
+ return n;
62
+ }
63
+
64
+ function decodeValueToNumber(value) {
65
+ const product = requireProduct(value, "float64");
66
+ const sign = requireVariant(product.sign, "float64.sign");
67
+ if (sign.tag !== "+" && sign.tag !== "-") {
68
+ throw new Error(`float64.sign: expected + or -, got ${sign.tag}`);
69
+ }
70
+ const exponent = parseBitsProduct(product.exponent, 10, "float64.exponent");
71
+ const fraction = parseBitsProduct(product.fraction, 51, "float64.fraction");
72
+
73
+ const bits =
74
+ (BigInt(sign.tag === "-" ? 1 : 0) << 63n) |
75
+ (exponent << 52n) |
76
+ fraction;
77
+
78
+ const buf = Buffer.alloc(8);
79
+ buf.writeBigUInt64BE(bits, 0);
80
+ return buf.readDoubleBE(0);
81
+ }
82
+
83
+ function parseFloatText(text) {
84
+ const trimmed = text.trim();
85
+ if (trimmed === "") {
86
+ throw new Error("Expected a floating-point literal");
87
+ }
88
+
89
+ if (/^[+-]?nan$/i.test(trimmed)) return NaN;
90
+ if (/^[+]?inf(inity)?$/i.test(trimmed)) return Infinity;
91
+ if (/^-inf(inity)?$/i.test(trimmed)) return -Infinity;
92
+
93
+ const value = Number(trimmed);
94
+ if (Number.isNaN(value)) {
95
+ throw new Error(`Invalid floating-point literal: ${JSON.stringify(trimmed)}`);
96
+ }
97
+ return value;
98
+ }
99
+
100
+ function printFloatText(number) {
101
+ if (Number.isNaN(number)) return "NaN";
102
+ if (number === Infinity) return "Infinity";
103
+ if (number === -Infinity) return "-Infinity";
104
+ if (Object.is(number, -0)) return "-0";
105
+ return String(number);
106
+ }
107
+
108
+ function readAll(stream) {
109
+ return new Promise((resolve, reject) => {
110
+ const chunks = [];
111
+ stream.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
112
+ stream.on("end", () => resolve(Buffer.concat(chunks)));
113
+ stream.on("error", reject);
114
+ });
115
+ }
116
+
117
+ async function main() {
118
+ const args = argv.slice(2);
119
+ if (args.length !== 1 || (args[0] !== "--parse" && args[0] !== "--print")) {
120
+ console.error("Usage: ieee.mjs --parse | --print");
121
+ console.error(" --parse read a float literal from stdin, write binary pattern+value stream");
122
+ console.error(" --print read binary pattern+value stream from stdin, write a float literal");
123
+ exit(1);
124
+ }
125
+
126
+ const buf = await readAll(stdin);
127
+
128
+ if (args[0] === "--parse") {
129
+ const value = encodeNumberToValue(parseFloatText(buf.toString("utf8")));
130
+ stdout.write(encodeToWire(value, FLOAT64_PATTERN));
131
+ } else {
132
+ const { value } = decodeWire(buf);
133
+ stdout.write(`${printFloatText(decodeValueToNumber(value))}\n`);
134
+ }
135
+ }
136
+
137
+ main().catch((error) => {
138
+ console.error(error.message || String(error));
139
+ exit(1);
140
+ });
package/codecs/int.mjs ADDED
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * int: parse/print integers in the k 'int' binary pattern+value stream.
5
+ *
6
+ * $ bits = < {} _, bits 0, bits 1 >;
7
+ * $ int = < bits '+', bits '-' >;
8
+ *
9
+ * Bits are stored MSB-outermost (remove_leading_zeros strips outermost 0s).
10
+ *
11
+ * Usage:
12
+ * echo "-21" | int.mjs --parse # decimal → binary pattern+value stream
13
+ * <wire> | int.mjs --print # binary pattern+value stream → decimal
14
+ */
15
+
16
+ import { stdin, stdout, argv, exit } from "node:process";
17
+ import { Product, Variant } from "../Value.mjs";
18
+ import { decodeWire, encodeToWire } from "./runtime/prefix-codec.mjs";
19
+
20
+ // Closed pattern for $ int = < bits '+', bits '-' >
21
+ // with $ bits = < {} _, bits 0, bits 1 >
22
+ const INT_PATTERN = [
23
+ ["closed-union", [["+", 1], ["-", 1]]],
24
+ ["closed-union", [["0", 1], ["1", 1], ["_", 2]]],
25
+ ["closed-product", []]
26
+ ];
27
+
28
+ function readAll(stream) {
29
+ return new Promise((resolve, reject) => {
30
+ const chunks = [];
31
+ stream.on("data", c => chunks.push(Buffer.isBuffer(c) ? c : Buffer.from(c)));
32
+ stream.on("end", () => resolve(Buffer.concat(chunks)));
33
+ stream.on("error", reject);
34
+ });
35
+ }
36
+
37
+ // Build bits Value (MSB outermost) from a non-negative BigInt.
38
+ function buildBits(n) {
39
+ const bitChars = n === 0n ? ["0"] : n.toString(2).split("");
40
+ let v = new Variant("_", new Product({}));
41
+ for (let i = bitChars.length - 1; i >= 0; i--) {
42
+ v = new Variant(bitChars[i], v);
43
+ }
44
+ return v;
45
+ }
46
+
47
+ // Parse a decimal integer string ([-+]?[ ]*[1-9][0-9]*|0) into a k int Value.
48
+ function parseIntStr(str) {
49
+ str = str.trim();
50
+ let sign = "+";
51
+ if (str[0] === "-") { sign = "-"; str = str.slice(1).replace(/\s+/g, ""); }
52
+ else if (str[0] === "+") { str = str.slice(1).replace(/\s+/g, ""); }
53
+ if (!/^(0|[1-9][0-9]*)$/.test(str)) {
54
+ throw new Error(`Invalid integer syntax: ${JSON.stringify(str)}`);
55
+ }
56
+ const n = BigInt(str);
57
+ if (n === 0n) sign = "+"; // zero is always '+'
58
+ return new Variant(sign, buildBits(n));
59
+ }
60
+
61
+ // Walk a decoded int Value (Variant sign → bits) and return a decimal string.
62
+ function printIntValue(value) {
63
+ if (!(value instanceof Variant) || (value.tag !== "+" && value.tag !== "-")) {
64
+ throw new Error("Not a valid k int value");
65
+ }
66
+ const sign = value.tag;
67
+ let bits = "";
68
+ let node = value.value;
69
+ while (node instanceof Variant && node.tag !== "_") {
70
+ bits += node.tag;
71
+ node = node.value;
72
+ }
73
+ // bits is MSB-first binary string (may be empty for zero represented as "0")
74
+ const n = bits === "" ? 0n : BigInt("0b" + bits);
75
+ const digits = n.toString(10);
76
+ if (n === 0n) return "0";
77
+ return (sign === "-" ? "-" : "") + digits;
78
+ }
79
+
80
+ async function main() {
81
+ const args = argv.slice(2);
82
+ if (args.length !== 1 || (args[0] !== "--parse" && args[0] !== "--print")) {
83
+ console.error("Usage: int.mjs --parse | --print");
84
+ console.error(" --parse read a decimal integer from stdin, write binary pattern+value stream");
85
+ console.error(" --print read binary pattern+value stream from stdin, write decimal integer");
86
+ exit(1);
87
+ }
88
+
89
+ const buf = await readAll(stdin);
90
+
91
+ if (args[0] === "--parse") {
92
+ const text = buf.toString("utf8").trim();
93
+ const value = parseIntStr(text);
94
+ stdout.write(encodeToWire(value, INT_PATTERN));
95
+ } else {
96
+ const { value } = decodeWire(buf);
97
+ stdout.write(printIntValue(value) + "\n");
98
+ }
99
+ }
100
+
101
+ main().catch(err => {
102
+ console.error(err.message || String(err));
103
+ exit(1);
104
+ });
@@ -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 };
@@ -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
+ });