@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.
- 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/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.md +54 -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.md +53 -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/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.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 +18 -8
- package/parser.jison +27 -46
- package/parser.mjs +68 -100
- package/pretty.mjs +21 -40
- package/repl2.mjs +652 -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 +95 -0
- package/test.mjs +45 -70
- package/tests.sh +10 -1
- 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,53 @@
|
|
|
1
|
+
# Binary Packaging Notes
|
|
2
|
+
|
|
3
|
+
This document no longer defines the active codec semantics.
|
|
4
|
+
|
|
5
|
+
The active format is the self-hosted pattern-plus-prefix-tree stream described
|
|
6
|
+
in [`POLYMORPHIC_BINARY_FORMAT.md`](./POLYMORPHIC_BINARY_FORMAT.md):
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
encode($pattern_value : $pattern) encode(value : decoded_pattern)
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Purpose Of This File
|
|
13
|
+
|
|
14
|
+
This file records constraints for any future optimized container layered above
|
|
15
|
+
the canonical stream.
|
|
16
|
+
|
|
17
|
+
The design sequence is:
|
|
18
|
+
|
|
19
|
+
1. define the abstract pattern graph,
|
|
20
|
+
2. define prefix-free value-tree encoding relative to that graph,
|
|
21
|
+
3. encode the pattern itself as a k `$pattern` value,
|
|
22
|
+
4. optionally add higher-level indexes or compression as separate layers.
|
|
23
|
+
|
|
24
|
+
## Expected Container Shape
|
|
25
|
+
|
|
26
|
+
The canonical stream contains:
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
encoded-$pattern + value-bitstream
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
where:
|
|
33
|
+
|
|
34
|
+
- `encoded-$pattern` is the k value representation defined in `core.k`,
|
|
35
|
+
- the value bitstream is exactly the same prefix-free payload described by the
|
|
36
|
+
semantic codec.
|
|
37
|
+
|
|
38
|
+
## Non-Goals
|
|
39
|
+
|
|
40
|
+
This future binary package should not redefine the semantic codec.
|
|
41
|
+
|
|
42
|
+
In particular, it should not introduce as part of the base semantics:
|
|
43
|
+
|
|
44
|
+
- byte-oriented node tables,
|
|
45
|
+
- mandatory DAG encoding,
|
|
46
|
+
- transport-driven structural compromises.
|
|
47
|
+
|
|
48
|
+
Those are explicitly outside the target architecture of the rewrite.
|
|
49
|
+
|
|
50
|
+
## Current Format
|
|
51
|
+
|
|
52
|
+
The working concrete format is the canonical stream above. JSON property-list
|
|
53
|
+
patterns are debug notation only, not a transport container.
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# K Prefix-Free Pattern Codec
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
This document defines the new target semantics for binary codecs in `k`.
|
|
6
|
+
|
|
7
|
+
The object to be serialized is:
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
(P, v)
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
where:
|
|
14
|
+
|
|
15
|
+
- `P` is a rooted pattern graph,
|
|
16
|
+
- `v` is a value tree compatible with `P`.
|
|
17
|
+
|
|
18
|
+
This is both the transport semantics and the runtime value semantics. In the
|
|
19
|
+
current JavaScript runtime, the materialized `Value` stores the pattern as
|
|
20
|
+
`value.pattern`; the tree is still represented by `Product` and `Variant`
|
|
21
|
+
nodes.
|
|
22
|
+
|
|
23
|
+
The codec is designed around:
|
|
24
|
+
|
|
25
|
+
1. compactness,
|
|
26
|
+
2. efficient structural navigation,
|
|
27
|
+
3. a clean separation between semantic encoding and optional acceleration
|
|
28
|
+
structures.
|
|
29
|
+
|
|
30
|
+
This document defines the semantic codec and the canonical wire stream.
|
|
31
|
+
|
|
32
|
+
## Design Principles
|
|
33
|
+
|
|
34
|
+
### 1. Pattern is the structural authority
|
|
35
|
+
|
|
36
|
+
The pattern determines:
|
|
37
|
+
|
|
38
|
+
- whether a node is a product or union,
|
|
39
|
+
- whether it is open or closed,
|
|
40
|
+
- what field names or tag names exist,
|
|
41
|
+
- how recursive positions are connected.
|
|
42
|
+
|
|
43
|
+
The value payload is interpreted relative to the pattern.
|
|
44
|
+
During execution, the same pattern context is propagated with materialized
|
|
45
|
+
values, so structural operations do not have to reconstruct framing information
|
|
46
|
+
after the fact.
|
|
47
|
+
|
|
48
|
+
### 2. Values are trees in the base codec
|
|
49
|
+
|
|
50
|
+
The base codec serializes value trees, not value DAGs.
|
|
51
|
+
|
|
52
|
+
DAG compression is not part of the primitive codec. If wanted, it should happen
|
|
53
|
+
as a separate transform above the base value encoding.
|
|
54
|
+
|
|
55
|
+
### 3. Prefix-free value encoding
|
|
56
|
+
|
|
57
|
+
The value payload is a prefix-free bitstream.
|
|
58
|
+
|
|
59
|
+
Products rely on structural concatenation.
|
|
60
|
+
Unions emit a choice code, then the payload of the selected branch.
|
|
61
|
+
|
|
62
|
+
### 4. One canonical stream
|
|
63
|
+
|
|
64
|
+
The pattern graph is embedded as an ordinary k `$pattern` value. The canonical
|
|
65
|
+
stream is that encoded pattern followed by the value payload interpreted under
|
|
66
|
+
the decoded pattern.
|
|
67
|
+
|
|
68
|
+
## Pattern Graph
|
|
69
|
+
|
|
70
|
+
### Semantic node kinds
|
|
71
|
+
|
|
72
|
+
There are exactly five node kinds:
|
|
73
|
+
|
|
74
|
+
- `any`
|
|
75
|
+
- `open-product`
|
|
76
|
+
- `open-union`
|
|
77
|
+
- `closed-product`
|
|
78
|
+
- `closed-union`
|
|
79
|
+
|
|
80
|
+
Their informal meanings are:
|
|
81
|
+
|
|
82
|
+
- `any`
|
|
83
|
+
unconstrained position,
|
|
84
|
+
- `open-product`
|
|
85
|
+
explicit fields plus possibly more fields in the matched value,
|
|
86
|
+
- `open-union`
|
|
87
|
+
explicit tags plus possibly more tags in the matched value,
|
|
88
|
+
- `closed-product`
|
|
89
|
+
exactly the listed fields,
|
|
90
|
+
- `closed-union`
|
|
91
|
+
exactly the listed tags.
|
|
92
|
+
|
|
93
|
+
In the base codec, `any` is not directly value-carrying.
|
|
94
|
+
|
|
95
|
+
### Graph structure
|
|
96
|
+
|
|
97
|
+
A pattern graph node is:
|
|
98
|
+
|
|
99
|
+
```text
|
|
100
|
+
[kind, edges]
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
where `edges` is a list of:
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
[label, target_node_id]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The root node is node `0`.
|
|
110
|
+
|
|
111
|
+
### Canonical constraints
|
|
112
|
+
|
|
113
|
+
- node `0` is the root,
|
|
114
|
+
- node order is canonical graph-discovery order,
|
|
115
|
+
- edges are sorted by label,
|
|
116
|
+
- no duplicate labels occur within one node,
|
|
117
|
+
- `any` has no outgoing edges.
|
|
118
|
+
|
|
119
|
+
### Readable property-list notation
|
|
120
|
+
|
|
121
|
+
For documentation and tests, the abstract graph may be rendered as:
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"pattern": [
|
|
126
|
+
["closed-union", [["nil", 1], ["cons", 2]]],
|
|
127
|
+
["closed-product", []],
|
|
128
|
+
["closed-product", [["car", 3], ["cdr", 0]]],
|
|
129
|
+
["closed-union", [["_", 1], ["0", 3], ["1", 3]]]
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
This syntax is only a readable notation for the abstract graph.
|
|
135
|
+
|
|
136
|
+
## Pattern Construction From A Witness Tree
|
|
137
|
+
|
|
138
|
+
When no external pattern or type is supplied, the codec tools derive a
|
|
139
|
+
pattern from the value tree itself.
|
|
140
|
+
|
|
141
|
+
- `{}` derives the closed product leaf `["closed-product", []]`.
|
|
142
|
+
- A textual tree node with multiple children derives a closed product.
|
|
143
|
+
- A textual tree node with exactly one child derives an open union.
|
|
144
|
+
- If an explicit product pattern is supplied, that pattern can disambiguate the
|
|
145
|
+
same one-child textual node as a singleton product.
|
|
146
|
+
|
|
147
|
+
Example:
|
|
148
|
+
|
|
149
|
+
```text
|
|
150
|
+
{a:{b:x,c:{}}}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
derives:
|
|
154
|
+
|
|
155
|
+
```json
|
|
156
|
+
[
|
|
157
|
+
["open-union", [["a", 1]]],
|
|
158
|
+
["closed-product", [["b", 2], ["c", 3]]],
|
|
159
|
+
["open-union", [["x", 3]]],
|
|
160
|
+
["closed-product", []]
|
|
161
|
+
]
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The derived graph is canonicalized by a bottom-up closed-node collapse. Starting
|
|
165
|
+
from the closed empty product, two closed nodes are collapsible only when their
|
|
166
|
+
kind, labels, and already-collapsed children are identical. Open nodes are not
|
|
167
|
+
collapsed, and this rule is not value-DAG compression.
|
|
168
|
+
|
|
169
|
+
## Value Encoding
|
|
170
|
+
|
|
171
|
+
### General shape
|
|
172
|
+
|
|
173
|
+
The value encoding is defined recursively relative to the current pattern node.
|
|
174
|
+
|
|
175
|
+
#### Product node
|
|
176
|
+
|
|
177
|
+
For `open-product` or `closed-product`:
|
|
178
|
+
|
|
179
|
+
```text
|
|
180
|
+
encode(v_0) encode(v_1) ... encode(v_(n-1))
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
in canonical edge order.
|
|
184
|
+
|
|
185
|
+
There are no separators between children. The pattern determines where each
|
|
186
|
+
child begins and ends.
|
|
187
|
+
|
|
188
|
+
#### Union node
|
|
189
|
+
|
|
190
|
+
For `open-union` or `closed-union`:
|
|
191
|
+
|
|
192
|
+
```text
|
|
193
|
+
encode-choice(tag_ordinal, tag_count)
|
|
194
|
+
encode(selected_payload)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
#### Any node
|
|
198
|
+
|
|
199
|
+
`any` is not directly value-carrying in the base format.
|
|
200
|
+
|
|
201
|
+
If a value would need to descend into an `any` position, the pattern must first
|
|
202
|
+
be refined.
|
|
203
|
+
|
|
204
|
+
## Choice Encoding
|
|
205
|
+
|
|
206
|
+
The initial concrete choice encoding is fixed-width by cardinality:
|
|
207
|
+
|
|
208
|
+
```text
|
|
209
|
+
width(cardinality) = ceil(log2(cardinality))
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
A choice with:
|
|
213
|
+
|
|
214
|
+
- `cardinality = n`
|
|
215
|
+
- `ordinal in [0, n)`
|
|
216
|
+
|
|
217
|
+
is encoded as the binary representation of `ordinal` in `width(n)` bits.
|
|
218
|
+
|
|
219
|
+
Examples:
|
|
220
|
+
|
|
221
|
+
- `n = 1`: `0` bits,
|
|
222
|
+
- `n = 2`: `1` bit,
|
|
223
|
+
- `n = 3`: `2` bits,
|
|
224
|
+
- `n = 4`: `2` bits,
|
|
225
|
+
- `n = 5`: `3` bits.
|
|
226
|
+
|
|
227
|
+
This is the initial canonical rule for the rewrite. More aggressive coding
|
|
228
|
+
schemes may be considered later, but only after the abstract semantics are
|
|
229
|
+
stable.
|
|
230
|
+
|
|
231
|
+
## Operational Properties
|
|
232
|
+
|
|
233
|
+
### `/tag`
|
|
234
|
+
|
|
235
|
+
At a union node:
|
|
236
|
+
|
|
237
|
+
1. read the choice code,
|
|
238
|
+
2. compare it to the requested tag ordinal,
|
|
239
|
+
3. if it matches, continue with the selected payload.
|
|
240
|
+
|
|
241
|
+
This makes `/tag` naturally efficient.
|
|
242
|
+
|
|
243
|
+
### `.field`
|
|
244
|
+
|
|
245
|
+
At a product node, child values appear in canonical field order.
|
|
246
|
+
|
|
247
|
+
So `.field` is resolved by:
|
|
248
|
+
|
|
249
|
+
1. locating the field ordinal in the pattern,
|
|
250
|
+
2. decoding or skipping earlier children,
|
|
251
|
+
3. decoding the requested child subtree.
|
|
252
|
+
|
|
253
|
+
The base codec does not include field-offset indexes. Such indexes may be added
|
|
254
|
+
later as separate higher-level acceleration structures.
|
|
255
|
+
|
|
256
|
+
In the materialized evaluator, `.field` applies the analogous pattern operation:
|
|
257
|
+
the output `Value` carries the subpattern reached by the selected field.
|
|
258
|
+
Likewise, `/tag` carries the subpattern reached by the selected variant tag.
|
|
259
|
+
|
|
260
|
+
## Recursive Types
|
|
261
|
+
|
|
262
|
+
Recursive pattern graphs are first-class.
|
|
263
|
+
|
|
264
|
+
For example, a bit-list-like recursive type:
|
|
265
|
+
|
|
266
|
+
```text
|
|
267
|
+
["closed-union", [["_", 1], ["0", 3], ["1", 3]]]
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
is encoded as repeated union choices in a value tree, not as a byte-aligned node
|
|
271
|
+
table and not as a built-in primitive integer format.
|
|
272
|
+
|
|
273
|
+
This keeps the codec uniform: recursion is handled by the pattern graph itself.
|
|
274
|
+
|
|
275
|
+
## Canonical Wire Format
|
|
276
|
+
|
|
277
|
+
The transport format is:
|
|
278
|
+
|
|
279
|
+
```text
|
|
280
|
+
encode($pattern_value : $pattern) encode(value : decoded_pattern)
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
The first segment is a normal k value of type `$pattern`, encoded under the
|
|
284
|
+
fixed singleton pattern for `$pattern` defined by `core.k`. The decoded pattern
|
|
285
|
+
is then used as the structural authority for the second segment.
|
|
286
|
+
|
|
287
|
+
Decoding the stream yields `Value(pattern, tree)`. Encoding a runtime `Value`
|
|
288
|
+
uses its carried pattern by default, or an explicit caller-supplied pattern when
|
|
289
|
+
one is provided.
|
|
290
|
+
|
|
291
|
+
## Out Of Scope For The Base Codec
|
|
292
|
+
|
|
293
|
+
The following are intentionally outside the primitive codec:
|
|
294
|
+
|
|
295
|
+
- DAG compression,
|
|
296
|
+
- subtree deduplication,
|
|
297
|
+
- projection indexes,
|
|
298
|
+
- alternate transport-specific framing,
|
|
299
|
+
- alternate binary pattern serialization,
|
|
300
|
+
- exact-type-only specializations.
|
|
301
|
+
|
|
302
|
+
These may be added later, but they are not part of the base pattern-plus-tree
|
|
303
|
+
prefix codec.
|
package/codecs/README.md
ADDED
|
@@ -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!');
|