@fraczak/k 6.10.6 → 7.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 (83) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/CLAUDE.md +1 -1
  3. package/DOCS/BIG_PICTURE.md +156 -172
  4. package/DOCS/BINARY_CODEC_STATUS_AND_TODO.md +3 -3
  5. package/DOCS/CODEC_ARCHITECTURE.md +2 -2
  6. package/DOCS/DICTIONARY.md +243 -250
  7. package/DOCS/DIVERGENCE_DETECTION.md +0 -1
  8. package/DOCS/FILE_FORMATS.md +5 -5
  9. package/DOCS/KIR_SPECIALIZATION_DESIGN.md +1 -1
  10. package/DOCS/OBJECT_FILE_AND_PATTERN.md +12 -12
  11. package/DOCS/PATTERNS.md +17 -17
  12. package/DOCS/PATTERNS_AND_TYPED_VALUES.md +1 -1
  13. package/DOCS/REPL.md +9 -19
  14. package/DOCS/TYPE_DERIVATION.md +2 -8
  15. package/DOCS/WEB_REPL_REQUIREMENTS.md +8 -8
  16. package/DOCS/book/01-introduction.md +8 -11
  17. package/DOCS/book/02-syntax-and-values.md +19 -20
  18. package/DOCS/book/03-types-as-finite-automata.md +42 -43
  19. package/DOCS/book/04-partial-functions-and-composition.md +2 -3
  20. package/DOCS/book/05-typing-filters-and-normalization.md +44 -46
  21. package/DOCS/book/06-values-in-memory.md +10 -10
  22. package/DOCS/book/08-operational-semantics-and-execution.md +21 -26
  23. package/DOCS/book/09-compiler-architecture.md +11 -11
  24. package/DOCS/book/10-from-ast-to-intermediate-representation.md +6 -7
  25. package/DOCS/book/14-canonical-serialization.md +2 -2
  26. package/DOCS/book/appendix-b-incorporating-external-predefined-types-and-functions.md +17 -17
  27. package/DOCS/book.md +5 -5
  28. package/Examples/arithmetics.k +49 -153
  29. package/Examples/bnat.k +13 -13
  30. package/Examples/byte.k +2 -50
  31. package/Examples/ieee.k +408 -423
  32. package/Examples/karatsuba-mult.k +30 -34
  33. package/Examples/nat.k +5 -6
  34. package/README.md +54 -49
  35. package/TODO.md +13 -18
  36. package/backend-api.mjs +9 -1
  37. package/backends/llvm/scripts/run-tests.mjs +5 -0
  38. package/backends/llvm/src/kvm2llvm.mjs +2 -1
  39. package/backends/llvm/src/llvm.mjs +18 -25
  40. package/backends/llvm/tests/integration.sh +2 -2
  41. package/backends/llvm/tests/test-llvm.mjs +3 -3
  42. package/backends/llvm/tests/test-open-product-misalignment.mjs +140 -0
  43. package/backends/wasm/demo_ieee.mjs +2 -3
  44. package/backends/wasm/runtime.wat +157 -5
  45. package/backends/wasm/src/kvm2wasm.mjs +57 -34
  46. package/backends/wasm/src/wasm.mjs +38 -17
  47. package/backends/wasm/tests/perf-support.mjs +4 -4
  48. package/backends/wasm/tests/test-wasm.mjs +13 -14
  49. package/browser/vfs-data.mjs +12 -12
  50. package/codecs/BINARY_FORMAT.md +4 -4
  51. package/codecs/POLYMORPHIC_BINARY_FORMAT.md +4 -4
  52. package/codecs/README.md +6 -6
  53. package/codecs/ieee.mjs +15 -11
  54. package/codecs/int.mjs +9 -5
  55. package/codecs/string-codec.mjs +46 -47
  56. package/core.k +123 -95
  57. package/kir.mjs +213 -17
  58. package/object.mjs +0 -7
  59. package/package.json +5 -2
  60. package/parser.jison +2 -41
  61. package/parser.mjs +55 -95
  62. package/pretty.mjs +11 -4
  63. package/repl.mjs +8 -63
  64. package/scripts/build-repl-html.mjs +8 -38
  65. package/tests/code-derivation/blowup.mjs +2 -4
  66. package/tests/code-derivation/bnat.mjs +2 -3
  67. package/tests/code-derivation/dot.mjs +5 -11
  68. package/tests/code-derivation/nat.mjs +2 -2
  69. package/tests/code-derivation/not-not.mjs +6 -6
  70. package/tests/code-derivation/pattern-envelope.mjs +4 -6
  71. package/tests/code-derivation/product.mjs +3 -6
  72. package/tests/code-derivation/rlz.mjs +4 -5
  73. package/tests/test-codecs.mjs +1 -1
  74. package/tests/test-fingerprint.mjs +36 -41
  75. package/tests/test-hash-normalization.mjs +4 -6
  76. package/tests/test-ieee-arithmetic.mjs +6 -7
  77. package/tests/test-k-object.mjs +11 -15
  78. package/tests/test-kir.mjs +0 -1
  79. package/tests/test-kvm-polymorphic.mjs +1 -2
  80. package/tests/test-kvm.mjs +8 -11
  81. package/tests/test-repl-html.mjs +20 -2
  82. package/tests/test-repl.mjs +48 -53
  83. package/tests/test.mjs +2 -3
@@ -2,23 +2,22 @@
2
2
  -- Self-contained and minimal implementation
3
3
  -- for arbitrary-precision integers
4
4
 
5
- $ yes_no = < {} yes, {} no >;
6
- yes = {} | yes $yes_no;
7
- no = {} | no $yes_no;
5
+ yes = {} | yes;
6
+ no = {} | no;
8
7
 
9
- $ bits = < {} _, bits 0, bits 1 >;
8
+ bits = ?< {} _, bits 0, bits 1 > = bits;
10
9
  0b = {} | _;
11
10
  0 = 0b |0;
12
11
  1 = 0b |1;
13
12
 
14
- $ unat = < {} _, unat 1 >;
15
- 0u = {} | _ $unat;
13
+ unat = ?< {} _, unat 1 > = unat;
14
+ 0u = {} | _;
16
15
 
17
- empty = $bits < /_ yes, no >;
16
+ empty = < /_ yes, no >;
18
17
  empty? = {empty /yes if, () then} .then;
19
18
 
20
19
  inv = {()x, 0b r} _inv;
21
- _inv = ${bits x, bits r}
20
+ _inv = ?{ <X 0, X 1, {} _>=X x, ... }
22
21
  <
23
22
  {.x empty? if, .r then} .then,
24
23
  <
@@ -27,8 +26,8 @@ _inv = ${bits x, bits r}
27
26
  > _inv
28
27
  >;
29
28
 
30
- concat = ${bits x, bits y} {.x inv x, .y y} concat_;
31
- concat_ = ${bits x, bits y}
29
+ concat = {.x inv x, .y y} concat_;
30
+ concat_ = ?{ <X 0, X 1, {} _>=X x, ... }
32
31
  <
33
32
  {.x empty? if, .y then} .then,
34
33
  <
@@ -40,21 +39,18 @@ concat_ = ${bits x, bits y}
40
39
  remove_leading_zeros = < /0 remove_leading_zeros, () >;
41
40
  nat = remove_leading_zeros <empty? 0, ()>;
42
41
 
43
- $ int = < bits '+', bits '-' >;
44
- int = nat | '+' $int;
45
- abs = $int </'+', /'-'>;
42
+ int = nat | '+';
43
+ abs = </'+', /'-'>;
46
44
 
47
- $ sign = < {} '+', {} '-' >;
48
- sign_plus = {} | '+' $sign;
49
- sign_minus = {} | '-' $sign;
45
+ sign_plus = {} | '+';
46
+ sign_minus = {} | '-';
50
47
  swap_sign = < /'+' | '-', /'-' | '+' >;
51
48
 
52
- $ carry = < {} 0, {} 1 >;
53
- c0 = {} | 0 $carry;
54
- c1 = {} | 1 $carry;
49
+ c0 = {} | 0;
50
+ c1 = {} | 1;
55
51
 
56
52
  _plus = {.x x, .y y, .c c, 0b r} _plus_;
57
- _plus_ = ${bits x, bits y, carry c, bits r}
53
+ _plus_ = ?{ <X 0, X 1, {} _>=X x, ... }
58
54
  <
59
55
  {.x empty? if, .y empty? and, .c/0 c, .r inv then} .then,
60
56
  {.x empty? if, .y empty? and, {.r x, 1 r} _inv then} .then,
@@ -74,7 +70,7 @@ _plus_ = ${bits x, bits y, carry c, bits r}
74
70
  >;
75
71
 
76
72
  _minus = {.x x, .y y, .c c, 0b r} _minus_;
77
- _minus_ = ${bits x, bits y, carry c, bits r}
73
+ _minus_ = ?{ <X 0, X 1, {} _>=X x, ... }
78
74
  <
79
75
  {.y empty? if, .c/0 and, {.r x, .x r} _inv then} .then,
80
76
  <
@@ -91,10 +87,10 @@ _minus_ = ${bits x, bits y, carry c, bits r}
91
87
  > _minus_
92
88
  >;
93
89
 
94
- plus_bits = ${bits x, bits y} {.x inv x, .y inv y, c0 c} _plus inv nat;
95
- minus_bits = ${bits x, bits y} {.x inv x, .y inv y, c0 c} _minus inv nat;
90
+ plus_bits = {.x inv x, .y inv y, c0 c} _plus inv nat;
91
+ minus_bits = {.x inv x, .y inv y, c0 c} _minus inv nat;
96
92
 
97
- _times = ${bits result, bits _x, bits y}
93
+ _times = ?{ <Y 0, Y 1, {} _>=Y y, ... }
98
94
  <
99
95
  {.y empty? if, .result then} .then,
100
96
  <
@@ -102,21 +98,21 @@ _times = ${bits result, bits _x, bits y}
102
98
  {{._x x, .result |0 y, c0 c} _plus result, ._x _x, .y /1 y}
103
99
  > _times
104
100
  >;
105
- times_bits = ${bits x, bits y} {0 result, .x inv _x, .y y} _times inv nat;
101
+ times_bits = {0 result, .x inv _x, .y y} _times inv nat;
106
102
 
107
- unat_to_zeros = $unat < /_ 0b, /1 unat_to_zeros |0 > $bits;
108
- unat_to_double_zeros = $unat
109
- < /_ 0b, /1 unat_to_double_zeros |0 |0 > $bits;
103
+ unat_to_zeros = ?< {} _, X 1 >=X < /_ 0b, /1 unat_to_zeros |0 > ?< {} _, Z 0, Z 1 >=Z;
104
+ unat_to_double_zeros = ?< {} _, X 1 >=X
105
+ < /_ 0b, /1 unat_to_double_zeros |0 |0 > ?< {} _, Z 0, Z 1 >=Z;
110
106
 
111
107
  _peel2 = < </0,/1> </0,/1>, </0,/1>, () >;
112
- _half_unat = ${bits x, bits y, unat m}
108
+ _half_unat = ?{ <X 0, X 1, {} _>=X x, ... }
113
109
  <
114
110
  {.x empty? if, .y empty? and, .m then} .then,
115
111
  {.x _peel2 x, .y _peel2 y, .m |1 m} _half_unat
116
112
  >;
117
113
  half_unat = {.x x, .y y, 0u m} _half_unat;
118
114
 
119
- _split_rev_u = ${bits x_rev, unat m, bits low}
115
+ _split_rev_u = ?{ <X 0, X 1, {} _>=X x_rev, <M 1, {} _>=M m, ... }
120
116
  <
121
117
  {.m /_ if, {.low nat low, .x_rev inv nat high} then} .then,
122
118
  {.x_rev empty? if, {.low nat low, 0 high} then} .then,
@@ -147,19 +143,19 @@ at_least_256_u? = <
147
143
  yes, no
148
144
  >;
149
145
 
150
- shift_bits_u = ${bits val, unat m}
146
+ shift_bits_u =
151
147
  <
152
148
  {.val empty? if, 0b then} .then,
153
149
  {.val x, .m unat_to_zeros y} concat
154
150
  >;
155
151
 
156
- shift2_bits_u = ${bits val, unat m}
152
+ shift2_bits_u =
157
153
  <
158
154
  {.val empty? if, 0b then} .then,
159
155
  {.val x, .m unat_to_double_zeros y} concat
160
156
  >;
161
157
 
162
- _karatsuba = ${bits x, bits y}
158
+ _karatsuba = ?{ <X 0, X 1, {} _>=X x, <Y 0, Y 1, {} _>=Y y }
163
159
  <
164
160
  -- Base case: if m < 256 (< 512 bits), fall back to times_bits
165
161
  {{.x x, .y y} half_unat m, .x x, .y y}
@@ -198,7 +194,7 @@ _karatsuba = ${bits x, bits y}
198
194
  >
199
195
  >;
200
196
 
201
- karatsuba = ${int x, int y}
197
+ karatsuba =
202
198
  {
203
199
  <
204
200
  {.x/'+' if, .y /'+' and} sign_plus,
package/Examples/nat.k CHANGED
@@ -1,10 +1,9 @@
1
- $ nat = < {} 0, nat +1 >;
2
1
  0 = {} | 0 ;
3
- 0? = $ nat { / 0 if, () then} .then;
4
- succ = | +1 $ nat ;
5
- pred = $nat / +1 ;
6
- add = ?{ $nat x, ... } = X <{.x pred x, .y succ y} ?X add, .y> ;
7
- mult = <
2
+ 0? = { / 0 if, () then} .then;
3
+ succ = | +1 ;
4
+ pred = / +1 ;
5
+ add = ?{ < {} 0, N +1 > = N x, ... } = X <{.x pred x, .y succ y} ?X add, .y> ;
6
+ mult = ?{ < {} 0, M +1 > = M x, ... } <
8
7
  {{.x pred x, .y y} mult x, .y y} add,
9
8
  0
10
9
  > ;
package/README.md CHANGED
@@ -1,15 +1,15 @@
1
1
  # k
2
2
 
3
- **k is a small language for typed data transformations.**
3
+ **k is a small language for content-addressable schemas and data transformations.**
4
4
 
5
- It describes data as algebraic shapes, programs as first-order partial
6
- functions, and runtime values as a binary `pattern + value` stream
7
- that can be parsed, transformed, printed, compiled, and inspected.
5
+ It describes data as algebraic schemas, programs as first-order partial
6
+ relations, and runtime values as a self-describing binary `schema + payload`
7
+ stream that can be parsed, transformed, printed, compiled, and inspected.
8
8
 
9
- Data descriptions and transformations share one syntax, so a k file can
10
- define both the shapes of values and the relations that move between them.
9
+ Schema definitions and transformations share one syntax, so a k file can
10
+ define both data schemas and the relations that transform between them.
11
11
 
12
- k is experimental, but it already has a working parser, type-derivation
12
+ k is experimental, but it already has a working parser, contract-derivation
13
13
  engine, REPL, binary codec pipeline, object/library format, Node.js API,
14
14
  and test suite.
15
15
 
@@ -17,23 +17,23 @@ and test suite.
17
17
 
18
18
  Many systems need to answer the same questions:
19
19
 
20
- - What shape does this data have?
21
- - Which transformations are valid for that shape?
22
- - What does a program accept, produce, or reject?
23
- - Can this transformation be serialized, tested, reused, or inspected?
20
+ - What schema does this data have?
21
+ - Which transformations are valid for that schema?
22
+ - What does a program accept, produce, or preserve?
23
+ - Can this transformation be serialized, tested, reused, or verified?
24
24
 
25
- k explores a compact answer: define algebraic data shapes, compose
26
- partial transformations over them, derive input/output patterns
27
- automatically, and move values across process boundaries with a canonical
28
- binary representation.
25
+ k explores a compact answer: define algebraic schemas, compose
26
+ partial relations over them, derive input/output contracts
27
+ automatically, and move values across process boundaries with a canonical,
28
+ content-addressable binary representation.
29
29
 
30
30
  That makes k interesting as a foundation for:
31
31
 
32
- - schema definitions and schema-to-schema transformations
32
+ - content-addressable schema registries and schema-to-schema pipelines
33
33
  - binary codecs and canonical serialization
34
34
  - protocol, hardware, or test-vector transformation pipelines
35
- - teaching algebraic data types and compositional programming
36
- - research into partial functions, finite tree automata, and typed IRs
35
+ - teaching algebraic data types and compositional relational programming
36
+ - research into partial relations, finite tree automata, and typed IRs
37
37
 
38
38
  ## A Small Example
39
39
 
@@ -41,11 +41,10 @@ k can define recursive data and transformations in the same file. Peano
41
41
  natural numbers are either `0` or one more than another natural number:
42
42
 
43
43
  ```k
44
- $ nat = < {} 0, nat +1 >;
45
- 0 = {} | 0 $ nat ;
46
- inc = | +1 $ nat ;
47
- dec = $ nat / +1 ; # undefined for '0'
48
- add = $ { nat x, nat y } <
44
+ 0 = {} | 0;
45
+ inc = | +1;
46
+ dec = / +1; # undefined for '0'
47
+ add = ?{ < {} 0, N +1 > = N x, ... } <
49
48
  { . x dec x, . y inc y } add, # defined if 'x > 0'
50
49
  . y # else, return 'y'
51
50
  >;
@@ -53,7 +52,8 @@ add = $ { nat x, nat y } <
53
52
 
54
53
  `add` takes a product `{ x, y }`. If `x` has a `+1`, it moves that
55
54
  successor from `x` to `y` and recurses. When that no longer applies, it
56
- returns `y`.
55
+ returns `y`. The inductive filter `?{ < {} 0, N +1 > = N x, ... }`
56
+ explicitly witnesses that recursive calls shrink `x`.
57
57
 
58
58
  In the REPL:
59
59
 
@@ -118,12 +118,13 @@ Every installed command supports `-h` and `--help`.
118
118
 
119
119
  **Algebraic data shapes**
120
120
 
121
- Types, called *codes*, are built from products and tagged unions:
121
+ All data structures in k are built from products and tagged unions (variants).
122
+ Relations and pattern filters describe their domains:
122
123
 
123
124
  ```k
124
- $ bit = < {} 0, {} 1 >;
125
- $ byte = { bit 0, bit 1, bit 2, bit 3, bit 4, bit 5, bit 6, bit 7 };
126
- $ bits = < {} _, bits 0, bits 1 >;
125
+ bit = ?< {} 0, {} 1 >;
126
+ byte = ?{ Bit 0, Bit 1, Bit 2, Bit 3, Bit 4, Bit 5, Bit 6, Bit 7 };
127
+ bits = ?< {} _, bits 0, bits 1 > = bits;
127
128
  ```
128
129
 
129
130
  There are no built-in primitive values. The empty product `{}` is the
@@ -137,34 +138,38 @@ Core expressions are deliberately small:
137
138
  | --- | --- |
138
139
  | `.field` | project a product field |
139
140
  | `/tag` | project a tagged-union branch |
140
- | `\|tag` | introduce a tagged-union branch |
141
+ | `\|tag` | introduce a variant (tagged union) |
141
142
  | `(f g)` | compose transformations |
142
143
  | `<f, g>` | try `f`, then `g` if `f` is undefined |
143
144
  | `{f a, g b}` | build a product from parallel transformations |
145
+ | `?filter` | schema filter / inductive termination witness |
144
146
  | `()` | identity |
145
147
  | `<>` | always undefined |
146
148
  | `{}` | constant empty product |
147
149
 
148
- **Derived input/output patterns**
150
+ **Derived relational contracts**
149
151
 
150
- k derives structural constraints for expressions. Those patterns become
151
- useful for diagnostics, REPL output, binary encoding, and object
152
- metadata.
152
+ k derives structural contracts for relations. A contract is a connected
153
+ $(input, output)$ schema graph that specifies accepted input schemas,
154
+ guaranteed output schemas, and preserved data structures ($=X$). Those
155
+ contracts guide diagnostics, REPL output, binary serialization, and
156
+ optimizations.
153
157
 
154
- **Binary-friendly runtime values**
158
+ **Self-describing binary streams**
155
159
 
156
160
  The command-line pipeline uses a self-describing binary stream:
157
161
 
158
162
  ```text
159
- encoded pattern, followed by value encoded under that pattern
163
+ encoded schema, followed by payload encoded under that schema
160
164
  ```
161
165
 
162
166
  The boundary tools are:
163
167
 
164
168
  ```bash
165
- k-parse # textual k value -> binary pattern+value stream
169
+ k-parse # textual k value -> binary schema+payload stream
166
170
  k # apply a k expression or .k/.ko program to the stream
167
- k-print # binary pattern+value stream -> textual value
171
+ k-print # binary schema+payload stream -> textual value
172
+ k-show # inspect decoded schema and payload value
168
173
  ```
169
174
 
170
175
  **Inspectable objects and libraries**
@@ -172,21 +177,21 @@ k-print # binary pattern+value stream -> textual value
172
177
  `k` programs can be authored, compiled, and linked across four main
173
178
  file formats:
174
179
 
175
- - `.k`: human-readable source code defining algebraic types and relations.
176
- - `.klib`: ahead-of-time (AOT) type-checked library objects (`main: null`)
177
- storing canonical relation definitions, type codes, and local aliases.
178
- - `.ko`: ahead-of-time (AOT) type-checked executable containers (`KOBJ\n`
179
- magic header) with entrypoint `main: "__main__"`, skipping parsing and
180
- type derivation at runtime.
180
+ - `.k`: human-readable source code defining algebraic schemas and relations.
181
+ - `.klib`: ahead-of-time (AOT) library objects (`main: null`) storing
182
+ canonical relation definitions, schemas, and local aliases.
183
+ - `.ko`: ahead-of-time (AOT) executable containers (`KOBJ\n` magic header)
184
+ with entrypoint `main: "__main__"`, skipping parsing and contract
185
+ derivation at runtime.
181
186
  - `.kvm`: polymorphic register-IR template artifacts (`layer: "KVM-P"`)
182
- carrying principal pattern graphs for instant runtime specialization
187
+ carrying principal schema contracts for instant runtime specialization
183
188
  (`specializeKVM`).
184
189
 
185
- In `k`, all relations and types are identified canonically by immutable
190
+ In `k`, all relations and derived schemas are identified canonically by immutable
186
191
  content-addressed hashes (`@hash`). There is no global symbol namespace;
187
192
  friendly names (such as `plus`, `int`, or `5`) are local aliases stored
188
193
  in metadata. Similarly, there are no primitive numbers: numerical
189
- identifiers like `5` or `10` are nullary relations mapping `${} -> $bits`.
194
+ identifiers like `5` or `10` are nullary relations mapping `{}` to `bits`.
190
195
 
191
196
  For a detailed guide to all four formats, commands, and workflows, see
192
197
  [DOCS/FILE_FORMATS.md](DOCS/FILE_FORMATS.md).
@@ -204,9 +209,9 @@ For a detailed guide to all four formats, commands, and workflows, see
204
209
 
205
210
  | Command | Purpose |
206
211
  | --- | --- |
207
- | `k-parse` | Convert textual k values to binary pattern+value streams |
208
- | `k-print` | Convert binary pattern+value streams back to textual values |
209
- | `k-show` | Pass a stream through while showing the decoded value/filter |
212
+ | `k-parse` | Convert textual k values to binary schema+payload streams |
213
+ | `k-print` | Convert binary schema+payload streams back to textual values |
214
+ | `k-show` | Pass a stream through while showing the decoded payload and schema |
210
215
 
211
216
  **Built-in codecs**
212
217
 
package/TODO.md CHANGED
@@ -17,37 +17,32 @@ This document details the issues, conceptual improvements, and completed enhance
17
17
  ## 2. Help Modal (`? Help` / `:help`) Overhaul
18
18
 
19
19
  ### Language Overview & Grammar Categorization
20
- - [x] **Language Overview**: Short, positive, accessible description: `k` is a concise language of types and relations (functions) over tree-like (JSON-like) documents.
21
- - [x] **Content-Addressed Identity**: Functions and types are identified by their canonical content hash (`@...`) derived directly from their structure; local names are just temporary aliases used for recursion and readability.
22
- - [x] **Three Clean Grammar Categories**:
20
+ - [x] **Language Overview**: Short, positive, accessible description: `k` is a concise language of relations (functions) over tree-like (JSON-like) documents.
21
+ - [x] **Content-Addressed Identity**: Relations are identified by their canonical content hash (`@...`) derived directly from their structure; local names are just temporary aliases used for recursion and readability.
22
+ - [x] **Grammar Categories**:
23
23
  1. **Definitions (Local Aliases)**:
24
24
  - `name = relExpr;` &mdash; Relation alias (e.g. `swap = { . y x, . x y };`).
25
- - `$ name = typeExpr;` &mdash; Type alias (e.g. `$ bool = < {} true, {} false >;`).
26
- 2. **Type Expressions (`typeExpr`)**: Schemas describing tree-like documents:
27
- - `{ Type_1 label_1, ..., Type_k label_k }` &mdash; Product type of arity $k$ (labeled records, e.g. `{float64 x, string n}`; special case: `{}` is the 0-ary product).
28
- - `< Type_1 tag_1, ..., Type_k tag_k >` &mdash; Union type of arity $k$ (tagged sum of variants, e.g. `<int ok, string err>`).
29
- - `name` / `@hash` &mdash; Type reference.
30
- 3. **Relation Expressions (`relExpr`)**: Functions transforming an input document to an output document:
25
+ 2. **Relation Expressions (`relExpr`)**: Functions transforming an input document to an output document:
31
26
  - `{ rel_1 label_1, ..., rel_k label_k }` &mdash; Product of arity $k$ (evaluates relations into record fields; special case: `{}` evaluates 0 relations, producing empty record `{}`).
32
27
  - `< rel_1, ..., rel_k >` &mdash; Union / ordered choice of arity $k$ (evaluates relations in order until one succeeds).
33
28
  - `( rel_1 ... rel_k )` &mdash; Composition of arity $k$ (sequentially composes relations; special case: `()` is the 0-ary composition denoting identity; parentheses can be omitted when non-empty: `f g`).
34
29
  - `. label` &mdash; Field projection (extracts field `label`).
35
30
  - `/ tag` &mdash; Variant branch projection (extracts payload of variant `tag`).
36
31
  - `| tag` &mdash; Variant constructor (wraps document into variant `tag`).
37
- - `$ typeExpr` &mdash; Type constraint (asserts input matches schema; compile-time Type Error on mismatch).
32
+ - `? filterExpr` &mdash; Pattern filter (asserts input matches pattern; serves as inductive termination witness).
38
33
  - `name` / `@hash` &mdash; Relation reference.
39
34
  - [x] **Simplified Intro**:
40
35
  - Made arbitrary arity explicit across products `{...}`, unions `<...>`, and compositions `(...)`; explained `{}` and `()` as the natural 0-ary special cases; omitted the pattern/filter expressions table from the introductory reference.
41
36
  - [x] **Replaced Misleading Expressions & Snippets**:
42
37
  - Removed phantom concepts (`10` as literal, "bit-path", `{10 int x, 5 int y} plus` in default state).
43
- - Added self-contained snippets (`{} | ok`, `not = < / true | false, / false | true >;`, `$ bool = < {} true, {} false >;`, `not = $ bool < / true | false, {} | true > $ bool;`, `swap = { . y x, . x y };`).
38
+ - Added self-contained snippets (`{} | ok`, `not = < / true | false, / false | true >;`, `bool = ?< {} true, {} false >;`, `not = bool ?X < / true | false, {} | true > ?X;`, `swap = { . y x, . x y };`).
44
39
  - [x] **Command Reference Table**:
45
40
  - Added `:time <expr>`.
46
41
  - Removed obsolete commands: `:rel <name> = expr`, `:val`, `:timing [on|off]`, `:codec define n t b`.
47
- - Updated `:type <name>` to purely inspect and display type definitions (type definition is native via `$ name = typeExpr;`).
42
+ - Removed obsolete commands: `:type`, `:types`, `:code`, `:codes`.
48
43
  - Timing is now always enabled by default across all evaluations.
49
44
  - Updated `:input` documentation to note the interactive browser dialog.
50
- - Clarified `:codes` (type aliases/hashes) and `:rels` (relation aliases).
45
+ - Clarified `:rels` (relation aliases).
51
46
 
52
47
  ---
53
48
 
@@ -56,15 +51,15 @@ This document details the issues, conceptual improvements, and completed enhance
56
51
  ### Concept Correction: External Format Adapters
57
52
  - [x] Reframed codecs as format adapters translating external text to/from $k$ values defined as pairs `(filter, tree)`.
58
53
  - [x] **Type-Specific Codecs**:
59
- - `int`: Converts decimal integers to/from `$ int = < bits '+', bits '-' >`.
60
- - `ieee`: Converts decimal floats to/from `$ float64` records (`sign`, `exponent`, `fraction`).
61
- - `utf8`: Converts text to/from `$ string` (aliased to `$ utf8`), a list of Unicode scalar values (`$ unicode`) partitioned by Unicode planes.
54
+ - `int`: Converts decimal integers to/from `int = ?< bits '+', bits '-' >`.
55
+ - `ieee`: Converts decimal floats to/from `float64` records (`sign`, `exponent`, `fraction`).
56
+ - `utf8`: Converts text to/from `string` (aliased to `utf8`), a list of Unicode scalar values (`unicode`) partitioned by Unicode planes.
62
57
  - `unit`: Converts to/from `{}`.
63
58
  - [x] **Parameterized Codecs**:
64
59
  - `json`: JSON text is untyped; deserializing JSON requires a target $k$ type schema parameter (e.g. `:input {float64 x, string n} json`).
65
60
  - [x] **Custom Codec Studio**:
66
61
  - Updated explanation to emphasize pairs `(filter, tree)`.
67
- - Fixed `yn` preset to provide self-contained type definition `$ bool = < {} true, {} false >;`.
62
+ - Fixed `yn` preset to provide self-contained relation definition `bool = ?< {} true, {} false >;`.
68
63
  - Fixed `blank` preset with proper Value payload formatting.
69
64
 
70
65
  ---
@@ -105,7 +100,7 @@ This document details the issues, conceptual improvements, and completed enhance
105
100
  - Verified via headless Chromium CDP automated tests that `#btn-help` is completely visible and interactable at narrow viewport widths (e.g. 600px).
106
101
  - [x] **Removed Obsolete Commands**:
107
102
  - Removed `:rel <name> = expr` and `:def` (relations are defined using native syntax `name = expr;`).
108
- - Removed `:type <name> = <...>` definition syntax from `:type` (types are defined using native syntax `$ name = typeExpr;`; `:type <name>` remains for inspecting type definitions).
103
+ - Removed `:type`, `:types`, `:code`, `:codes` commands completely on `no-codes`.
109
104
  - Removed `:val` completely.
110
105
  - Removed `:timing [on|off]` (timing reporting is now permanently enabled by default for all evaluations; `:time <expr>` remains for explicit timing).
111
106
  - Removed `:codec define n t b` (custom codecs are created using the browser Custom Codec Studio UI or loaded from modules via `:codec load`).
package/backend-api.mjs CHANGED
@@ -4,7 +4,15 @@ export { decodeWire, encodeToWire } from "./codecs/runtime/prefix-codec.mjs";
4
4
  export { exportPatternGraph, NODE_KIND } from "./codecs/runtime/codec.mjs";
5
5
  export { patternToPropertyList, propertyListToPattern } from "./codecs/runtime/pattern-json.mjs";
6
6
  export { Value, fromObject, isProduct, isVariant, isValue } from "./Value.mjs";
7
- export { KIR_FORMAT, KIR_VERSION, objectToKIRP, retypeObjectRelation, retypeObjectRelationForBackend } from "./kir.mjs";
7
+ export {
8
+ KIR_FORMAT,
9
+ KIR_VERSION,
10
+ objectToKIRP,
11
+ relationPatternPropertyList,
12
+ retypeObjectRelation,
13
+ retypeObjectRelationForBackend,
14
+ specializeObjectRelations
15
+ } from "./kir.mjs";
8
16
  export { compileLibrary, decodeObject, loadLibrary } from "./object.mjs";
9
17
  export { createState, evaluateInput } from "./repl.mjs";
10
18
  export { parse as parseFloat64, print as printFloat64 } from "./codecs/ieee.mjs";
@@ -24,6 +24,11 @@ if (process.argv.includes("-h") || process.argv.includes("--help")) {
24
24
 
25
25
  const tests = [
26
26
  ["tests/test-llvm.mjs", node, ["tests/test-llvm.mjs"]],
27
+ [
28
+ "tests/test-open-product-misalignment.mjs",
29
+ node,
30
+ ["tests/test-open-product-misalignment.mjs", "--assert"]
31
+ ],
27
32
  ["tests/integration.sh", path.join(root, "tests/integration.sh"), []],
28
33
  ["scripts/conformance.mjs", node, ["scripts/conformance.mjs"]]
29
34
  ];
@@ -678,7 +678,7 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
678
678
  const label = ctx.labelRef(inst.label);
679
679
  let val;
680
680
  if (edgeIndex >= 0 && ctx.runtimeMode !== "compact") {
681
- val = lowerProductGetAt(ctx, input, edgeIndex, label);
681
+ val = lowerProductGetAt(ctx, input, edgeIndex, null);
682
682
  } else {
683
683
  val = ctx.tempName("field");
684
684
  ctx.lines.push(` ${val} = call ptr @k_product_get_n(ptr ${input}, ptr ${label.pointer}, i64 ${label.length})`);
@@ -831,6 +831,7 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
831
831
  }
832
832
 
833
833
  regValues.set(cleanReg(inst.dest), product);
834
+ if (inst.pattern) regPatterns.set(cleanReg(inst.dest), inst.pattern);
834
835
  break;
835
836
  }
836
837
  case "union": {
@@ -1011,8 +1011,7 @@ export function emitLLVMModule(input, options = {}) {
1011
1011
  export function compileObjectToLLVM(object, options = {}) {
1012
1012
  const inputPattern = options.inputPattern ? readPattern(options.inputPattern) : null;
1013
1013
  const relation = options.relation || object.main;
1014
-
1015
- let retypedKir = null;
1014
+ let targetObject = object;
1016
1015
  let entryInputPattern = inputPattern;
1017
1016
  let outputPattern = null;
1018
1017
 
@@ -1020,43 +1019,37 @@ export function compileObjectToLLVM(object, options = {}) {
1020
1019
  const retyped = retypeObjectRelationForBackend(object, relation, inputPattern, {
1021
1020
  source: options.source || "<k-llvm>"
1022
1021
  });
1023
- retypedKir = retyped.kir;
1022
+ targetObject = retyped.retypedObject;
1024
1023
  entryInputPattern = retyped.inputPattern;
1025
1024
  outputPattern = retyped.outputPattern;
1026
- } else {
1027
- retypedKir = objectToKIRP(object);
1028
1025
  }
1029
1026
 
1030
- let kvmArtifact = objectToKVMArtifact(object, relation, null, options);
1031
- let specializedKvm = kvmArtifact;
1032
- if (inputPattern) {
1033
- try {
1034
- specializedKvm = specializeKVM(kvmArtifact, inputPattern);
1035
- } catch {
1036
- specializedKvm = {
1037
- ...kvmArtifact,
1038
- functions: lowerKIRToKVM(retypedKir),
1039
- entry: relation
1040
- };
1041
- }
1042
- }
1043
-
1044
- const entry = specializedKvm.entry || relation;
1045
- const functions = specializedKvm.functions;
1027
+ const retypedKir = objectToKIRP(targetObject);
1028
+ const functions = lowerKIRToKVM(retypedKir);
1029
+ const entry = relation || targetObject.main || "__main__";
1030
+
1031
+ const specializedKvm = {
1032
+ format: "k-vm",
1033
+ version: 1,
1034
+ entry,
1035
+ functions,
1036
+ inputPattern: entryInputPattern,
1037
+ outputPattern
1038
+ };
1046
1039
 
1047
1040
  const llvm = compileKVMModuleToLLVM(entry, functions, {
1048
1041
  ...options,
1049
1042
  relation,
1050
- inputPattern: entryInputPattern || specializedKvm.inputPattern,
1051
- outputPattern: outputPattern || specializedKvm.outputPattern
1043
+ inputPattern: entryInputPattern,
1044
+ outputPattern
1052
1045
  });
1053
1046
 
1054
1047
  return {
1055
1048
  kir: retypedKir,
1056
1049
  kvm: specializedKvm,
1057
1050
  relation,
1058
- inputPattern: entryInputPattern || specializedKvm.inputPattern,
1059
- outputPattern: outputPattern || specializedKvm.outputPattern,
1051
+ inputPattern: entryInputPattern,
1052
+ outputPattern,
1060
1053
  llvm
1061
1054
  };
1062
1055
  }
@@ -112,7 +112,7 @@ node --input-type=module -e "import { stdout } from 'node:process'; import { enc
112
112
  | node --input-type=module -e "import { stdin } from 'node:process'; import { decodeWire } from '../../codecs/runtime/prefix-codec.mjs'; const chunks = []; stdin.on('data', (chunk) => chunks.push(chunk)); stdin.on('end', () => console.log(JSON.stringify(decodeWire(Buffer.concat(chunks)).pattern)));" \
113
113
  | grep -Fqx '[["open-union",[["left",1],["right",1]]],["closed-product",[]]]'
114
114
 
115
- node ./bin/k-llvm-build.mjs '$bits = < {} _, bits 0, bits 1 >; $int = < bits "+", bits "-" >; $int' -o "$TMP_DIR/id-int-exe"
115
+ node ./bin/k-llvm-build.mjs '?< <bits 0, bits 1, {} _>=bits "+", bits "-">' -o "$TMP_DIR/id-int-exe"
116
116
  printf '2' \
117
117
  | node ../../codecs/int.mjs --parse \
118
118
  | "$TMP_DIR/id-int-exe" \
@@ -121,7 +121,7 @@ printf '2' \
121
121
 
122
122
  node --input-type=module -e "import assert from 'node:assert/strict'; import { spawn } from 'node:child_process'; import { encodeToWire, decodeWire } from '../../codecs/runtime/prefix-codec.mjs'; import { parse, INT_PATTERN } from '../../codecs/int.mjs'; const input = encodeToWire(parse('2'), INT_PATTERN); const header = Buffer.alloc(4); header.writeUInt32BE(input.length); const child = spawn(process.argv[1], ['--server']); const chunks = []; const stderr = []; child.stdout.on('data', (chunk) => chunks.push(chunk)); child.stderr.on('data', (chunk) => stderr.push(chunk)); child.stdin.end(Buffer.concat([header, input])); const status = await new Promise((resolve, reject) => { child.on('error', reject); child.on('close', resolve); }); assert.equal(status, 0, Buffer.concat(stderr).toString('utf8')); const output = Buffer.concat(chunks); const length = output.readUInt32BE(0); assert.equal(output.length, 4 + length); assert.deepEqual(decodeWire(output.subarray(4)).value.toJSON(), parse('2').toJSON());" "$TMP_DIR/id-int-exe"
123
123
 
124
- node ./bin/k-llvm-build.mjs --lib ../../Examples/arithmetics.k --export times 's = {()x, ()y} times; s' -o "$TMP_DIR/square-exe"
124
+ node ./bin/k-llvm-build.mjs --lib ../../Examples/arithmetics.k --export times 's = ?< <bits 0, bits 1, {} _>=bits "+", bits "-" > {()x, ()y} times; s' -o "$TMP_DIR/square-exe"
125
125
  printf '987654321' \
126
126
  | node ../../codecs/int.mjs --parse \
127
127
  | "$TMP_DIR/square-exe" \
@@ -239,11 +239,11 @@ assert.doesNotMatch(nestedUnionLLVM, /call void @k_product_set_at\(ptr %product\
239
239
  assert.doesNotMatch(nestedUnionLLVM, /ptr false/);
240
240
 
241
241
  const productRecurseObject = decodeObject(compileObjectBuffer(`
242
- $ list = < {} nil, { {} car, list cdr } cons >;
243
- foo = $list <
242
+ list = ?< {} nil, { {} car, list cdr } cons >;
243
+ foo = list <
244
244
  /nil |nil,
245
245
  /cons { .car car, .cdr foo cdr } |cons
246
- > $list;
246
+ > list;
247
247
  foo
248
248
  `, { source: "llvm-product-recurse.k" }));
249
249
  const { llvm: productRecurseLLVM } = compileObjectToLLVM(productRecurseObject, {