@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.
Files changed (115) hide show
  1. package/.codex +0 -0
  2. package/Code-derivation-tests/blowup.mjs +3 -3
  3. package/Code-derivation-tests/bnat.mjs +2 -2
  4. package/Code-derivation-tests/codec-witness-pattern.mjs +50 -0
  5. package/Code-derivation-tests/convergence-strategy.mjs +24 -0
  6. package/Code-derivation-tests/dot.mjs +12 -9
  7. package/Code-derivation-tests/filter-syntax.mjs +21 -0
  8. package/Code-derivation-tests/loop.mjs +8 -2
  9. package/Code-derivation-tests/nat.mjs +1 -1
  10. package/Code-derivation-tests/not-not.mjs +3 -3
  11. package/Code-derivation-tests/pattern-envelope.mjs +68 -0
  12. package/Code-derivation-tests/rlz.mjs +2 -2
  13. package/{BIG_PICTURE.md → DOCS/BIG_PICTURE.md} +103 -50
  14. package/DOCS/REPL.md +191 -0
  15. package/DOCS/a.html +398 -0
  16. package/DOCS/book/01-introduction.md +51 -0
  17. package/DOCS/book/02-syntax-and-values.md +111 -0
  18. package/DOCS/book/03-types-as-finite-automata.md +156 -0
  19. package/DOCS/book/04-partial-functions-and-composition.md +146 -0
  20. package/DOCS/book/05-typing-filters-and-normalization.md +111 -0
  21. package/DOCS/book-combined.html +3798 -0
  22. package/DOCS/book-combined.md +3745 -0
  23. package/DOCS/book-combined.pdf +0 -0
  24. package/DOCS/book-combined.tex +5682 -0
  25. package/DOCS/book.html +65 -0
  26. package/DOCS/book.md +54 -0
  27. package/DOCS/book.pdf +0 -0
  28. package/DOCS/book.tex +150 -0
  29. package/NAT.k~ +452 -0
  30. package/README.md +204 -508
  31. package/TypeGraph.mjs +43 -0
  32. package/TypePatternGraph.mjs +251 -0
  33. package/Value.mjs +192 -0
  34. package/augmentation.mjs +198 -0
  35. package/codecs/BINARY_FORMAT.html +471 -0
  36. package/codecs/BINARY_FORMAT.md +53 -0
  37. package/codecs/POLYMORPHIC_BINARY_FORMAT.html +355 -0
  38. package/codecs/POLYMORPHIC_BINARY_FORMAT.md +303 -0
  39. package/codecs/README.md +215 -0
  40. package/codecs/example-pipeline.mjs +149 -0
  41. package/codecs/ieee.mjs +140 -0
  42. package/codecs/int.mjs +104 -0
  43. package/codecs/json-codec.mjs +215 -0
  44. package/codecs/json.mjs +40 -0
  45. package/codecs/k-parse.mjs +90 -0
  46. package/codecs/k-pattern.mjs +75 -0
  47. package/codecs/k-print.mjs +46 -0
  48. package/codecs/runtime/codec.mjs +768 -0
  49. package/codecs/runtime/ieee-pattern.mjs +30 -0
  50. package/codecs/runtime/pattern-json.mjs +96 -0
  51. package/codecs/runtime/prefix-codec.mjs +425 -0
  52. package/codecs/runtime/show-value.mjs +68 -0
  53. package/codecs/runtime/typeFromValue.mjs +34 -0
  54. package/codecs/runtime/unicode-string.mjs +220 -0
  55. package/codecs/show.mjs +41 -0
  56. package/codecs/string-codec.mjs +80 -0
  57. package/codecs/unit.mjs +51 -0
  58. package/codecs/utf16.mjs +66 -0
  59. package/codecs/utf8.mjs +37 -0
  60. package/codes.mjs +146 -44
  61. package/compiler.mjs +111 -0
  62. package/convergence.mjs +197 -0
  63. package/core.k +197 -0
  64. package/export.mjs +22 -32
  65. package/hash.mjs +29 -31
  66. package/ieee.klib +0 -0
  67. package/index.mjs +41 -15
  68. package/k-vscode/.vscode/launch.json +14 -0
  69. package/k-vscode/README.md +65 -0
  70. package/k-vscode/language-configuration.json +42 -0
  71. package/k-vscode/package-lock.json +4176 -0
  72. package/k-vscode/package.json +57 -0
  73. package/k-vscode/snippets/k.json +92 -0
  74. package/k-vscode/syntaxes/k.tmLanguage.json +243 -0
  75. package/k.mjs +56 -54
  76. package/object.mjs +517 -0
  77. package/objects/README.md +38 -0
  78. package/objects/compile-lib.mjs +42 -0
  79. package/objects/compile.mjs +42 -0
  80. package/objects/decompile.mjs +32 -0
  81. package/package.json +13 -6
  82. package/parser.jison +27 -46
  83. package/parser.mjs +68 -100
  84. package/pretty.mjs +21 -40
  85. package/repl2.mjs +662 -0
  86. package/run.mjs +264 -231
  87. package/symbol-table.mjs +3 -17
  88. package/test-fingerprint.mjs +7 -7
  89. package/test-hash-fuzz.mjs +107 -0
  90. package/test-hash-normalization.mjs +134 -0
  91. package/test-k-object.mjs +74 -0
  92. package/test-repl2.mjs +106 -0
  93. package/test.mjs +45 -70
  94. package/tests.sh +10 -1
  95. package/type_registry/registry.mjs~ +105 -0
  96. package/type_registry/typeParser.jison~ +132 -0
  97. package/typing.mjs +129 -676
  98. package/unification.mjs +157 -0
  99. package/valueIO.mjs +54 -0
  100. package/valueParser.jison +143 -0
  101. package/valueParser.mjs +713 -0
  102. package/Code-derivation-tests/built-in.mjs +0 -19
  103. package/Code-derivation-tests/vector.mjs +0 -19
  104. package/Filters/bug.k +0 -3
  105. package/Filters/composing.k +0 -15
  106. package/Filters/filter.k +0 -9
  107. package/TODO.md +0 -53
  108. package/TYPING.md +0 -365
  109. package/k-repl.cast +0 -1913
  110. package/k.cast +0 -618
  111. package/my-objects.json +0 -6
  112. package/patterns.mjs +0 -543
  113. package/repl.mjs +0 -213
  114. package/test-filters.mjs +0 -45
  115. package/typing-test.mjs +0 -40
@@ -0,0 +1,215 @@
1
+ # K Codecs
2
+
3
+ This directory is being rewritten around a new codec design:
4
+
5
+ ```text
6
+ abstract pattern graph + prefix-free tree encoding
7
+ ```
8
+
9
+ The default concrete format is now the binary encoding of a `$pattern` value,
10
+ using the `$pattern` type from [`../core.k`](../core.k), immediately followed by
11
+ the binary encoding of the value under that decoded pattern.
12
+
13
+ There is no separate JSON container format.
14
+
15
+ ## Objectives
16
+
17
+ The rewrite is guided by two hard requirements:
18
+
19
+ 1. compactness close to the structural lower bound,
20
+ 2. efficient `k` projections, especially `.field` and `/tag`.
21
+
22
+ The current target architecture is the pattern graph plus prefix-free value-tree
23
+ stream described here and in
24
+ [`POLYMORPHIC_BINARY_FORMAT.md`](./POLYMORPHIC_BINARY_FORMAT.md).
25
+
26
+ ## Core Idea
27
+
28
+ The semantic object serialized by the new codec is:
29
+
30
+ ```text
31
+ (P, v)
32
+ ```
33
+
34
+ where:
35
+
36
+ - `P` is an abstract rooted pattern graph,
37
+ - `v` is a value tree compatible with `P`.
38
+
39
+ The same pair is now the in-memory runtime model as well. Decoding a stream
40
+ attaches `P` to the resulting `Value` as `value.pattern`; evaluation propagates
41
+ that pattern through projections and constructors; encoding a `Value` uses its
42
+ carried pattern unless an explicit pattern is supplied.
43
+
44
+ The base value encoding is:
45
+
46
+ - tree-based, not DAG-based,
47
+ - prefix-free,
48
+ - interpreted relative to the pattern graph,
49
+ - free of repeated field names and tag names in the value payload.
50
+
51
+ The base codec does **not** perform DAG compression. If sharing is desired, it
52
+ should happen as a higher-level transform, not inside the primitive value
53
+ format.
54
+
55
+ ## Wire Format
56
+
57
+ The default transport format is:
58
+
59
+ ```text
60
+ encode($pattern_value : $pattern) encode(value : decoded_pattern)
61
+ ```
62
+
63
+ `$pattern_value` is a normal k value whose shape is defined in `core.k`. After
64
+ that value is decoded, it becomes the pattern used to decode the remaining
65
+ value payload.
66
+
67
+ The runtime boundary is therefore:
68
+
69
+ ```text
70
+ binary pattern+value stream <-> Value(pattern, tree)
71
+ ```
72
+
73
+ `k.mjs` is only the command-line adapter for that boundary. The operational
74
+ runtime sees and preserves the pattern on the `Value` itself.
75
+
76
+ ## Pattern Graph Representation
77
+
78
+ For documentation and tests, a pattern graph may be shown as a property-list
79
+ style vector of nodes:
80
+
81
+ ```text
82
+ [kind, edges]
83
+ ```
84
+
85
+ where:
86
+
87
+ - `kind` is one of:
88
+ - `"any"`
89
+ - `"open-product"`
90
+ - `"open-union"`
91
+ - `"closed-product"`
92
+ - `"closed-union"`
93
+ - `edges` is a list of:
94
+ - `[label, target_node_id]`
95
+
96
+ Example:
97
+
98
+ ```json
99
+ [
100
+ ["closed-union", [["nil", 1], ["cons", 2]]],
101
+ ["closed-product", []],
102
+ ["closed-product", [["car", 3], ["cdr", 0]]],
103
+ ["closed-union", [["_", 1], ["0", 3], ["1", 3]]]
104
+ ]
105
+ ```
106
+
107
+ Canonical rules:
108
+
109
+ - root node is node `0`,
110
+ - node list order is canonical graph-discovery order,
111
+ - edges are sorted by label,
112
+ - edge labels are unique within a node,
113
+ - `"any"` must have no outgoing edges.
114
+
115
+ This JSON-like graph is only a readable notation. The wire representation is
116
+ the ordinary k `$pattern` value from `core.k`.
117
+
118
+ ## Witness-Derived Patterns
119
+
120
+ When `k-parse` is used without an explicit input pattern or type, the wire
121
+ pattern is derived from the parsed value tree.
122
+
123
+ - An empty textual node is a closed product: `{}`.
124
+ - A textual node with multiple children is a closed product.
125
+ - A textual node with one child is interpreted as an open union by default.
126
+ - An explicit product input pattern may force such a node to be treated as a
127
+ singleton product instead.
128
+
129
+ For example, parsing:
130
+
131
+ ```text
132
+ {a:{b:x,c:{}}}
133
+ ```
134
+
135
+ without an input pattern derives:
136
+
137
+ ```json
138
+ [
139
+ ["open-union", [["a", 1]]],
140
+ ["closed-product", [["b", 2], ["c", 3]]],
141
+ ["open-union", [["x", 3]]],
142
+ ["closed-product", []]
143
+ ]
144
+ ```
145
+
146
+ During this construction, finite closed pattern subtrees are hash-consed from
147
+ the leaves upward. The starting closed leaf is `["closed-product", []]`. Two
148
+ closed nodes collapse only when they have the same closed kind, the same labels,
149
+ and the same already-collapsed child targets. Open nodes keep their identity,
150
+ and recursive closed nodes are not collapsed by this witness-tree rule.
151
+
152
+ This is canonicalization of the pattern graph carried in the wire stream. It is
153
+ not DAG compression of the value payload.
154
+
155
+ ## Prefix-Free Value Encoding
156
+
157
+ The value payload is a bitstream interpreted relative to the pattern graph.
158
+
159
+ Base rules:
160
+
161
+ - closed or open product:
162
+ - encode child values in canonical edge order,
163
+ - closed or open union:
164
+ - encode the selected tag position,
165
+ - then encode the selected payload,
166
+ - `any`:
167
+ - not directly value-carrying in the base format.
168
+
169
+ The initial concrete union encoding rule is:
170
+
171
+ ```text
172
+ width = ceil(log2(cardinality))
173
+ emit tag ordinal in width bits
174
+ ```
175
+
176
+ This is the simplest canonical prefix-free choice encoding. It is not the final
177
+ word on compression, but it gives a regular and compact base encoding that can
178
+ later be refined without changing the abstract pattern/value model.
179
+
180
+ ## Projections
181
+
182
+ The base tree encoding is chosen so that:
183
+
184
+ - `/tag` only needs to read the union choice at the current node,
185
+ - `.field` follows canonical product order and may later be accelerated by
186
+ higher-level indexes if necessary.
187
+
188
+ In the materialized runtime, projections also project the carried pattern:
189
+ `.field` returns the subpattern at that product field, and `/tag` returns the
190
+ subpattern at that union tag. If no carried subpattern is available, later
191
+ encoding can still derive a witness pattern from the result tree.
192
+
193
+ The primitive codec stays minimal. Projection indexes, framing, or sharing
194
+ schemes are explicitly separate concerns.
195
+
196
+ ## Design Boundary
197
+
198
+ The new codec work is split into layers:
199
+
200
+ 1. abstract pattern graph semantics,
201
+ 2. prefix-free value-tree semantics relative to that graph,
202
+ 3. self-hosted `k` representation of the pattern graph,
203
+ 4. optional higher-level optimizations.
204
+
205
+ ## Files
206
+
207
+ - [`POLYMORPHIC_BINARY_FORMAT.md`](./POLYMORPHIC_BINARY_FORMAT.md):
208
+ main design document for the new pattern-plus-prefix-tree codec.
209
+ - [`BINARY_FORMAT.md`](./BINARY_FORMAT.md):
210
+ notes on future binary packaging of the same abstract semantics.
211
+
212
+ ## Status
213
+
214
+ The active command-line pipeline emits and consumes the self-hosted binary
215
+ pattern+value stream.
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Example: Demonstrating the codec pipeline
4
+ *
5
+ * Shows how to:
6
+ * 1. Define types with canonical names
7
+ * 2. Create values
8
+ * 3. Encode to binary
9
+ * 4. Pass through "compiled program" (identity)
10
+ * 5. Decode from binary
11
+ * 6. Print result
12
+ */
13
+
14
+ import { deriveClosedPattern } from './runtime/codec.mjs';
15
+ import { encodeToWire, decodeWire } from './runtime/prefix-codec.mjs';
16
+ import { patternToPropertyList } from './runtime/pattern-json.mjs';
17
+ import { Product, Variant } from '../Value.mjs';
18
+ import hash from '../hash.mjs';
19
+
20
+ console.log('=== K Codec Pipeline Example ===\n');
21
+
22
+ // ============================================================================
23
+ // Step 1: Define types (normally from compiler)
24
+ // ============================================================================
25
+
26
+ const types = {};
27
+
28
+ // Unit: {}
29
+ const unitDef = { code: 'product', product: {} };
30
+ const unitName = hash('$C0={};');
31
+ types[unitName] = unitDef;
32
+
33
+ // Bool: <{} false, {} true>
34
+ const boolDef = {
35
+ code: 'union',
36
+ union: { false: unitName, true: unitName }
37
+ };
38
+ const boolName = hash(`$C0=<${unitName}"false",${unitName}"true">;`);
39
+ types[boolName] = boolDef;
40
+
41
+ // Maybe: <{} nothing, Bool something>
42
+ const maybeDef = {
43
+ code: 'union',
44
+ union: { nothing: unitName, something: boolName }
45
+ };
46
+ const maybeName = hash(
47
+ `$C0=<${unitName}"nothing",${boolName}"something">;`
48
+ );
49
+ types[maybeName] = maybeDef;
50
+
51
+ console.log('Types defined:');
52
+ console.log(' unit:', unitName);
53
+ console.log(' bool:', boolName);
54
+ console.log(' maybe:', maybeName);
55
+ console.log();
56
+
57
+ // ============================================================================
58
+ // Step 2: Type resolver
59
+ // ============================================================================
60
+
61
+ function resolveType(typeName) {
62
+ const def = types[typeName];
63
+ if (!def) {
64
+ throw new Error(`Unknown type: ${typeName}`);
65
+ }
66
+ return def;
67
+ }
68
+
69
+ // ============================================================================
70
+ // Step 3: Create input value: Maybe Bool = something(true)
71
+ // ============================================================================
72
+
73
+ const inputValue = new Variant(
74
+ 'something',
75
+ new Variant('true', new Product({}))
76
+ );
77
+
78
+ console.log('Input value:', inputValue.toString());
79
+ console.log();
80
+
81
+ const maybePattern = patternToPropertyList(
82
+ deriveClosedPattern(maybeName, maybeDef, resolveType)
83
+ );
84
+
85
+ // ============================================================================
86
+ // Step 4: Parse (TEXT → BINARY)
87
+ // ============================================================================
88
+
89
+ console.log('--- PARSE (text → binary) ---');
90
+ const binaryInput = encodeToWire(inputValue, maybePattern);
91
+ console.log('Binary size:', binaryInput.length, 'bytes');
92
+ console.log(' Bytes:', binaryInput.toString('hex'));
93
+ console.log();
94
+
95
+ // ============================================================================
96
+ // Step 5: Compiled k-program (BINARY → BINARY)
97
+ // ============================================================================
98
+
99
+ console.log('--- COMPILED PROGRAM (binary → binary) ---');
100
+
101
+ // Simulate a compiled k-program: decode → transform → encode
102
+ const { value: programInput } = decodeWire(binaryInput);
103
+
104
+ console.log('Program sees value:', programInput.toString());
105
+
106
+ // Example transformation: NOT operation (flip bool inside Maybe)
107
+ let programOutput;
108
+ if (programInput instanceof Variant && programInput.tag === 'something') {
109
+ const innerBool = programInput.value;
110
+ if (innerBool instanceof Variant) {
111
+ const flipped = new Variant(
112
+ innerBool.tag === 'true' ? 'false' : 'true',
113
+ innerBool.value
114
+ );
115
+ programOutput = new Variant('something', flipped);
116
+ }
117
+ } else {
118
+ programOutput = programInput; // nothing → nothing
119
+ }
120
+
121
+ console.log('Program output value:', programOutput.toString());
122
+
123
+ // Encode output
124
+ const binaryOutput = encodeToWire(programOutput, maybePattern);
125
+
126
+ console.log('Binary output size:', binaryOutput.length, 'bytes');
127
+ console.log(' Bytes:', binaryOutput.toString('hex'));
128
+ console.log();
129
+
130
+ // ============================================================================
131
+ // Step 6: Print (BINARY → TEXT)
132
+ // ============================================================================
133
+
134
+ console.log('--- PRINT (binary → text) ---');
135
+ const { value: finalValue } = decodeWire(binaryOutput);
136
+
137
+ console.log('Output value:', finalValue.toString());
138
+ console.log();
139
+
140
+ // ============================================================================
141
+ // Summary
142
+ // ============================================================================
143
+
144
+ console.log('=== Pipeline Summary ===');
145
+ console.log('Input: ', inputValue.toString(), '(true inside Maybe)');
146
+ console.log('Transform: NOT operation on inner bool');
147
+ console.log('Output: ', finalValue.toString(), '(false inside Maybe)');
148
+ console.log();
149
+ console.log('Binary representations are canonical and type-safe!');
@@ -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
+ });