@fraczak/k 6.0.1 → 6.0.3

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 (55) hide show
  1. package/AGENTS.md +35 -0
  2. package/CHANGELOG.md +48 -0
  3. package/CLAUDE.md +64 -0
  4. package/DOCS/BIG_PICTURE.md +4 -8
  5. package/DOCS/BINARY_CODEC_STATUS_AND_TODO.md +74 -0
  6. package/DOCS/CONVERGENCE.md +92 -0
  7. package/DOCS/DIVERGENCE_DETECTION.md +24 -0
  8. package/DOCS/Makefile +99 -0
  9. package/DOCS/OBJECT_FILE_AND_PATTERN.md +221 -0
  10. package/DOCS/PATTERNS.md +114 -0
  11. package/DOCS/PATTERNS_AND_TYPED_VALUES.md +665 -0
  12. package/DOCS/REPL.md +127 -126
  13. package/DOCS/TEXTUAL_VALUES.md +108 -0
  14. package/DOCS/TYPE_DERIVATION.md +230 -0
  15. package/DOCS/book/06-values-in-memory.md +1085 -0
  16. package/DOCS/book/07-the-partial-function-abi.md +143 -0
  17. package/DOCS/book/08-operational-semantics-and-execution.md +201 -0
  18. package/DOCS/book/09-compiler-architecture.md +160 -0
  19. package/DOCS/book/10-from-ast-to-intermediate-representation.md +167 -0
  20. package/DOCS/book/14-canonical-serialization.md +176 -0
  21. package/DOCS/book/appendix-b-incorporating-external-predefined-types-and-functions.md +155 -0
  22. package/DOCS/book/overview.txt +68 -0
  23. package/README.md +78 -30
  24. package/UU/ta.k +1 -0
  25. package/UU/ta.k~ +0 -0
  26. package/UU/tb.k +0 -0
  27. package/UU/tc.k +0 -0
  28. package/codecs/README.md +12 -0
  29. package/codecs/pandoc.css +71 -0
  30. package/codecs/runtime/test-codec.mjs +89 -0
  31. package/core.klib +0 -0
  32. package/core.klib~ +0 -0
  33. package/ieee.klib +0 -0
  34. package/kkk.k +197 -0
  35. package/kkk.klib +0 -0
  36. package/kkk.klib~ +0 -0
  37. package/object.mjs +162 -8
  38. package/objects/README.md +10 -0
  39. package/objects/compile-lib.mjs +26 -2
  40. package/objects/compile.mjs +26 -2
  41. package/objects/decompile.mjs +25 -2
  42. package/objects/extract-aliases.mjs +59 -0
  43. package/package.json +3 -2
  44. package/{codecs/k-pattern.mjs → patterns/from-k.mjs} +3 -3
  45. package/repl2.mjs +345 -83
  46. package/scripts/generate-dependency-graph.mjs +121 -0
  47. package/test-k-object.mjs +77 -1
  48. package/test-repl2.mjs +65 -8
  49. package/DOCS/book-combined.html +0 -3798
  50. package/DOCS/book-combined.md +0 -3745
  51. package/DOCS/book-combined.pdf +0 -0
  52. package/DOCS/book-combined.tex +0 -5682
  53. package/DOCS/book.html +0 -65
  54. package/DOCS/book.pdf +0 -0
  55. package/DOCS/book.tex +0 -150
@@ -1,3798 +0,0 @@
1
- <div data-align="center">
2
- <pre><code> { } { }
3
- / \ {.lang name} |
4
- lang by --&gt; name
5
- | | |
6
- &#39;k&#39; &#39;wojtek&#39; &#39;k&#39;</code></pre>
7
- </div>
8
- <h1 id="table-of-contents">Table of Contents</h1>
9
- <ol type="1">
10
- <li><a href="#chapter-1-introduction">Introduction</a></li>
11
- <li><a href="#chapter-2-syntax-and-values">Syntax and Values</a></li>
12
- <li><a href="#chapter-3-types-as-finite-automata">Types as Finite
13
- Automata</a></li>
14
- <li><a href="#chapter-4-partial-functions-and-composition">Partial
15
- Functions and Composition</a></li>
16
- <li><a href="#chapter-5-typing-filters-and-normalization">Typing,
17
- Filters, and Normalization</a></li>
18
- <li><a href="#chapter-6-values-in-memory">Values in Memory</a></li>
19
- <li><a href="#chapter-7-the-partial-function-abi">The Partial Function
20
- ABI</a></li>
21
- <li><a href="#chapter-8-operational-semantics-and-execution">Operational
22
- Semantics and Execution</a></li>
23
- <li><a href="#chapter-9-compiler-architecture">Compiler
24
- Architecture</a></li>
25
- <li><a href="#chapter-10-from-ast-to-intermediate-representation">From
26
- AST to Intermediate Representation</a></li>
27
- <li><a href="#chapter-11-llvm-basics">LLVM Basics</a></li>
28
- <li><a href="#chapter-12-code-generation">Code Generation</a></li>
29
- <li><a href="#chapter-13-linking-and-execution">Linking and
30
- Execution</a></li>
31
- <li><a href="#chapter-14-canonical-serialization">Canonical
32
- Serialization</a></li>
33
- <li><a href="#chapter-15-optimization-and-folding">Optimization and
34
- Folding</a></li>
35
- <li><a href="#chapter-16-toward-a-universal-schema-registry">Toward a
36
- Universal Schema Registry</a></li>
37
- </ol>
38
- <h2 id="appendices">Appendices</h2>
39
- <ul>
40
- <li><a
41
- href="#appendix-a-implementing-a-prototype-compiler-in-python">Appendix
42
- A: Implementing a Prototype Compiler in Python</a></li>
43
- <li><a
44
- href="#appendix-b-incorporating-external-predefined-types-and-functions">Appendix
45
- B: Incorporating External Predefined Types and Functions</a></li>
46
- </ul>
47
- <hr />
48
- <h1 id="chapter-1-introduction">Chapter 1 — Introduction</h1>
49
- <h2 id="the-purpose-of-this-book"><strong>1.1 The purpose of this
50
- book</strong></h2>
51
- <p>This book describes a small programming language called
52
- <strong>k</strong>. It is meant to show how data can be represented and
53
- transformed in a uniform, precise way.</p>
54
- <hr />
55
- <h2 id="data-as-trees"><strong>1.2 Data as trees</strong></h2>
56
- <p>All information in <code>k</code> is treated as a
57
- <strong>tree</strong>. A tree has:</p>
58
- <ul>
59
- <li>a single root,</li>
60
- <li>labeled edges (field names or tags),</li>
61
- <li>and possibly subtrees.</li>
62
- </ul>
63
- <p>Both JSON objects and XML documents are trees in this sense. Every
64
- <code>k</code> value is such a finite labeled tree.</p>
65
- <hr />
66
- <h2 id="functions-that-may-fail"><strong>1.3 Functions that may
67
- fail</strong></h2>
68
- <p>In ordinary mathematics a function always returns a result. In
69
- <code>k</code>, a function may be <strong>undefined</strong> for some
70
- inputs. For example, asking for the field <code>age</code> in a record
71
- that has no <code>age</code> is undefined.</p>
72
- <p>We call such mappings <strong>partial functions</strong>.</p>
73
- <hr />
74
- <h2 id="simplicity-over-features"><strong>1.4 Simplicity over
75
- features</strong></h2>
76
- <p><code>k</code> avoids most language constructs: no <em>variables</em>
77
- and no <em>control statements</em>. It has only:</p>
78
- <ol type="1">
79
- <li><strong>types</strong> (which describe tree shapes), and</li>
80
- <li><strong>partial functions</strong> (which transform one tree into
81
- another).</li>
82
- </ol>
83
- <p>These two ingredients are sufficient and powerful enough to express
84
- structured computation in a concise and understandable way.</p>
85
- <p>There is another concept in the language, called
86
- <strong>filters</strong>. Filters play a role in the process of
87
- reasoning about types of partial functions. Filters have been added to
88
- the syntax of the language as they allow explicit annotations of
89
- “polymorphic” expressions, i.e., expressions which make sense in
90
- different contexts. Filters are similar to <em>type classes</em> in
91
- other languages.</p>
92
- <hr />
93
- <hr />
94
- <h1 id="chapter-2-syntax-and-values">Chapter 2 — Syntax and Values</h1>
95
- <h2 id="language-fragments"><strong>2.1 Language fragments</strong></h2>
96
- <p>The <code>k</code> language has only one kind of program element: a
97
- <strong>definition</strong>. A program is a sequence of definitions of
98
- two kinds:</p>
99
- <pre class="k-lang"><code>$ type_name = ...type_expression... ;
100
- function_name = ...expression... ;</code></pre>
101
- <p>The definitions are followed in the file by the <em>main
102
- expression</em>; it represents the partial function defined by the
103
- program as a whole.</p>
104
- <p>There is no syntax for values. Every syntactic form in an expression
105
- describes a <strong>function</strong> – possibly a constant function
106
- that always returns the same value.</p>
107
- <hr />
108
- <h2 id="types"><strong>2.2 Types</strong></h2>
109
- <p>A type describes the possible <strong>tree shapes</strong> of values.
110
- Types are formed from two constructors:</p>
111
- <ol type="1">
112
- <li><p><strong>Product</strong> – written
113
- <code>{ T₁ l₁, T₂ l₂, … }</code> represents records with fixed labeled
114
- fields.</p></li>
115
- <li><p><strong>Union</strong> – written
116
- <code>&lt; T₁ l₁, T₂ l₂, … &gt;</code> represents a choice between
117
- labeled alternatives.</p></li>
118
- </ol>
119
- <p>Both are finite and fully explicit. Every type denotes a finite tree
120
- automaton whose accepted trees are the possible values of that type.</p>
121
- <hr />
122
- <h2 id="special-and-limiting-cases"><strong>2.3 Special and limiting
123
- cases</strong></h2>
124
- <ol type="1">
125
- <li><p><strong>Empty product</strong> <code>{}</code> has no fields. It
126
- represents the type that admits exactly one value, called <em>unit</em>.
127
- There is nothing exceptional about the type and its value; it is simply
128
- the degenerate case of a product with zero fields.</p></li>
129
- <li><p><strong>Empty union</strong> <code>&lt;&gt;</code> has no
130
- variants. It represents a type with no possible values.</p></li>
131
- </ol>
132
- <hr />
133
- <h2 id="projections"><strong>2.4 Projections</strong></h2>
134
- <p><strong>Dot</strong> notation, e.g.,</p>
135
- <pre class="k"><code> . field_name</code></pre>
136
- <p>is used for extracting the value of a field from a record (product
137
- type value). <strong>Div</strong> notation, e.g.,</p>
138
- <pre class="k"><code> / variant_name</code></pre>
139
- <p>is used for asserting a particular variant of a union and extracting
140
- its value. Product type <code>{ T₁ l₁, T₂ l₂, … , Tₙ lₙ }</code>
141
- naturally defines <code>n</code> partial functions:
142
- <code>.l₁, .l₂, … , .lₙ</code>,<br />
143
- and union type <code>&lt; T₁ l₁, T₂ l₂, … , Tₙ lₙ &gt;</code> naturally
144
- defines <code>n</code> partial functions <code>/l₁, /l₂, … , /lₙ</code>.
145
- Those partial functions are called <strong>projections</strong> and they
146
- constitute the basis for the definition of all other partial functions
147
- in the <code>k</code> language.</p>
148
- <hr />
149
- <h2 id="functions"><strong>2.5 Functions</strong></h2>
150
- <p>Expressions combine partial functions using the following
151
- operators:</p>
152
- <ol type="1">
153
- <li><strong>Composition</strong> <code>(f₁ f₂ …)</code> — sequential
154
- application.</li>
155
- <li><strong>Union</strong> <code>&lt; f₁, f₂, … &gt;</code> — try each
156
- in order, first defined wins.</li>
157
- <li><strong>Product (parallel)</strong> <code>{ f₁ l₁, f₂ l₂, … }</code>
158
- — apply all to the same input, succeed only if all succeed.</li>
159
- <li><strong>Variant construction</strong> <code>| tag</code> — lift the
160
- input as a variant <code>tag</code> of a union type.</li>
161
- </ol>
162
- <p>Parentheses around a composition may be omitted except for the empty
163
- composition <code>()</code> — the identity function. Empty product,
164
- <code>{ }</code>, defines a constant function (ignoring its input)
165
- returning <em>unit</em>.</p>
166
- <p>It is important to notice that after the three markers:
167
- <code>dot (.)</code>, <code>div (/)</code>, or <code>pipe (|)</code>,
168
- there must be a constant label literal. For that reason, it is possible
169
- and advised not to leave any blanks after the marker, e.g.:</p>
170
- <pre class="k-lang"><code> .field /&#39;a-tag&#39; |&quot;strange and long tag name ✅&quot; </code></pre>
171
- <hr />
172
- <h2 id="example"><strong>2.6 Example</strong></h2>
173
- <pre class="k-lang"><code>$ bool = &lt; {} true, {} false &gt;;
174
- true = {} |true $ bool;
175
- false = {} |false $ bool;
176
- neg = $ bool &lt; /true false, /false true &gt;;</code></pre>
177
- <p>This defines a “two-variant” union type and three functions: two
178
- constants and one transformation exchanging the variants.</p>
179
- <hr />
180
- <h2 id="summary"><strong>2.7 Summary</strong></h2>
181
- <ul>
182
- <li>All types describe tree shapes.</li>
183
- <li>As type expression, <code>{}</code> is the empty product type (with
184
- one value, called <em>unit</em>).</li>
185
- <li>Functions, not values, are the only expressions in
186
- <code>k</code>.</li>
187
- </ul>
188
- <hr />
189
- <hr />
190
- <h1 id="chapter-3-types-as-finite-automata">Chapter 3 — Types as Finite
191
- Automata</h1>
192
- <h2 id="motivation"><strong>3.1 Motivation</strong></h2>
193
- <p>A type in <code>k</code> describes a set of finite labeled trees,
194
- which can be recognized by a finite tree automaton (FTA). Equivalently,
195
- a type definition can be seen as a Context-Free Grammar (CFG), where the
196
- values of the type are the derivation trees of the grammar.</p>
197
- <p>For example, the recursive type definition of a
198
- <code>list</code>:</p>
199
- <pre class="k-lang"><code>$ bool = &lt; {} true, {} false &gt;;
200
- $ list = &lt; {} nil, { bool head, list tail } cons &gt;;</code></pre>
201
- <p>corresponds to the following 4-rule grammar:</p>
202
- <pre class="bnf"><code>1: &lt;bool&gt; ::= {} |true
203
- 2: &lt;bool&gt; ::= {} |false
204
- 3: &lt;list&gt; ::= {} |nil
205
- 4: &lt;list&gt; ::= { &lt;bool&gt; head, &lt;list&gt; tail } |cons</code></pre>
206
- <p>A value of type <code>list</code> is a derivation tree of this
207
- grammar. For instance, a list containing a single boolean value
208
- <code>true</code> can be represented by the following derivation:</p>
209
- <pre><code>&lt;list&gt;
210
- -- (rule 4) --&gt; { &lt;bool&gt; head, &lt;list&gt; tail } |cons
211
- | |
212
- | -- (rule 3) --&gt; {} |nil
213
- |
214
- -- (rule 1) --&gt; {} |true</code></pre>
215
- <p>This derivation tree corresponds to the value generated by constant
216
- function: <code>{ {} |true head, {} |nil tail } |cons</code>.</p>
217
- <p>Representing types as automata (or CFGs) provides each type with a
218
- well-defined structure, independent of the names used in the source
219
- code. This allows for canonical normal forms and for comparing types for
220
- equality by structure alone.</p>
221
- <hr />
222
- <h2 id="states-and-transitions"><strong>3.2 States and
223
- Transitions</strong></h2>
224
- <p>Each type definition introduces one or more <em>states</em> in the
225
- automaton. A union or a product definition corresponds to a state, and
226
- the variants or fields correspond to transitions to other states.</p>
227
- <p>For example, consider the <code>$bool</code> type:</p>
228
- <pre class="k-lang"><code>$ bool = &lt; {} true, {} false &gt;;</code></pre>
229
- <p>This definition translates to an automaton with two states:</p>
230
- <ul>
231
- <li>A root state, let’s call it <code>C0</code>, representing the
232
- <code>$bool</code> type itself (a union).</li>
233
- <li>A state <code>C1</code> representing the empty product
234
- <code>{}</code>.</li>
235
- </ul>
236
- <p>From the root state <code>C0</code>, there are two transitions:</p>
237
- <ul>
238
- <li>A transition labeled <code>true</code> to state
239
- <code>C1</code>.</li>
240
- <li>A transition labeled <code>false</code> to state
241
- <code>C1</code>.</li>
242
- </ul>
243
- <p><code>C0</code> is the root state of the type, and <code>C1</code> is
244
- a leaf state, representing an empty value.</p>
245
- <hr />
246
- <h2 id="canonical-form"><strong>3.3 Canonical Form</strong></h2>
247
- <p>Different type expressions can describe the same automaton. For
248
- example:</p>
249
- <pre class="k-lang"><code>$ bool = &lt; {} false, {} true &gt;;
250
- $ pair = { bool x, bool y };
251
- $ pair2 = { &lt; {} true, {} false &gt; x, bool y };</code></pre>
252
- <p>The types <code>pair</code> and <code>pair2</code> are structurally
253
- equivalent because <code>$bool</code> is defined as
254
- <code>&lt; {} true, {} false &gt;</code>, making the definition of
255
- <code>x</code> in <code>pair2</code> identical to the standalone
256
- <code>$bool</code> type used in <code>pair</code>. Canonicalization is
257
- the process of removing these superficial differences by erasing local
258
- names and renumbering states to produce a single stable representation
259
- for each unique type structure.</p>
260
- <p>The canonical form is generated by traversing the type’s graph
261
- structure starting from its root state. The process ensures a unique
262
- representation by following a consistent ordering:</p>
263
- <ol type="1">
264
- <li><strong>Start at the Root</strong>: Assign the number
265
- <code>C0</code> to the root state of the type.</li>
266
- <li><strong>Explore Neighbors</strong>: Visit all states reachable from
267
- <code>C0</code>. Sort the transitions alphabetically by their labels
268
- (field or variant names) and assign consecutive numbers
269
- (<code>C1</code>, <code>C2</code>, …) to the destination states in that
270
- order.</li>
271
- <li><strong>Iterate</strong>: Move to the next state in the numbered
272
- sequence (<code>C1</code>, then <code>C2</code>, etc.) and repeat the
273
- process for any of its neighbors that have not yet been numbered.</li>
274
- <li><strong>Complete</strong>: Continue until all reachable states have
275
- been assigned a unique number.</li>
276
- </ol>
277
- <p>This traversal produces a unique and deterministic numbering for any
278
- finite directed graph, ensuring that any two structurally identical
279
- types will have the exact same canonical representation.</p>
280
- <hr />
281
- <h2 id="examples"><strong>3.4 Examples</strong></h2>
282
- <p>For a type representing binary natural numbers:</p>
283
- <pre class="k-lang"><code>$ bnat = &lt; bnat 0, bnat 1, {} _ &gt;;</code></pre>
284
- <p>the canonical form is:</p>
285
- <pre class="k-lang"><code>$C0 = &lt; C0 &quot;0&quot;, C0 &quot;1&quot;, C1 &quot;_&quot; &gt;;
286
- $C1 = {};</code></pre>
287
- <p>The automaton has two states. <code>C0</code> is a recursive state
288
- that recognizes sequences of “0”s and “1”s, while <code>C1</code> is the
289
- terminal state, marked by the “_” transition.</p>
290
- <hr />
291
- <h2 id="normalization-process"><strong>3.5 Normalization
292
- Process</strong></h2>
293
- <p>When compiling a program, the following steps are taken to normalize
294
- types:</p>
295
- <ol type="1">
296
- <li><strong>Collect</strong>: Gather all type definitions from the
297
- program.</li>
298
- <li><strong>Expand</strong>: Recursively replace all named types with
299
- their underlying definitions until only products and unions remain.</li>
300
- <li><strong>Deduplicate</strong>: Eliminate duplicate type structures by
301
- comparing them structurally.</li>
302
- <li><strong>Canonicalize</strong>: Assign stable state numbers to the
303
- unique types to produce their canonical text representation.</li>
304
- </ol>
305
- <p>This process is deterministic, ensuring that the same type structure
306
- always produces the exact same canonical form.</p>
307
- <hr />
308
- <h2 id="hash-based-naming"><strong>3.6 Hash-Based Naming</strong></h2>
309
- <p>To create a globally unique and stable identifier for each type, the
310
- compiler computes a hash of its canonical representation. This hash
311
- becomes the official, unambiguous name of the type.</p>
312
- <p>For example:</p>
313
- <pre class="text"><code>Canonical Form: $C0=&lt;C0&quot;0&quot;,C0&quot;1&quot;,C1&quot;_&quot;&gt;;$C1={}
314
- ↓
315
- Hash
316
- ↓
317
- Identifier: @BsAqRMv</code></pre>
318
- <p>Program objects can then refer to types by their hash-based
319
- identifiers (prefixed with <code>@</code>) without ambiguity.</p>
320
- <hr />
321
- <h2 id="interpretation"><strong>3.7 Interpretation</strong></h2>
322
- <p>The canonical representation of a type can be interpreted as:</p>
323
- <ul>
324
- <li>A finite set of states, <code>C0…Cn</code>.</li>
325
- <li>Each state is either a product (a record with named fields) or a
326
- union (a set of variants).</li>
327
- <li>Transitions between states are labeled with strings (field or
328
- variant names).</li>
329
- </ul>
330
- <p>Every value of a given type is a finite tree that is accepted by this
331
- automaton.</p>
332
- <hr />
333
- <h2 id="summary-1"><strong>3.8 Summary</strong></h2>
334
- <ul>
335
- <li>Types in <code>k</code> denote sets of finite, labeled trees.</li>
336
- <li>Every type can be expressed as a finite tree automaton or a
337
- context-free grammar.</li>
338
- <li>The canonical form eliminates naming differences, providing a single
339
- representation for structurally identical types.</li>
340
- <li>Hash-based naming gives each unique type a stable and globally
341
- unique identifier.</li>
342
- </ul>
343
- <hr />
344
- <hr />
345
- <h1 id="chapter-4-partial-functions-and-composition">Chapter 4 — Partial
346
- Functions and Composition</h1>
347
- <h2 id="partial-functions"><strong>4.1 Partial functions</strong></h2>
348
- <p>A <strong>partial function</strong> is a mapping that may be
349
- undefined for some inputs. In <code>k</code>, every expression denotes
350
- such a function. If a function is undefined for a given input, the
351
- evaluation process halts at that point, producing no result.</p>
352
- <p>There is no notion of error or exception. Undefined means simply “no
353
- output”.</p>
354
- <hr />
355
- <h2 id="composition"><strong>4.2 Composition</strong></h2>
356
- <p>Composition combines two or more partial functions sequentially. If
357
- <code>f</code> and <code>g</code> are functions, <code>(f g)</code>
358
- means “apply <code>f</code>, then apply <code>g</code> to the
359
- result”.</p>
360
- <p>A composition <code>(f g)</code> is defined on a value <code>x</code>
361
- if and only if:</p>
362
- <ul>
363
- <li><code>f</code> is defined on <code>x</code>, and</li>
364
- <li><code>g</code> is defined on the result of <code>f(x)</code>.</li>
365
- </ul>
366
- <p>Otherwise, the composition is undefined.</p>
367
- <p>Composition is <strong>associative</strong>:</p>
368
- <pre class="math"><code>(f (g h)) ≡ ((f g) h)</code></pre>
369
- <p>Therefore, parentheses are unnecessary, except for the special case
370
- of the <strong>empty composition</strong>, written <code>()</code>,
371
- which is the identity function:</p>
372
- <pre class="math"><code>() x = x () = x</code></pre>
373
- <hr />
374
- <h2 id="product-composition"><strong>4.3 Product
375
- composition</strong></h2>
376
- <p>Product composition creates a function that applies several
377
- subfunctions in parallel to the same input and gathers their results
378
- into a product value.</p>
379
- <p>Syntax:</p>
380
- <pre class="math"><code>{ f₁ l₁, f₂ l₂, …, fₙ lₙ }</code></pre>
381
- <p>This expression is defined on an input value if all component
382
- functions are defined on that input. Its result is a product with fields
383
- labeled <code>l₁ … lₙ</code>, each containing the result of the
384
- corresponding function.</p>
385
- <hr />
386
- <h2 id="union-composition"><strong>4.4 Union composition</strong></h2>
387
- <p>Union composition represents concurrent evaluation with fallback:</p>
388
- <pre class="k-lang"><code>&lt; f₁, f₂, …, fₙ &gt;</code></pre>
389
- <p>The result is defined for an input <code>x</code> if at least one
390
- subfunction is defined. Evaluation proceeds left to right; the first
391
- defined result is used. If none are defined, the result is
392
- undefined.</p>
393
- <p>Example:</p>
394
- <pre class="k-lang"><code>&lt; /x, /y &gt;</code></pre>
395
- <p>extracts variant <code>x</code> if present; otherwise <code>y</code>
396
- if present.</p>
397
- <hr />
398
- <h2 id="constants"><strong>4.5 Constants</strong></h2>
399
- <p>A constant function is one that always returns the same value,
400
- regardless of its input. Since <code>k</code> lacks a direct syntax for
401
- literal values, constants are created using functions that produce
402
- them.</p>
403
- <p>For example, we can define functions that return <code>true</code>
404
- and <code>false</code>:</p>
405
- <pre class="k-lang"><code>$ bool = &lt; {} true, {} false &gt;;
406
- true_bool = {} |true $bool ;
407
- false_bool = {} |false $bool ;</code></pre>
408
- <p>Here, <code>true_bool</code> and <code>false_bool</code> are constant
409
- functions. They are also <strong>total functions</strong>, meaning they
410
- are defined for all inputs. Each function ignores its input and produces
411
- a fixed boolean value.</p>
412
- <hr />
413
- <h2 id="projection-and-variant-value-constructor"><strong>4.6 Projection
414
- and Variant Value constructor</strong></h2>
415
- <p>Projection selects a field or a variant from a product or union. It
416
- is written with a leading dot <code>.</code> or a leading slash
417
- <code>/</code>, respectively:</p>
418
- <pre class="k-lang"><code>.x // Selects field &#39;x&#39; from a product: { T x, ... }
419
- /x // Extracts the value from a union variant &#39;x&#39;: &lt; T x, ... &gt;</code></pre>
420
- <p>If the input is a product, <code>.x</code> returns the value of field
421
- <code>x</code>. If the input is a union, <code>/x</code> returns the
422
- value of variant <code>x</code>. In all other cases, the projection is
423
- undefined.</p>
424
- <p>Variant value constructors for a given union type
425
- <code>T = &lt;T₁ tag₁, T₂ tag₂, … &gt;</code> are written as
426
- <code>|tag₁</code>, <code>|tag₂</code>, ….</p>
427
- <pre class="k-lang"><code>|tag₁ // lift a value of type T₁ into a value of type T</code></pre>
428
- <p>Projections and variant constructors are the most basic partial
429
- functions.</p>
430
- <hr />
431
- <h2 id="derived-combinations"><strong>4.7 Derived
432
- combinations</strong></h2>
433
- <p>Complex functions are built by nesting compositions. For example:</p>
434
- <pre class="k-lang"><code>{ .x field1, .y |tag field2 }</code></pre>
435
- <hr />
436
- <h2 id="identity-and-emptiness"><strong>4.8 Identity and
437
- emptiness</strong></h2>
438
- <p>The empty composition <code>()</code> is the identity function. The
439
- empty union <code>&lt;&gt;</code> is the always-undefined function. The
440
- empty product <code>{}</code> is the constant function returning the
441
- unit value.</p>
442
- <hr />
443
- <h2 id="summary-2"><strong>4.9 Summary</strong></h2>
444
- <ul>
445
- <li>In <code>k</code>, all expressions denote <strong>partial
446
- functions</strong>.</li>
447
- <li>An undefined result simply means “no output,” not an error.</li>
448
- <li><strong>Composition</strong> <code>(f g)</code> applies functions
449
- sequentially and is associative, so parentheses are often optional.</li>
450
- <li>The empty composition <code>()</code> is the <strong>identity
451
- function</strong>.</li>
452
- <li><strong>Product composition</strong> <code>{...}</code> runs
453
- functions in parallel and gathers their results.</li>
454
- <li><strong>Union composition</strong> <code>&lt;...&gt;</code> tries
455
- functions in order, returning the first successful result.</li>
456
- <li><strong>Projections</strong> (<code>.x</code>, <code>/x</code>) are
457
- fundamental building blocks for accessing data structures.</li>
458
- <li><strong>Variant constructor</strong> (<code>|tag</code>) allows
459
- lifting a value into a variant type value.</li>
460
- </ul>
461
- <hr />
462
- <hr />
463
- <h1 id="chapter-5-typing-filters-and-normalization">Chapter 5 — Typing,
464
- Filters, and Normalization</h1>
465
- <h2 id="types-as-functions"><strong>5.1 Types as functions</strong></h2>
466
- <p>A type expression in <code>k</code> can appear wherever a function is
467
- expected. When used this way, it is prefixed by <code>$</code>. It then
468
- behaves as a partial <strong>identity</strong> function that is defined
469
- only for values of that type. For example, <code>$ bool</code> is a
470
- partial identity: it returns its argument unchanged when the argument is
471
- of type <code>bool</code>, and it is undefined otherwise.</p>
472
- <p>This convention eliminates any special syntax for annotating
473
- sub-expressions with types. An expression may be <em>restricted</em> to
474
- a type simply by composing it with the corresponding type
475
- expression.</p>
476
- <hr />
477
- <h2 id="filters"><strong>5.2 Filters</strong></h2>
478
- <p>A <strong>filter</strong> is a syntactic form that denotes a
479
- <em>class of types</em> — a set of types that share a common
480
- structure.</p>
481
- <p>Filter expressions are introduced by <code>?</code> and can be:</p>
482
- <ul>
483
- <li><strong>Type expressions</strong> — <code>? $bool</code>,
484
- <code>? $&lt; {} x, bool y &gt;</code></li>
485
- <li><strong>Product filters</strong> —
486
- <code>? { Filter1 field1, Filter2 field2 }</code><br />
487
- </li>
488
- <li><strong>Union filters</strong> —
489
- <code>? &lt; Filter1 tag1, Filter2 tag2 &gt;</code></li>
490
- <li><strong>Product-or-union filters</strong> —
491
- <code>? ( Filter1 label1, Filter2 label2 )</code></li>
492
- <li><strong>Filter variables</strong> — <code>? X</code> (metavariables
493
- representing unknown types)</li>
494
- <li><strong>Filter bindings</strong> —
495
- <code>? &lt; X f, (...) = Y g, ... &gt; = X</code></li>
496
- </ul>
497
- <p>Filters may contain <code>...</code> to indicate that additional
498
- fields or tags are allowed: <code>? { Filter1 field1, ... }</code>
499
- matches any product with at least <code>field1</code>.</p>
500
- <p>The filter <code>? (...)</code> matches any type. The filter
501
- <code>? {...}</code> matches any product type. The filter
502
- <code>? &lt;...&gt;</code> matches any union type.</p>
503
- <hr />
504
- <h2 id="examples-of-filters"><strong>5.3 Examples of
505
- filters</strong></h2>
506
- <ul>
507
- <li><code>?(...)</code> — represents any type.</li>
508
- <li><code>?()</code> — represents an empty product or empty union.</li>
509
- <li><code>?&lt; (...) f, (...) g &gt;</code> — represents all union
510
- types having exactly two variants <code>f</code> and
511
- <code>g</code>.</li>
512
- <li><code>?{ X f, X g }</code> — represents all product types with two
513
- fields <code>f</code> and <code>g</code>, both of the same type.</li>
514
- </ul>
515
- <p>A filter constrains where a partial function is defined; it does not
516
- affect the operational behavior of the function once defined.</p>
517
- <hr />
518
- <h2 id="recursive-filters"><strong>5.4 Recursive filters</strong></h2>
519
- <p>Filters may be recursive. They can describe families of recursive
520
- types by defining a metavariable in terms of a filter that references
521
- it.</p>
522
- <p>Example (list definition):</p>
523
- <pre class="k-lang"><code>?&lt; {} nil, {X car, Y cdr} cons &gt; = Y</code></pre>
524
- <p>This filter states that <code>Y</code> is a union type with two
525
- variants: <code>nil</code> and <code>cons</code>.</p>
526
- <ul>
527
- <li>The <code>nil</code> variant holds an empty product
528
- <code>{}</code>.</li>
529
- <li>The <code>cons</code> variant is a product with two fields:
530
- <code>car</code> of some type <code>X</code>, and <code>cdr</code> of
531
- type <code>Y</code> itself.</li>
532
- </ul>
533
- <p>This recursive structure defines a linked list where each element has
534
- a <code>car</code> (the value) and a <code>cdr</code> (the rest of the
535
- list). It thus denotes lists of elements of type <code>X</code>.</p>
536
- <hr />
537
- <h2 id="type-variables-and-scope"><strong>5.5 Type variables and
538
- scope</strong></h2>
539
- <p>A type variable (an identifier, typically starting with an uppercase
540
- letter) introduced in a filter is visible within the enclosing function
541
- definition. For example:</p>
542
- <pre class="k-lang"><code>car = ?&lt; {} nil, {X car, Y cdr} cons &gt; = Y /cons .car ?X;</code></pre>
543
- <p>Here:</p>
544
- <ul>
545
- <li><code>X</code> and <code>Y</code> are type variables.</li>
546
- <li>The filter <code>?&lt;{}nil,{X car,Y cdr}cons&gt;=Y</code>
547
- constrains the function <code>car</code> to be defined only on types
548
- that match the recursive list structure.</li>
549
- <li>The expression <code>/cons</code> selects the <code>cons</code>
550
- variant of the union.</li>
551
- <li>The expression <code>.car</code> accesses the <code>car</code> field
552
- of a <code>cons</code> variant.</li>
553
- <li>The final filter <code>?X</code> asserts that the result of the
554
- field access is of type <code>X</code>, the type of the list’s
555
- elements.</li>
556
- </ul>
557
- <hr />
558
- <h2 id="type-inference-and-normalization"><strong>5.6 Type inference and
559
- normalization</strong></h2>
560
- <p>Every <code>k</code> program can be analyzed to assign an input and
561
- an output filter to every sub-expression. This process is called type
562
- inference abd normalization.</p>
563
- <p>Type inference and normalization proceeds as follows:</p>
564
- <ol type="1">
565
- <li>Build a graph of all type references appearing explicitly and
566
- implicitly in the program.</li>
567
- <li>Annotate each expression node with a pair of (input filter, output
568
- filter).</li>
569
- <li>Replace filters that match a single, concrete type with that type
570
- expression, adding any newly-discovered types to the graph.</li>
571
- <li>Repeat until a fixed point is reached and no more changes
572
- occur.</li>
573
- <li>Compute canonical forms for all newly introduced types.</li>
574
- </ol>
575
- <hr />
576
- <h2 id="summary-3"><strong>5.7 Summary</strong></h2>
577
- <ul>
578
- <li>Type expressions act as identity functions defined on values of that
579
- type.</li>
580
- <li>Filters describe sets of types and can constrain where a function is
581
- defined.</li>
582
- <li>Filters may be products, unions, or product-or-union forms, and can
583
- be recursive.</li>
584
- <li>Variables in filters have definition-level scope.</li>
585
- <li>Normalization computes explicit input/output filters for every
586
- expression.</li>
587
- <li>Filters are used in the normalization and type checking process.
588
- They are ignored at runtime.</li>
589
- </ul>
590
- <hr />
591
- <hr />
592
- <h1 id="chapter-6-values-in-memory-and-canonical-serialization">Chapter
593
- 6 — Values in Memory and Canonical Serialization</h1>
594
- <h2 id="unified-value-representation"><strong>6.1 Unified value
595
- representation</strong></h2>
596
- <p>Every <code>k</code> value exists in one of three forms during
597
- execution:</p>
598
- <ol type="1">
599
- <li><strong>Serialized form</strong> — a canonical bit sequence that can
600
- be stored, transmitted, or passed between processes.</li>
601
- <li><strong>Lazy (or hybrid) form</strong> — a partially deserialized
602
- structure that keeps most data in its serialized form until access is
603
- needed.</li>
604
- <li><strong>Materialized form</strong> — a fully deserialized tree of
605
- nodes in memory.</li>
606
- </ol>
607
- <p>This unified approach enables programs to operate on serialized
608
- inputs without unnecessary deserialization, optimizing performance for
609
- identity operations and partial data access patterns.</p>
610
- <hr />
611
- <h2 id="the-kvalue-abstraction"><strong>6.2 The KValue
612
- abstraction</strong></h2>
613
- <p>All values are represented by a single abstraction:</p>
614
- <div class="sourceCode" id="cb26"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> KValue <span class="op">{</span></span>
615
- <span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">enum</span> ValueForm <span class="op">{</span></span>
616
- <span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a> SERIALIZED<span class="op">,</span> <span class="co">// pure bitstream + type info</span></span>
617
- <span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a> LAZY<span class="op">,</span> <span class="co">// hybrid: some nodes materialized, others serialized</span></span>
618
- <span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a> MATERIALIZED<span class="op">,</span> <span class="co">// traditional tree structure</span></span>
619
- <span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a> EXTERNAL <span class="co">// built-in/foreign type with custom handlers</span></span>
620
- <span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> form<span class="op">;</span></span>
621
- <span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a> </span>
622
- <span id="cb26-9"><a href="#cb26-9" aria-hidden="true" tabindex="-1"></a> <span class="kw">union</span> <span class="op">{</span></span>
623
- <span id="cb26-10"><a href="#cb26-10" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> <span class="op">{</span></span>
624
- <span id="cb26-11"><a href="#cb26-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> bits<span class="op">;</span> <span class="co">// canonical bitstream</span></span>
625
- <span id="cb26-12"><a href="#cb26-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> type_id<span class="op">;</span> <span class="co">// identifies canonical type</span></span>
626
- <span id="cb26-13"><a href="#cb26-13" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> serialized<span class="op">;</span></span>
627
- <span id="cb26-14"><a href="#cb26-14" aria-hidden="true" tabindex="-1"></a> </span>
628
- <span id="cb26-15"><a href="#cb26-15" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> <span class="op">{</span></span>
629
- <span id="cb26-16"><a href="#cb26-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> KNode<span class="op">*</span> root<span class="op">;</span> <span class="co">// root of materialized or partially materialized tree</span></span>
630
- <span id="cb26-17"><a href="#cb26-17" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> materialized<span class="op">;</span></span>
631
- <span id="cb26-18"><a href="#cb26-18" aria-hidden="true" tabindex="-1"></a> </span>
632
- <span id="cb26-19"><a href="#cb26-19" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> <span class="op">{</span></span>
633
- <span id="cb26-20"><a href="#cb26-20" aria-hidden="true" tabindex="-1"></a> <span class="dt">void</span><span class="op">*</span> data<span class="op">;</span> <span class="co">// opaque external data</span></span>
634
- <span id="cb26-21"><a href="#cb26-21" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> type_id<span class="op">;</span> <span class="co">// external type identifier</span></span>
635
- <span id="cb26-22"><a href="#cb26-22" aria-hidden="true" tabindex="-1"></a> ExternalOps<span class="op">*</span> ops<span class="op">;</span> <span class="co">// function pointers for operations</span></span>
636
- <span id="cb26-23"><a href="#cb26-23" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> external<span class="op">;</span></span>
637
- <span id="cb26-24"><a href="#cb26-24" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
638
- <span id="cb26-25"><a href="#cb26-25" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
639
- <h3 id="self-delimiting-streams"><strong>6.2.1 Self-delimiting
640
- streams</strong></h3>
641
- <p>The canonical encoding is <strong>self-delimiting</strong>, meaning
642
- each value can be parsed without knowing its length in advance:</p>
643
- <ul>
644
- <li><strong>Union nodes</strong>: Fixed-length discriminators define
645
- clear boundaries</li>
646
- <li><strong>Product nodes</strong>: Type structure determines field
647
- count and termination<br />
648
- </li>
649
- <li><strong>External data</strong>: Length-prefixed encoding (LEB128 +
650
- payload)</li>
651
- <li><strong>Unit values</strong>: Zero bytes consumed</li>
652
- </ul>
653
- <p>This enables <strong>streaming evaluation</strong> where programs can
654
- process data incrementally without buffering entire inputs.</p>
655
- <hr />
656
- <h2 id="lazy-node-structure"><strong>6.3 Lazy node
657
- structure</strong></h2>
658
- <p>Nodes in lazy values can be in different states of
659
- materialization:</p>
660
- <div class="sourceCode" id="cb27"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> KNode <span class="op">{</span></span>
661
- <span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> state<span class="op">;</span> <span class="co">// canonical type state (C0, C1,…)</span></span>
662
- <span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> tag<span class="op">;</span> <span class="co">// variant index, −1 for product</span></span>
663
- <span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> arity<span class="op">;</span> <span class="co">// number of children</span></span>
664
- <span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a> </span>
665
- <span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">enum</span> NodeState <span class="op">{</span></span>
666
- <span id="cb27-7"><a href="#cb27-7" aria-hidden="true" tabindex="-1"></a> SERIALIZED_CHILD<span class="op">,</span> <span class="co">// child exists as bitstream only</span></span>
667
- <span id="cb27-8"><a href="#cb27-8" aria-hidden="true" tabindex="-1"></a> MATERIALIZED_CHILD<span class="op">,</span> <span class="co">// child is fully materialized</span></span>
668
- <span id="cb27-9"><a href="#cb27-9" aria-hidden="true" tabindex="-1"></a> EXTERNAL_CHILD <span class="co">// child is external/built-in type</span></span>
669
- <span id="cb27-10"><a href="#cb27-10" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
670
- <span id="cb27-11"><a href="#cb27-11" aria-hidden="true" tabindex="-1"></a> </span>
671
- <span id="cb27-12"><a href="#cb27-12" aria-hidden="true" tabindex="-1"></a> <span class="kw">union</span> KChild <span class="op">{</span></span>
672
- <span id="cb27-13"><a href="#cb27-13" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> <span class="op">{</span></span>
673
- <span id="cb27-14"><a href="#cb27-14" aria-hidden="true" tabindex="-1"></a> <span class="kw">enum</span> NodeState state<span class="op">;</span> <span class="co">// which kind of child this is</span></span>
674
- <span id="cb27-15"><a href="#cb27-15" aria-hidden="true" tabindex="-1"></a> <span class="kw">union</span> <span class="op">{</span></span>
675
- <span id="cb27-16"><a href="#cb27-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> KNode<span class="op">*</span> node<span class="op">;</span> <span class="co">// materialized child</span></span>
676
- <span id="cb27-17"><a href="#cb27-17" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> <span class="op">{</span></span>
677
- <span id="cb27-18"><a href="#cb27-18" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> bits<span class="op">;</span> <span class="co">// serialized child data</span></span>
678
- <span id="cb27-19"><a href="#cb27-19" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> bit_offset<span class="op">;</span> <span class="co">// position within parent&#39;s bitstream</span></span>
679
- <span id="cb27-20"><a href="#cb27-20" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> serialized<span class="op">;</span></span>
680
- <span id="cb27-21"><a href="#cb27-21" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> KValue<span class="op">*</span> external<span class="op">;</span> <span class="co">// external child</span></span>
681
- <span id="cb27-22"><a href="#cb27-22" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
682
- <span id="cb27-23"><a href="#cb27-23" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
683
- <span id="cb27-24"><a href="#cb27-24" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> child<span class="op">[];</span></span>
684
- <span id="cb27-25"><a href="#cb27-25" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
685
- <hr />
686
- <h2 id="canonical-serialization-format"><strong>6.4 Canonical
687
- serialization format</strong></h2>
688
- <p>The serialized form uses a deterministic canonical encoding that
689
- produces identical bit sequences for structurally identical values,
690
- extended to support lazy evaluation:</p>
691
- <h3 id="canonical-encoding-principles"><strong>6.4.0 Canonical encoding
692
- principles</strong></h3>
693
- <p>The encoding is based on the canonical finite automaton
694
- representation of types (Chapter 3):</p>
695
- <h4 id="fixed-length-union-codes"><strong>Fixed-length union
696
- codes</strong></h4>
697
- <p>For each union state with <em>m</em> variants, we use
698
- <code>k = ceil(log2(m))</code> bits to encode the variant selection:</p>
699
- <table>
700
- <thead>
701
- <tr>
702
- <th>Variants</th>
703
- <th>Bits needed</th>
704
- <th>Example codes</th>
705
- </tr>
706
- </thead>
707
- <tbody>
708
- <tr>
709
- <td>2</td>
710
- <td>1</td>
711
- <td><code>0</code>, <code>1</code></td>
712
- </tr>
713
- <tr>
714
- <td>3</td>
715
- <td>2</td>
716
- <td><code>00</code>, <code>01</code>, <code>10</code></td>
717
- </tr>
718
- <tr>
719
- <td>4</td>
720
- <td>2</td>
721
- <td><code>00</code>, <code>01</code>, <code>10</code>,
722
- <code>11</code></td>
723
- </tr>
724
- <tr>
725
- <td>5-8</td>
726
- <td>3</td>
727
- <td><code>000</code> through <code>111</code></td>
728
- </tr>
729
- </tbody>
730
- </table>
731
- <h4 id="encoding-by-node-type"><strong>Encoding by node
732
- type</strong></h4>
733
- <p>Each node in the value tree is encoded based on its automaton
734
- state:</p>
735
- <ul>
736
- <li><strong>Product nodes</strong> — emit no bits, encode children in
737
- canonical field order (alphabetical)</li>
738
- <li><strong>Union nodes</strong> — emit fixed-length variant code, then
739
- encode the selected child<br />
740
- </li>
741
- <li><strong>Unit nodes</strong> — emit nothing (arity = 0, no
742
- children)</li>
743
- <li><strong>External nodes</strong> — emit type marker + delegate to
744
- external serializer</li>
745
- </ul>
746
- <h4 id="example-natural-numbers"><strong>Example: Natural
747
- numbers</strong></h4>
748
- <p>For type <code>bnat</code>, intuitively binary natural numbers
749
- defined by <code>$bnat = &lt; bnat 0, bnat 1, {} _ &gt;</code>, we
750
- get</p>
751
- <pre class="k-repl"><code>--C bnat
752
- $ @BsAqRMv = &lt; @BsAqRMv 0, @BsAqRMv 1, @KL _ &gt;; -- $C0=&lt;C0&quot;0&quot;,C0&quot;1&quot;,C1&quot;_&quot;&gt; $C1={};</code></pre>
753
- <p>The corresponding Context-Free grammar is:</p>
754
- <pre class="text"><code>// 3 rules for C0, so we need 2 bits to encode the variant choice:
755
- C0 -&gt; C0 &quot;|0&quot; // encoded by &#39;00&#39;
756
- C0 -&gt; C0 &quot;|1&quot; // encoded by &#39;01&#39;
757
- C0 -&gt; C1 &quot;|_&quot; // encoded by &#39;10&#39;
758
- // 1 rule for C1 so we need zero bits:
759
- C1 -&gt; &#39;{}&#39;; // encoded by &#39;&#39;</code></pre>
760
- <ul>
761
- <li>3 variants require <code>ceil(log2(3)) = 2</code> bits</li>
762
- <li>Codes: <code>00</code> (0-bit), <code>01</code> (1-bit),
763
- <code>10</code> (end marker)</li>
764
- </ul>
765
- <p>The value <code>{}|_|0|1</code> or in JSON-like notation
766
- <code>{1:{0:{_:{}}}}</code> (binary 10₂ = decimal 2) encodes as:</p>
767
- <pre class="text"><code>01 00 10</code></pre>
768
- <p>This represents the left-most derivation of <code>{}|_|0|1</code>
769
- from <code>C0</code>.</p>
770
- <h4 id="prefix-free-property"><strong>Prefix-free property</strong></h4>
771
- <p>The encoding is <strong>prefix-free</strong>: no valid encoding is a
772
- prefix of another. This enables:</p>
773
- <ul>
774
- <li>Linear-time parsing without backtracking<br />
775
- </li>
776
- <li>Efficient <code>skip_field()</code> operations for lazy
777
- evaluation</li>
778
- <li>Deterministic decoding from any valid position in the stream</li>
779
- </ul>
780
- <h3 id="dag-compression-for-repeated-subtrees"><strong>6.4.1 DAG
781
- compression for repeated subtrees</strong></h3>
782
- <p>The canonical serialization can be compressed using <strong>DAG
783
- (Directed Acyclic Graph) representation</strong> to eliminate duplicate
784
- subtrees:</p>
785
- <h4 id="subtree-identification"><strong>Subtree
786
- identification</strong></h4>
787
- <p>Each unique subtree is assigned a <strong>node ID</strong> based on
788
- its canonical hash:</p>
789
- <pre class="text"><code>hash(node) = hash(state, tag, arity, hash(child_0), hash(child_1), ...)</code></pre>
790
- <p>Identical subtrees (same structure and content) get the same hash and
791
- share the same node ID.</p>
792
- <h4 id="two-pass-encoding"><strong>Two-pass encoding</strong></h4>
793
- <h5 id="pass-1-collection"><strong>Pass 1: Collection</strong></h5>
794
- <ul>
795
- <li>Traverse the value tree and compute hashes for all subtrees</li>
796
- <li>Build a <strong>node table</strong> mapping
797
- <code>node_id → (first_occurrence_offset, reference_count)</code></li>
798
- <li>Subtrees with <code>reference_count &gt; 1</code> are candidates for
799
- sharing</li>
800
- </ul>
801
- <h5 id="pass-2-emission"><strong>Pass 2: Emission</strong></h5>
802
- <ul>
803
- <li><strong>First occurrence</strong>: emit the full subtree
804
- encoding</li>
805
- <li><strong>Subsequent occurrences</strong>: emit a
806
- <strong>back-reference</strong> to the node ID</li>
807
- </ul>
808
- <h4 id="back-reference-encoding"><strong>Back-reference
809
- encoding</strong></h4>
810
- <pre class="text"><code>| Reference Bit (1) | Node ID (variable length) |</code></pre>
811
- <ul>
812
- <li><code>0</code> bit indicates normal encoding follows</li>
813
- <li><code>1</code> bit indicates back-reference follows</li>
814
- <li>Node ID uses variable-length encoding (e.g., LEB128)</li>
815
- </ul>
816
- <h4 id="example-shared-subtrees"><strong>Example: Shared
817
- subtrees</strong></h4>
818
- <p>Consider a binary tree with repeated leaf patterns:</p>
819
- <pre class="k-lang"><code>$tree = &lt; { tree left, tree right } branch, int leaf &gt;;</code></pre>
820
- <p>Value: A tree corresponding to the structure:
821
- <code>branch( leaf(42), branch( leaf(42), leaf(17) ) )</code>:</p>
822
- <p><strong>Without DAG</strong>: Each leaf <code>(42)</code> is encoded
823
- separately <strong>With DAG</strong>: The <code>(42)</code> subtree is
824
- encoded once, then referenced</p>
825
- <p><strong>Encoding sequence</strong>:</p>
826
- <pre class="text"><code>Node Table:
827
- N0: 42 (appears 2 times)
828
- N1: 17 (appears 1 time)
829
-
830
- Bitstream:
831
- 00 // branch variant
832
- 0 &lt;N0&gt; // first occurrence of value: 42
833
- 00 // branch variant
834
- 1 N0 // back-reference to value: 42
835
- 0 &lt;N1&gt; // {value: 17}</code></pre>
836
- <h3 id="stream-structure"><strong>6.4.2 Stream structure</strong></h3>
837
- <pre class="text"><code>| Header (8 bytes) | Node Count (4 bytes) | Node Table | Bitstream |</code></pre>
838
- <ul>
839
- <li><strong>Header</strong> — type hash identifying the canonical
840
- automaton</li>
841
- <li><strong>Node Count</strong> — number of shared nodes (0 = no DAG
842
- compression)</li>
843
- <li><strong>Node Table</strong> —
844
- <code>[node_id, offset_in_bitstream, size_in_bits]</code> for each
845
- shared node</li>
846
- <li><strong>Bitstream</strong> — concatenated prefix-free codes with
847
- back-references</li>
848
- </ul>
849
- <h4 id="node-table-format"><strong>Node table format</strong></h4>
850
- <p>When DAG compression is used (<code>Node Count &gt; 0</code>):</p>
851
- <pre class="text"><code>For each shared node:
852
- | Node ID (4 bytes) | Offset (4 bytes) | Size in bits (4 bytes) |</code></pre>
853
- <p>This allows the decoder to:</p>
854
- <ol type="1">
855
- <li><strong>Random access</strong>: Jump directly to any shared subtree
856
- definition</li>
857
- <li><strong>Lazy loading</strong>: Resolve back-references only when
858
- needed</li>
859
- <li><strong>Validation</strong>: Verify subtree boundaries during
860
- parsing</li>
861
- </ol>
862
- <h4 id="compression-algorithms"><strong>Compression
863
- algorithms</strong></h4>
864
- <p><strong>Greedy sharing</strong>: Share any subtree that appears more
865
- than once</p>
866
- <ul>
867
- <li>Simple to implement</li>
868
- <li>Good compression for naturally occurring patterns</li>
869
- </ul>
870
- <p><strong>Size-based sharing</strong>: Only share subtrees above a
871
- minimum size threshold</p>
872
- <ul>
873
- <li>Avoids overhead of referencing tiny subtrees</li>
874
- <li>Better compression ratio in practice</li>
875
- </ul>
876
- <p><strong>Frequency-weighted sharing</strong>: Prioritize subtrees by
877
- <code>size × frequency</code></p>
878
- <ul>
879
- <li>Optimal compression for space-constrained scenarios</li>
880
- <li>Requires more sophisticated analysis</li>
881
- </ul>
882
- <h4 id="lazy-back-reference-resolution"><strong>Lazy back-reference
883
- resolution</strong></h4>
884
- <p>Back-references integrate seamlessly with lazy evaluation:</p>
885
- <div class="sourceCode" id="cb37"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a>DecoratedPtr resolve_reference<span class="op">(</span>DecoratedPtr backref<span class="op">)</span> <span class="op">{</span></span>
886
- <span id="cb37-2"><a href="#cb37-2" aria-hidden="true" tabindex="-1"></a> node_id <span class="op">=</span> read_variable_int<span class="op">(</span>backref<span class="op">.</span>bits<span class="op">,</span> backref<span class="op">.</span>bit_offset<span class="op">);</span></span>
887
- <span id="cb37-3"><a href="#cb37-3" aria-hidden="true" tabindex="-1"></a> </span>
888
- <span id="cb37-4"><a href="#cb37-4" aria-hidden="true" tabindex="-1"></a> <span class="co">// Look up in node table</span></span>
889
- <span id="cb37-5"><a href="#cb37-5" aria-hidden="true" tabindex="-1"></a> node_entry <span class="op">=</span> node_table<span class="op">[</span>node_id<span class="op">];</span></span>
890
- <span id="cb37-6"><a href="#cb37-6" aria-hidden="true" tabindex="-1"></a> </span>
891
- <span id="cb37-7"><a href="#cb37-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">(</span>DecoratedPtr<span class="op">)</span> <span class="op">{</span></span>
892
- <span id="cb37-8"><a href="#cb37-8" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>bits <span class="op">=</span> backref<span class="op">.</span>bits<span class="op">,</span></span>
893
- <span id="cb37-9"><a href="#cb37-9" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>bit_offset <span class="op">=</span> node_entry<span class="op">.</span>offset<span class="op">,</span></span>
894
- <span id="cb37-10"><a href="#cb37-10" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>type_state <span class="op">=</span> node_entry<span class="op">.</span>type_state<span class="op">,</span></span>
895
- <span id="cb37-11"><a href="#cb37-11" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>ref_count <span class="op">=</span> <span class="dv">1</span></span>
896
- <span id="cb37-12"><a href="#cb37-12" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
897
- <span id="cb37-13"><a href="#cb37-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
898
- <p>The decorated pointer model naturally handles back-references as
899
- lightweight pointer redirections.</p>
900
- <h4 id="memory-vs.-compression-trade-offs"><strong>Memory
901
- vs. compression trade-offs</strong></h4>
902
- <table>
903
- <thead>
904
- <tr>
905
- <th>Strategy</th>
906
- <th>Memory usage</th>
907
- <th>Compression ratio</th>
908
- <th>Decode speed</th>
909
- </tr>
910
- </thead>
911
- <tbody>
912
- <tr>
913
- <td>No DAG</td>
914
- <td>Low</td>
915
- <td>1.0× (baseline)</td>
916
- <td>Fastest</td>
917
- </tr>
918
- <tr>
919
- <td>Greedy DAG</td>
920
- <td>Medium</td>
921
- <td>2-10×</td>
922
- <td>Fast</td>
923
- </tr>
924
- <tr>
925
- <td>Optimal DAG</td>
926
- <td>High</td>
927
- <td>5-50×</td>
928
- <td>Medium</td>
929
- </tr>
930
- </tbody>
931
- </table>
932
- <p>For <strong>streaming applications</strong>: Prefer greedy DAG with
933
- small node tables For <strong>archival storage</strong>: Use optimal DAG
934
- compression For <strong>real-time processing</strong>: Skip DAG
935
- compression entirely</p>
936
- <h4
937
- id="compression-example-repeated-data-structures"><strong>Compression
938
- example: Repeated data structures</strong></h4>
939
- <p>Consider a list of similar records:</p>
940
- <pre class="k-lang"><code>$record = { string name, int age, string department };
941
- $company = &lt; { record head, company tail } cons, {} nil &gt;;</code></pre>
942
- <p>Value representing 1000 employees where 80% work in
943
- “Engineering”:</p>
944
- <pre class="text"><code>Without DAG: Each &quot;Engineering&quot; string encoded separately
945
- - 1000 records × 30 bytes/record = 30KB
946
-
947
- With DAG: &quot;Engineering&quot; string shared via back-references
948
- - 1 × &quot;Engineering&quot; (11 bytes) + 800 × back-reference (3 bytes) = 2.4KB
949
- - Compression ratio: ~12.5×</code></pre>
950
- <p>The DAG representation transforms the <strong>tree</strong> into a
951
- more efficient <strong>directed acyclic graph</strong>:</p>
952
- <pre class="text"><code>Tree: Record1 → &quot;Engineering&quot;
953
- Record2 → &quot;Engineering&quot;
954
- Record3 → &quot;Engineering&quot;
955
- ...
956
-
957
- DAG: Record1 ↘
958
- Record2 → Shared(&quot;Engineering&quot;)
959
- Record3 ↗
960
- ...</code></pre>
961
- <h3 id="hardware-optimized-encoding"><strong>6.4.3 Hardware-optimized
962
- encoding</strong></h3>
963
- <p>While bit-level precision is theoretically optimal, modern hardware
964
- operates on <strong>byte-aligned data</strong> using <strong>word-sized
965
- registers</strong>. A practical encoding must balance compression with
966
- decode performance.</p>
967
- <h4 id="register-friendly-union-encoding"><strong>Register-friendly
968
- union encoding</strong></h4>
969
- <p>Instead of <code>ceil(log2(m))</code> bits, use <strong>byte-aligned
970
- codes</strong> optimized for common union sizes:</p>
971
- <table>
972
- <thead>
973
- <tr>
974
- <th>Union variants</th>
975
- <th>Theoretical bits</th>
976
- <th>Hardware-optimized</th>
977
- </tr>
978
- </thead>
979
- <tbody>
980
- <tr>
981
- <td>2-3 variants</td>
982
- <td>1-2 bits</td>
983
- <td>1 byte (8 bits)</td>
984
- </tr>
985
- <tr>
986
- <td>4-15 variants</td>
987
- <td>2-4 bits</td>
988
- <td>1 byte (8 bits)</td>
989
- </tr>
990
- <tr>
991
- <td>16-255 variants</td>
992
- <td>4-8 bits</td>
993
- <td>1 byte (8 bits)</td>
994
- </tr>
995
- <tr>
996
- <td>256+ variants</td>
997
- <td>8+ bits</td>
998
- <td>2+ bytes (LEB128)</td>
999
- </tr>
1000
- </tbody>
1001
- </table>
1002
- <p><strong>Rationale</strong>: Single-byte discriminators enable
1003
- efficient decoding with simple memory loads and bit masking.</p>
1004
- <h4 id="simd-friendly-data-layout"><strong>SIMD-friendly data
1005
- layout</strong></h4>
1006
- <p>Modern CPUs can process multiple bytes simultaneously using
1007
- <strong>SIMD instructions</strong>. Structure the encoding to leverage
1008
- this:</p>
1009
- <div class="sourceCode" id="cb41"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Bad: bit-packed discriminators</span></span>
1010
- <span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> BitPacked <span class="op">{</span></span>
1011
- <span id="cb41-3"><a href="#cb41-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint64_t</span> discriminators<span class="op">;</span> <span class="co">// 8 × 8-bit = 64 discriminators packed</span></span>
1012
- <span id="cb41-4"><a href="#cb41-4" aria-hidden="true" tabindex="-1"></a> <span class="co">// Requires expensive bit extraction</span></span>
1013
- <span id="cb41-5"><a href="#cb41-5" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
1014
- <span id="cb41-6"><a href="#cb41-6" aria-hidden="true" tabindex="-1"></a></span>
1015
- <span id="cb41-7"><a href="#cb41-7" aria-hidden="true" tabindex="-1"></a><span class="co">// Good: byte-aligned discriminators </span></span>
1016
- <span id="cb41-8"><a href="#cb41-8" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> ByteAligned <span class="op">{</span></span>
1017
- <span id="cb41-9"><a href="#cb41-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> discriminators<span class="op">[</span><span class="dv">8</span><span class="op">];</span> <span class="co">// 8 discriminators, SIMD-friendly</span></span>
1018
- <span id="cb41-10"><a href="#cb41-10" aria-hidden="true" tabindex="-1"></a> <span class="co">// Can be processed with single AVX2 instruction</span></span>
1019
- <span id="cb41-11"><a href="#cb41-11" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
1020
- <h4 id="cache-line-aware-field-ordering"><strong>Cache-line aware field
1021
- ordering</strong></h4>
1022
- <p>Arrange product fields to minimize <strong>cache misses</strong>:</p>
1023
- <div class="sourceCode" id="cb42"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb42-1"><a href="#cb42-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Product field layout optimization</span></span>
1024
- <span id="cb42-2"><a href="#cb42-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> ProductLayout <span class="op">{</span></span>
1025
- <span id="cb42-3"><a href="#cb42-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> discriminators<span class="op">[</span>N<span class="op">];</span> <span class="co">// All discriminators together (hot data)</span></span>
1026
- <span id="cb42-4"><a href="#cb42-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> padding<span class="op">[</span><span class="dv">64</span> <span class="op">-</span> N <span class="op">%</span> <span class="dv">64</span><span class="op">];</span> <span class="co">// Align to cache line boundary</span></span>
1027
- <span id="cb42-5"><a href="#cb42-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> field_data<span class="op">[];</span> <span class="co">// Field data follows (cold data)</span></span>
1028
- <span id="cb42-6"><a href="#cb42-6" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
1029
- <p>Fields are ordered by <strong>access frequency</strong> rather than
1030
- alphabetical order:</p>
1031
- <ul>
1032
- <li><strong>Hot fields</strong> (frequently accessed): placed
1033
- first<br />
1034
- </li>
1035
- <li><strong>Cold fields</strong> (rarely accessed): placed last</li>
1036
- <li><strong>Large fields</strong> (arrays, strings): placed at end to
1037
- avoid cache pollution</li>
1038
- </ul>
1039
- <h4 id="word-aligned-pointer-arithmetic"><strong>Word-aligned pointer
1040
- arithmetic</strong></h4>
1041
- <p>Replace bit-level navigation with <strong>word-aligned
1042
- operations</strong>:</p>
1043
- <div class="sourceCode" id="cb43"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb43-1"><a href="#cb43-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Bit-level navigation (slow)</span></span>
1044
- <span id="cb43-2"><a href="#cb43-2" aria-hidden="true" tabindex="-1"></a>DecoratedPtr navigate_bitwise<span class="op">(</span>DecoratedPtr ptr<span class="op">,</span> <span class="dt">int</span> field_index<span class="op">)</span> <span class="op">{</span></span>
1045
- <span id="cb43-3"><a href="#cb43-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">size_t</span> bit_offset <span class="op">=</span> ptr<span class="op">.</span>bit_offset<span class="op">;</span></span>
1046
- <span id="cb43-4"><a href="#cb43-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op">&lt;</span> field_index<span class="op">;</span> i<span class="op">++)</span> <span class="op">{</span></span>
1047
- <span id="cb43-5"><a href="#cb43-5" aria-hidden="true" tabindex="-1"></a> bit_offset <span class="op">+=</span> extract_field_bit_size<span class="op">(</span>ptr<span class="op">.</span>bits<span class="op">,</span> bit_offset<span class="op">);</span> <span class="co">// Expensive!</span></span>
1048
- <span id="cb43-6"><a href="#cb43-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
1049
- <span id="cb43-7"><a href="#cb43-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_ptr<span class="op">(</span>ptr<span class="op">.</span>bits<span class="op">,</span> bit_offset<span class="op">);</span></span>
1050
- <span id="cb43-8"><a href="#cb43-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
1051
- <span id="cb43-9"><a href="#cb43-9" aria-hidden="true" tabindex="-1"></a></span>
1052
- <span id="cb43-10"><a href="#cb43-10" aria-hidden="true" tabindex="-1"></a><span class="co">// Word-aligned navigation (fast)</span></span>
1053
- <span id="cb43-11"><a href="#cb43-11" aria-hidden="true" tabindex="-1"></a>DecoratedPtr navigate_wordwise<span class="op">(</span>DecoratedPtr ptr<span class="op">,</span> <span class="dt">int</span> field_index<span class="op">)</span> <span class="op">{</span></span>
1054
- <span id="cb43-12"><a href="#cb43-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> byte_ptr <span class="op">=</span> ptr<span class="op">.</span>bits <span class="op">+</span> <span class="op">(</span>ptr<span class="op">.</span>bit_offset <span class="op">&gt;&gt;</span> <span class="dv">3</span><span class="op">);</span> <span class="co">// Convert to byte offset</span></span>
1055
- <span id="cb43-13"><a href="#cb43-13" aria-hidden="true" tabindex="-1"></a> </span>
1056
- <span id="cb43-14"><a href="#cb43-14" aria-hidden="true" tabindex="-1"></a> <span class="co">// Read field offset table (precomputed during encoding)</span></span>
1057
- <span id="cb43-15"><a href="#cb43-15" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span><span class="op">*</span> offset_table <span class="op">=</span> <span class="op">(</span><span class="dt">uint32_t</span><span class="op">*)</span>byte_ptr<span class="op">;</span></span>
1058
- <span id="cb43-16"><a href="#cb43-16" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span> field_offset <span class="op">=</span> offset_table<span class="op">[</span>field_index<span class="op">];</span> <span class="co">// Single memory load</span></span>
1059
- <span id="cb43-17"><a href="#cb43-17" aria-hidden="true" tabindex="-1"></a> </span>
1060
- <span id="cb43-18"><a href="#cb43-18" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_ptr<span class="op">(</span>ptr<span class="op">.</span>bits<span class="op">,</span> field_offset <span class="op">&lt;&lt;</span> <span class="dv">3</span><span class="op">);</span> <span class="co">// Convert back to bits</span></span>
1061
- <span id="cb43-19"><a href="#cb43-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
1062
- <h4 id="cpu-instruction-optimization"><strong>CPU instruction
1063
- optimization</strong></h4>
1064
- <p><strong>Branch prediction friendly encoding</strong>:</p>
1065
- <div class="sourceCode" id="cb44"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb44-1"><a href="#cb44-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Bad: unpredictable branching</span></span>
1066
- <span id="cb44-2"><a href="#cb44-2" aria-hidden="true" tabindex="-1"></a><span class="dt">uint8_t</span> discriminator <span class="op">=</span> <span class="op">*</span>byte_ptr<span class="op">++;</span></span>
1067
- <span id="cb44-3"><a href="#cb44-3" aria-hidden="true" tabindex="-1"></a><span class="cf">switch</span> <span class="op">(</span>discriminator<span class="op">)</span> <span class="op">{</span></span>
1068
- <span id="cb44-4"><a href="#cb44-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="dv">0</span><span class="op">:</span> handle_variant_0<span class="op">();</span> <span class="cf">break</span><span class="op">;</span></span>
1069
- <span id="cb44-5"><a href="#cb44-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="dv">1</span><span class="op">:</span> handle_variant_1<span class="op">();</span> <span class="cf">break</span><span class="op">;</span></span>
1070
- <span id="cb44-6"><a href="#cb44-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="dv">2</span><span class="op">:</span> handle_variant_2<span class="op">();</span> <span class="cf">break</span><span class="op">;</span></span>
1071
- <span id="cb44-7"><a href="#cb44-7" aria-hidden="true" tabindex="-1"></a> <span class="co">// ... many cases cause branch misprediction</span></span>
1072
- <span id="cb44-8"><a href="#cb44-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
1073
- <span id="cb44-9"><a href="#cb44-9" aria-hidden="true" tabindex="-1"></a></span>
1074
- <span id="cb44-10"><a href="#cb44-10" aria-hidden="true" tabindex="-1"></a><span class="co">// Good: function table dispatch</span></span>
1075
- <span id="cb44-11"><a href="#cb44-11" aria-hidden="true" tabindex="-1"></a><span class="kw">typedef</span> <span class="dt">void</span> <span class="op">(*</span>VariantHandler<span class="op">)(</span><span class="dt">uint8_t</span><span class="op">*</span> data<span class="op">);</span></span>
1076
- <span id="cb44-12"><a href="#cb44-12" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> VariantHandler variant_handlers<span class="op">[</span><span class="dv">256</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span></span>
1077
- <span id="cb44-13"><a href="#cb44-13" aria-hidden="true" tabindex="-1"></a> handle_variant_0<span class="op">,</span> handle_variant_1<span class="op">,</span> handle_variant_2<span class="op">,</span> <span class="co">/* ... */</span></span>
1078
- <span id="cb44-14"><a href="#cb44-14" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
1079
- <span id="cb44-15"><a href="#cb44-15" aria-hidden="true" tabindex="-1"></a></span>
1080
- <span id="cb44-16"><a href="#cb44-16" aria-hidden="true" tabindex="-1"></a><span class="dt">uint8_t</span> discriminator <span class="op">=</span> <span class="op">*</span>byte_ptr<span class="op">++;</span></span>
1081
- <span id="cb44-17"><a href="#cb44-17" aria-hidden="true" tabindex="-1"></a>variant_handlers<span class="op">[</span>discriminator<span class="op">](</span>byte_ptr<span class="op">);</span> <span class="co">// Single indirect call</span></span></code></pre></div>
1082
- <p><strong>Prefetch-aware access patterns</strong>:</p>
1083
- <div class="sourceCode" id="cb45"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb45-1"><a href="#cb45-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Sequential prefetching for product fields</span></span>
1084
- <span id="cb45-2"><a href="#cb45-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> prefetch_product_fields<span class="op">(</span>DecoratedPtr ptr<span class="op">,</span> <span class="dt">int</span> num_fields<span class="op">)</span> <span class="op">{</span></span>
1085
- <span id="cb45-3"><a href="#cb45-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span><span class="op">*</span> offset_table <span class="op">=</span> <span class="op">(</span><span class="dt">uint32_t</span><span class="op">*)(</span>ptr<span class="op">.</span>bits <span class="op">+</span> <span class="op">(</span>ptr<span class="op">.</span>bit_offset <span class="op">&gt;&gt;</span> <span class="dv">3</span><span class="op">));</span></span>
1086
- <span id="cb45-4"><a href="#cb45-4" aria-hidden="true" tabindex="-1"></a> </span>
1087
- <span id="cb45-5"><a href="#cb45-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// Prefetch offset table into L1 cache</span></span>
1088
- <span id="cb45-6"><a href="#cb45-6" aria-hidden="true" tabindex="-1"></a> __builtin_prefetch<span class="op">(</span>offset_table<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">3</span><span class="op">);</span> <span class="co">// Read, high temporal locality</span></span>
1089
- <span id="cb45-7"><a href="#cb45-7" aria-hidden="true" tabindex="-1"></a> </span>
1090
- <span id="cb45-8"><a href="#cb45-8" aria-hidden="true" tabindex="-1"></a> <span class="co">// Prefetch first few fields</span></span>
1091
- <span id="cb45-9"><a href="#cb45-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op">&lt;</span> min<span class="op">(</span>num_fields<span class="op">,</span> <span class="dv">4</span><span class="op">);</span> i<span class="op">++)</span> <span class="op">{</span></span>
1092
- <span id="cb45-10"><a href="#cb45-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> field_ptr <span class="op">=</span> ptr<span class="op">.</span>bits <span class="op">+</span> offset_table<span class="op">[</span>i<span class="op">];</span></span>
1093
- <span id="cb45-11"><a href="#cb45-11" aria-hidden="true" tabindex="-1"></a> __builtin_prefetch<span class="op">(</span>field_ptr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">2</span><span class="op">);</span> <span class="co">// Read, medium temporal locality</span></span>
1094
- <span id="cb45-12"><a href="#cb45-12" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
1095
- <span id="cb45-13"><a href="#cb45-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
1096
- <h4 id="memory-bandwidth-optimization"><strong>Memory bandwidth
1097
- optimization</strong></h4>
1098
- <p><strong>Streaming-friendly encoding</strong>:</p>
1099
- <div class="sourceCode" id="cb46"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb46-1"><a href="#cb46-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Structure data for optimal memory bandwidth</span></span>
1100
- <span id="cb46-2"><a href="#cb46-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> StreamLayout <span class="op">{</span></span>
1101
- <span id="cb46-3"><a href="#cb46-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> <span class="op">{</span></span>
1102
- <span id="cb46-4"><a href="#cb46-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span> total_size<span class="op">;</span> <span class="co">// 4 bytes</span></span>
1103
- <span id="cb46-5"><a href="#cb46-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint16_t</span> num_fields<span class="op">;</span> <span class="co">// 2 bytes </span></span>
1104
- <span id="cb46-6"><a href="#cb46-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint16_t</span> flags<span class="op">;</span> <span class="co">// 2 bytes (padding + metadata)</span></span>
1105
- <span id="cb46-7"><a href="#cb46-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> header<span class="op">;</span> <span class="co">// 8 bytes total (fits in single cache line)</span></span>
1106
- <span id="cb46-8"><a href="#cb46-8" aria-hidden="true" tabindex="-1"></a> </span>
1107
- <span id="cb46-9"><a href="#cb46-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span> field_offsets<span class="op">[];</span> <span class="co">// 4N bytes (word-aligned)</span></span>
1108
- <span id="cb46-10"><a href="#cb46-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> field_data<span class="op">[];</span> <span class="co">// Variable length data</span></span>
1109
- <span id="cb46-11"><a href="#cb46-11" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
1110
- <p><strong>Memory access patterns</strong>:</p>
1111
- <ul>
1112
- <li><strong>Sequential reads</strong>: Optimal for streaming
1113
- workloads</li>
1114
- <li><strong>Random access</strong>: Offset table enables O(1) field
1115
- access</li>
1116
- <li><strong>Bulk operations</strong>: SIMD can process multiple
1117
- discriminators simultaneously</li>
1118
- </ul>
1119
- <h4 id="hardware-specific-optimizations"><strong>Hardware-specific
1120
- optimizations</strong></h4>
1121
- <p><strong>x86-64 optimizations</strong>:</p>
1122
- <div class="sourceCode" id="cb47"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb47-1"><a href="#cb47-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Exploit x86-64 addressing modes</span></span>
1123
- <span id="cb47-2"><a href="#cb47-2" aria-hidden="true" tabindex="-1"></a>DecoratedPtr navigate_x86<span class="op">(</span>DecoratedPtr ptr<span class="op">,</span> <span class="dt">int</span> field_index<span class="op">)</span> <span class="op">{</span></span>
1124
- <span id="cb47-3"><a href="#cb47-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span><span class="op">*</span> offset_table <span class="op">=</span> <span class="op">(</span><span class="dt">uint32_t</span><span class="op">*)(</span>ptr<span class="op">.</span>bits <span class="op">+</span> <span class="op">(</span>ptr<span class="op">.</span>bit_offset <span class="op">&gt;&gt;</span> <span class="dv">3</span><span class="op">));</span></span>
1125
- <span id="cb47-4"><a href="#cb47-4" aria-hidden="true" tabindex="-1"></a> </span>
1126
- <span id="cb47-5"><a href="#cb47-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// Single instruction: LEA + memory operand</span></span>
1127
- <span id="cb47-6"><a href="#cb47-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> field_ptr <span class="op">=</span> ptr<span class="op">.</span>bits <span class="op">+</span> offset_table<span class="op">[</span>field_index<span class="op">];</span></span>
1128
- <span id="cb47-7"><a href="#cb47-7" aria-hidden="true" tabindex="-1"></a> </span>
1129
- <span id="cb47-8"><a href="#cb47-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_ptr_from_bytes<span class="op">(</span>field_ptr<span class="op">);</span></span>
1130
- <span id="cb47-9"><a href="#cb47-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
1131
- <span id="cb47-10"><a href="#cb47-10" aria-hidden="true" tabindex="-1"></a></span>
1132
- <span id="cb47-11"><a href="#cb47-11" aria-hidden="true" tabindex="-1"></a><span class="co">// Utilize SIMD for bulk discriminator reading</span></span>
1133
- <span id="cb47-12"><a href="#cb47-12" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> decode_discriminators_avx2<span class="op">(</span><span class="dt">uint8_t</span><span class="op">*</span> input<span class="op">,</span> <span class="dt">uint8_t</span><span class="op">*</span> output<span class="op">,</span> <span class="dt">size_t</span> count<span class="op">)</span> <span class="op">{</span></span>
1134
- <span id="cb47-13"><a href="#cb47-13" aria-hidden="true" tabindex="-1"></a> __m256i<span class="op">*</span> input_vec <span class="op">=</span> <span class="op">(</span>__m256i<span class="op">*)</span>input<span class="op">;</span></span>
1135
- <span id="cb47-14"><a href="#cb47-14" aria-hidden="true" tabindex="-1"></a> __m256i<span class="op">*</span> output_vec <span class="op">=</span> <span class="op">(</span>__m256i<span class="op">*)</span>output<span class="op">;</span></span>
1136
- <span id="cb47-15"><a href="#cb47-15" aria-hidden="true" tabindex="-1"></a> </span>
1137
- <span id="cb47-16"><a href="#cb47-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">size_t</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op">&lt;</span> count <span class="op">/</span> <span class="dv">32</span><span class="op">;</span> i<span class="op">++)</span> <span class="op">{</span></span>
1138
- <span id="cb47-17"><a href="#cb47-17" aria-hidden="true" tabindex="-1"></a> __m256i data <span class="op">=</span> _mm256_load_si256<span class="op">(&amp;</span>input_vec<span class="op">[</span>i<span class="op">]);</span></span>
1139
- <span id="cb47-18"><a href="#cb47-18" aria-hidden="true" tabindex="-1"></a> </span>
1140
- <span id="cb47-19"><a href="#cb47-19" aria-hidden="true" tabindex="-1"></a> <span class="co">// Process 32 discriminators in parallel</span></span>
1141
- <span id="cb47-20"><a href="#cb47-20" aria-hidden="true" tabindex="-1"></a> __m256i decoded <span class="op">=</span> _mm256_and_si256<span class="op">(</span>data<span class="op">,</span> _mm256_set1_epi8<span class="op">(</span><span class="bn">0x0F</span><span class="op">));</span></span>
1142
- <span id="cb47-21"><a href="#cb47-21" aria-hidden="true" tabindex="-1"></a> </span>
1143
- <span id="cb47-22"><a href="#cb47-22" aria-hidden="true" tabindex="-1"></a> _mm256_store_si256<span class="op">(&amp;</span>output_vec<span class="op">[</span>i<span class="op">],</span> decoded<span class="op">);</span></span>
1144
- <span id="cb47-23"><a href="#cb47-23" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
1145
- <span id="cb47-24"><a href="#cb47-24" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
1146
- <p><strong>ARM64 optimizations</strong>:</p>
1147
- <div class="sourceCode" id="cb48"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb48-1"><a href="#cb48-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Exploit ARM64 load-with-offset instructions</span></span>
1148
- <span id="cb48-2"><a href="#cb48-2" aria-hidden="true" tabindex="-1"></a>DecoratedPtr navigate_arm64<span class="op">(</span>DecoratedPtr ptr<span class="op">,</span> <span class="dt">int</span> field_index<span class="op">)</span> <span class="op">{</span></span>
1149
- <span id="cb48-3"><a href="#cb48-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span><span class="op">*</span> offset_table <span class="op">=</span> <span class="op">(</span><span class="dt">uint32_t</span><span class="op">*)(</span>ptr<span class="op">.</span>bits <span class="op">+</span> <span class="op">(</span>ptr<span class="op">.</span>bit_offset <span class="op">&gt;&gt;</span> <span class="dv">3</span><span class="op">));</span></span>
1150
- <span id="cb48-4"><a href="#cb48-4" aria-hidden="true" tabindex="-1"></a> </span>
1151
- <span id="cb48-5"><a href="#cb48-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// ARM64: single LDR instruction with register offset</span></span>
1152
- <span id="cb48-6"><a href="#cb48-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span> offset <span class="op">=</span> offset_table<span class="op">[</span>field_index<span class="op">];</span></span>
1153
- <span id="cb48-7"><a href="#cb48-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> field_ptr <span class="op">=</span> ptr<span class="op">.</span>bits <span class="op">+</span> offset<span class="op">;</span></span>
1154
- <span id="cb48-8"><a href="#cb48-8" aria-hidden="true" tabindex="-1"></a> </span>
1155
- <span id="cb48-9"><a href="#cb48-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_ptr_from_bytes<span class="op">(</span>field_ptr<span class="op">);</span></span>
1156
- <span id="cb48-10"><a href="#cb48-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
1157
- <h4
1158
- id="performance-analysis-hardware-vs.-theoretical-encoding"><strong>Performance
1159
- analysis: Hardware vs. theoretical encoding</strong></h4>
1160
- <p><strong>Decoding performance comparison</strong> (cycles per field
1161
- access):</p>
1162
- <table>
1163
- <colgroup>
1164
- <col style="width: 27%" />
1165
- <col style="width: 27%" />
1166
- <col style="width: 23%" />
1167
- <col style="width: 20%" />
1168
- </colgroup>
1169
- <thead>
1170
- <tr>
1171
- <th>Encoding strategy</th>
1172
- <th>Field access cost</th>
1173
- <th>Cache behavior</th>
1174
- <th>SIMD support</th>
1175
- </tr>
1176
- </thead>
1177
- <tbody>
1178
- <tr>
1179
- <td>Bit-packed optimal</td>
1180
- <td>50-100 cycles</td>
1181
- <td>Poor (bit manipulation)</td>
1182
- <td>No</td>
1183
- </tr>
1184
- <tr>
1185
- <td>Byte-aligned</td>
1186
- <td>5-15 cycles</td>
1187
- <td>Good (word loads)</td>
1188
- <td>Yes</td>
1189
- </tr>
1190
- <tr>
1191
- <td>Word-aligned + offset table</td>
1192
- <td>2-8 cycles</td>
1193
- <td>Excellent (prefetchable)</td>
1194
- <td>Yes</td>
1195
- </tr>
1196
- </tbody>
1197
- </table>
1198
- <p><strong>Space vs. time trade-offs</strong>:</p>
1199
- <pre><code>Bit-packed: 100% space efficiency, 10× decode overhead
1200
- Byte-aligned: 90% space efficiency, 2× decode overhead
1201
- Word-aligned: 80% space efficiency, 1× decode overhead (baseline)</code></pre>
1202
- <p><strong>Real-world measurements</strong> (modern x86-64, 3.2GHz):</p>
1203
- <div class="sourceCode" id="cb50"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb50-1"><a href="#cb50-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Benchmark: Navigate to field in 1000-field product</span></span>
1204
- <span id="cb50-2"><a href="#cb50-2" aria-hidden="true" tabindex="-1"></a>Bit<span class="op">-</span>manipulation<span class="op">:</span> <span class="dv">2</span><span class="op">,</span><span class="dv">400</span> ns <span class="op">(</span><span class="dv">7</span><span class="op">,</span><span class="dv">680</span> cycles<span class="op">)</span></span>
1205
- <span id="cb50-3"><a href="#cb50-3" aria-hidden="true" tabindex="-1"></a>Byte<span class="op">-</span>aligned<span class="op">:</span> <span class="dv">480</span> ns <span class="op">(</span><span class="dv">1</span><span class="op">,</span><span class="dv">536</span> cycles<span class="op">)</span> </span>
1206
- <span id="cb50-4"><a href="#cb50-4" aria-hidden="true" tabindex="-1"></a>Word<span class="op">-</span>aligned table<span class="op">:</span> <span class="dv">160</span> ns <span class="op">(</span><span class="dv">512</span> cycles<span class="op">)</span></span></code></pre></div>
1207
- <p>The <strong>offset table approach</strong> provides the best
1208
- practical performance despite modest space overhead.</p>
1209
- <h4 id="recommended-encoding-strategy"><strong>Recommended encoding
1210
- strategy</strong></h4>
1211
- <p><strong>Hybrid approach</strong> balancing theory and practice:</p>
1212
- <ol type="1">
1213
- <li><strong>Small products</strong> (≤8 fields): Byte-aligned, no offset
1214
- table</li>
1215
- <li><strong>Medium products</strong> (9-64 fields): Word-aligned with
1216
- offset table</li>
1217
- <li><strong>Large products</strong> (65+ fields): Hierarchical offset
1218
- tables + prefetching</li>
1219
- <li><strong>Unions</strong>: Single byte discriminator (sufficient for
1220
- 99.9% of real types)</li>
1221
- </ol>
1222
- <p><strong>Encoding format</strong>:</p>
1223
- <div class="sourceCode" id="cb51"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb51-1"><a href="#cb51-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> OptimalEncoding <span class="op">{</span></span>
1224
- <span id="cb51-2"><a href="#cb51-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> type_tag<span class="op">;</span> <span class="co">// 1 byte: product/union/external marker</span></span>
1225
- <span id="cb51-3"><a href="#cb51-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> arity<span class="op">;</span> <span class="co">// 1 byte: number of children (0-255)</span></span>
1226
- <span id="cb51-4"><a href="#cb51-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint16_t</span> flags<span class="op">;</span> <span class="co">// 2 bytes: compression flags, alignment info</span></span>
1227
- <span id="cb51-5"><a href="#cb51-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span> total_size<span class="op">;</span> <span class="co">// 4 bytes: total size for skipping</span></span>
1228
- <span id="cb51-6"><a href="#cb51-6" aria-hidden="true" tabindex="-1"></a> </span>
1229
- <span id="cb51-7"><a href="#cb51-7" aria-hidden="true" tabindex="-1"></a> <span class="co">// For products with &gt;8 fields:</span></span>
1230
- <span id="cb51-8"><a href="#cb51-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span> field_offsets<span class="op">[</span>arity<span class="op">];</span> <span class="co">// 4×N bytes: random access table</span></span>
1231
- <span id="cb51-9"><a href="#cb51-9" aria-hidden="true" tabindex="-1"></a> </span>
1232
- <span id="cb51-10"><a href="#cb51-10" aria-hidden="true" tabindex="-1"></a> <span class="co">// Payload data follows</span></span>
1233
- <span id="cb51-11"><a href="#cb51-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> data<span class="op">[];</span></span>
1234
- <span id="cb51-12"><a href="#cb51-12" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
1235
- <p><strong>Benefits</strong>:</p>
1236
- <ul>
1237
- <li><strong>8-byte aligned</strong> structures for optimal memory
1238
- access</li>
1239
- <li><strong>Single cache line</strong> headers for small products<br />
1240
- </li>
1241
- <li><strong>SIMD-friendly</strong> data layout</li>
1242
- <li><strong>Prefetch-optimized</strong> for large structures</li>
1243
- <li><strong>Hardware-agnostic</strong> but optimized for common
1244
- architectures</li>
1245
- </ul>
1246
- <h3 id="external-type-integration"><strong>6.4.4 External type
1247
- integration</strong></h3>
1248
- <pre class="text"><code>| External Marker (2 bits) | Type ID | External Data Length | External Data |</code></pre>
1249
- <p>This allows built-in types (strings, floats, etc.) to be efficiently
1250
- serialized within <code>k</code> values while maintaining the canonical
1251
- property.</p>
1252
- <hr />
1253
- <h2 id="demand-driven-deserialization"><strong>6.5 Demand-driven
1254
- deserialization</strong></h2>
1255
- <p>Operations on values trigger selective deserialization:</p>
1256
- <h3 id="access-patterns"><strong>6.5.1 Access patterns</strong></h3>
1257
- <ul>
1258
- <li><strong>Identity operation <code>()</code></strong> — no
1259
- deserialization, direct bitstream copy</li>
1260
- <li><strong>Field access <code>.field</code></strong> — deserialize only
1261
- the path to the requested field</li>
1262
- <li><strong>Pattern matching</strong> — deserialize only the
1263
- discriminator, then the matched branch</li>
1264
- <li><strong>Full evaluation</strong> — progressive deserialization as
1265
- computation proceeds</li>
1266
- </ul>
1267
- <h3 id="lazy-evaluation-strategy"><strong>6.5.2 Lazy evaluation
1268
- strategy</strong></h3>
1269
- <div class="sourceCode" id="cb53"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb53-1"><a href="#cb53-1" aria-hidden="true" tabindex="-1"></a>function access_field<span class="op">(</span>value<span class="op">:</span> KValue<span class="op">,</span> field_path<span class="op">:</span> String<span class="op">[]):</span> KValue <span class="op">{</span></span>
1270
- <span id="cb53-2"><a href="#cb53-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>value<span class="op">.</span>form <span class="op">==</span> SERIALIZED<span class="op">)</span> <span class="op">{</span></span>
1271
- <span id="cb53-3"><a href="#cb53-3" aria-hidden="true" tabindex="-1"></a> <span class="co">// Partially deserialize to reach the field</span></span>
1272
- <span id="cb53-4"><a href="#cb53-4" aria-hidden="true" tabindex="-1"></a> root <span class="op">=</span> deserialize_to_depth<span class="op">(</span>value<span class="op">,</span> field_path<span class="op">.</span>length<span class="op">);</span></span>
1273
- <span id="cb53-5"><a href="#cb53-5" aria-hidden="true" tabindex="-1"></a> value <span class="op">=</span> make_lazy<span class="op">(</span>root<span class="op">,</span> value<span class="op">.</span>serialized<span class="op">.</span>bits<span class="op">);</span></span>
1274
- <span id="cb53-6"><a href="#cb53-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
1275
- <span id="cb53-7"><a href="#cb53-7" aria-hidden="true" tabindex="-1"></a> </span>
1276
- <span id="cb53-8"><a href="#cb53-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>value<span class="op">.</span>form <span class="op">==</span> LAZY<span class="op">)</span> <span class="op">{</span></span>
1277
- <span id="cb53-9"><a href="#cb53-9" aria-hidden="true" tabindex="-1"></a> node <span class="op">=</span> navigate_path<span class="op">(</span>value<span class="op">.</span>lazy<span class="op">.</span>root<span class="op">,</span> field_path<span class="op">);</span></span>
1278
- <span id="cb53-10"><a href="#cb53-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>node<span class="op">.</span>child<span class="op">[</span>field_idx<span class="op">].</span>state <span class="op">==</span> SERIALIZED_CHILD<span class="op">)</span> <span class="op">{</span></span>
1279
- <span id="cb53-11"><a href="#cb53-11" aria-hidden="true" tabindex="-1"></a> <span class="co">// Deserialize this child on demand</span></span>
1280
- <span id="cb53-12"><a href="#cb53-12" aria-hidden="true" tabindex="-1"></a> child_value <span class="op">=</span> deserialize_child<span class="op">(</span>node<span class="op">,</span> field_idx<span class="op">);</span></span>
1281
- <span id="cb53-13"><a href="#cb53-13" aria-hidden="true" tabindex="-1"></a> node<span class="op">.</span>child<span class="op">[</span>field_idx<span class="op">].</span>state <span class="op">=</span> MATERIALIZED_CHILD<span class="op">;</span></span>
1282
- <span id="cb53-14"><a href="#cb53-14" aria-hidden="true" tabindex="-1"></a> node<span class="op">.</span>child<span class="op">[</span>field_idx<span class="op">].</span>node <span class="op">=</span> child_value<span class="op">;</span></span>
1283
- <span id="cb53-15"><a href="#cb53-15" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
1284
- <span id="cb53-16"><a href="#cb53-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">&amp;</span>node<span class="op">.</span>child<span class="op">[</span>field_idx<span class="op">];</span></span>
1285
- <span id="cb53-17"><a href="#cb53-17" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
1286
- <span id="cb53-18"><a href="#cb53-18" aria-hidden="true" tabindex="-1"></a> </span>
1287
- <span id="cb53-19"><a href="#cb53-19" aria-hidden="true" tabindex="-1"></a> <span class="co">// Traditional navigation for fully materialized values</span></span>
1288
- <span id="cb53-20"><a href="#cb53-20" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> navigate_materialized<span class="op">(</span>value<span class="op">,</span> field_path<span class="op">);</span></span>
1289
- <span id="cb53-21"><a href="#cb53-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
1290
- <hr />
1291
- <h2 id="external-type-system"><strong>6.6 External type
1292
- system</strong></h2>
1293
- <p>Built-in and foreign types integrate through a plugin interface:</p>
1294
- <h3 id="external-operations"><strong>6.6.1 External
1295
- operations</strong></h3>
1296
- <div class="sourceCode" id="cb54"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb54-1"><a href="#cb54-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> ExternalOps <span class="op">{</span></span>
1297
- <span id="cb54-2"><a href="#cb54-2" aria-hidden="true" tabindex="-1"></a> KValue<span class="op">*</span> <span class="op">(*</span>serialize<span class="op">)(</span><span class="dt">void</span><span class="op">*</span> data<span class="op">);</span></span>
1298
- <span id="cb54-3"><a href="#cb54-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">void</span><span class="op">*</span> <span class="op">(*</span>deserialize<span class="op">)(</span>KValue<span class="op">*</span> serialized<span class="op">);</span></span>
1299
- <span id="cb54-4"><a href="#cb54-4" aria-hidden="true" tabindex="-1"></a> KValue<span class="op">*</span> <span class="op">(*</span>apply_function<span class="op">)(</span><span class="dt">void</span><span class="op">*</span> data<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span><span class="op">*</span> func_name<span class="op">,</span> KValue<span class="op">*</span> args<span class="op">);</span></span>
1300
- <span id="cb54-5"><a href="#cb54-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">bool</span> <span class="op">(*</span>equals<span class="op">)(</span><span class="dt">void</span><span class="op">*</span> a<span class="op">,</span> <span class="dt">void</span><span class="op">*</span> b<span class="op">);</span></span>
1301
- <span id="cb54-6"><a href="#cb54-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint64_t</span> <span class="op">(*</span>hash<span class="op">)(</span><span class="dt">void</span><span class="op">*</span> data<span class="op">);</span></span>
1302
- <span id="cb54-7"><a href="#cb54-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">void</span> <span class="op">(*</span>destroy<span class="op">)(</span><span class="dt">void</span><span class="op">*</span> data<span class="op">);</span></span>
1303
- <span id="cb54-8"><a href="#cb54-8" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
1304
- <h3 id="built-in-type-examples"><strong>6.6.2 Built-in type
1305
- examples</strong></h3>
1306
- <ul>
1307
- <li><strong>Strings</strong> — UTF-8 encoded with length prefix</li>
1308
- <li><strong>Integers</strong> — variable-length encoding (LEB128)</li>
1309
- <li><strong>Floats</strong> — IEEE 754 binary representation</li>
1310
- <li><strong>Blobs</strong> — raw binary data with length prefix</li>
1311
- <li><strong>Handles</strong> — opaque references to external
1312
- resources</li>
1313
- </ul>
1314
- <h3 id="type-registration"><strong>6.6.3 Type registration</strong></h3>
1315
- <div class="sourceCode" id="cb55"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb55-1"><a href="#cb55-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> register_external_type<span class="op">(</span><span class="dt">int</span> type_id<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span><span class="op">*</span> name<span class="op">,</span> ExternalOps<span class="op">*</span> ops<span class="op">)</span> <span class="op">{</span></span>
1316
- <span id="cb55-2"><a href="#cb55-2" aria-hidden="true" tabindex="-1"></a> external_types<span class="op">[</span>type_id<span class="op">]</span> <span class="op">=</span> <span class="op">{</span></span>
1317
- <span id="cb55-3"><a href="#cb55-3" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>name <span class="op">=</span> name<span class="op">,</span></span>
1318
- <span id="cb55-4"><a href="#cb55-4" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>ops <span class="op">=</span> ops<span class="op">,</span></span>
1319
- <span id="cb55-5"><a href="#cb55-5" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>canonical_hash <span class="op">=</span> compute_type_hash<span class="op">(</span>name<span class="op">,</span> ops<span class="op">-&gt;</span>signature<span class="op">)</span></span>
1320
- <span id="cb55-6"><a href="#cb55-6" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
1321
- <span id="cb55-7"><a href="#cb55-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
1322
- <hr />
1323
- <h2 id="memory-management-and-performance"><strong>6.7 Memory management
1324
- and performance</strong></h2>
1325
- <h3 id="arena-allocation"><strong>6.7.1 Arena allocation</strong></h3>
1326
- <p>All materialized nodes use arena allocation for fast allocation and
1327
- bulk deallocation:</p>
1328
- <div class="sourceCode" id="cb56"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb56-1"><a href="#cb56-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Arena <span class="op">{</span></span>
1329
- <span id="cb56-2"><a href="#cb56-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> memory<span class="op">;</span></span>
1330
- <span id="cb56-3"><a href="#cb56-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">size_t</span> capacity<span class="op">;</span></span>
1331
- <span id="cb56-4"><a href="#cb56-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">size_t</span> used<span class="op">;</span></span>
1332
- <span id="cb56-5"><a href="#cb56-5" aria-hidden="true" tabindex="-1"></a> Arena<span class="op">*</span> next<span class="op">;</span> <span class="co">// linked list of arena blocks</span></span>
1333
- <span id="cb56-6"><a href="#cb56-6" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
1334
- <h3 id="sharing-and-deduplication"><strong>6.7.2 Sharing and
1335
- deduplication</strong></h3>
1336
- <ul>
1337
- <li><strong>Canonical folding</strong> — identical subtrees share the
1338
- same materialized nodes</li>
1339
- <li><strong>Bitstream sharing</strong> — multiple lazy values can
1340
- reference the same underlying bitstream</li>
1341
- <li><strong>DAG back-references</strong> — shared subtrees in serialized
1342
- form avoid duplication during lazy materialization</li>
1343
- <li><strong>External sharing</strong> — external values use reference
1344
- counting or garbage collection as appropriate</li>
1345
- </ul>
1346
- <h3 id="optimization-opportunities"><strong>6.7.3 Optimization
1347
- opportunities</strong></h3>
1348
- <ul>
1349
- <li><strong>Zero-copy operations</strong> — identity, field projection
1350
- on serialized values</li>
1351
- <li><strong>Streaming evaluation</strong> — process large datasets
1352
- without full materialization<br />
1353
- </li>
1354
- <li><strong>Parallel deserialization</strong> — independent subtrees can
1355
- be materialized concurrently</li>
1356
- <li><strong>DAG-aware caching</strong> — cache resolutions of frequently
1357
- accessed back-references</li>
1358
- <li><strong>Memoization</strong> — cache frequently accessed paths in
1359
- lazy structures</li>
1360
- </ul>
1361
- <hr />
1362
- <h2 id="example-lazy-evaluation-in-practice"><strong>6.8 Example: Lazy
1363
- evaluation in practice</strong></h2>
1364
- <p>Consider processing a large JSON-like structure where we only need
1365
- one field:</p>
1366
- <pre class="k-lang"><code>$record = { string name, list data, metadata meta };
1367
- $list = &lt; {nat value, list next} cons, {} nil &gt;;
1368
- $metadata = { timestamp created, string author };</code></pre>
1369
- <p>For the input program <code>\x.x.name</code> (extract name
1370
- field):</p>
1371
- <ol type="1">
1372
- <li><strong>Input</strong> arrives as serialized bitstream (e.g., from
1373
- network/disk)</li>
1374
- <li><strong>Lazy parsing</strong> deserializes only the discriminator of
1375
- the root product</li>
1376
- <li><strong>Field access</strong> deserializes path to <code>name</code>
1377
- field, leaving <code>data</code> and <code>meta</code> serialized</li>
1378
- <li><strong>Output</strong> the extracted string value (possibly in
1379
- external string format)</li>
1380
- </ol>
1381
- <p>The entire <code>data</code> list and <code>metadata</code> remain as
1382
- untouched bitstreams, providing massive performance benefits for large,
1383
- sparsely accessed data structures.</p>
1384
- <h3 id="serialized-representation"><strong>6.8.1 Serialized
1385
- representation</strong></h3>
1386
- <p>The same value can exist in different forms simultaneously:</p>
1387
- <div class="sourceCode" id="cb58"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb58-1"><a href="#cb58-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Original input: fully serialized</span></span>
1388
- <span id="cb58-2"><a href="#cb58-2" aria-hidden="true" tabindex="-1"></a>KValue input <span class="op">=</span> <span class="op">{</span></span>
1389
- <span id="cb58-3"><a href="#cb58-3" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>form <span class="op">=</span> SERIALIZED<span class="op">,</span></span>
1390
- <span id="cb58-4"><a href="#cb58-4" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>serialized <span class="op">=</span> <span class="op">{</span></span>
1391
- <span id="cb58-5"><a href="#cb58-5" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>bits <span class="op">=</span> bitstream_buffer<span class="op">,</span></span>
1392
- <span id="cb58-6"><a href="#cb58-6" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>type_hash <span class="op">=</span> hash<span class="op">(</span><span class="st">&quot;record&quot;</span><span class="op">)</span></span>
1393
- <span id="cb58-7"><a href="#cb58-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
1394
- <span id="cb58-8"><a href="#cb58-8" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
1395
- <span id="cb58-9"><a href="#cb58-9" aria-hidden="true" tabindex="-1"></a></span>
1396
- <span id="cb58-10"><a href="#cb58-10" aria-hidden="true" tabindex="-1"></a><span class="co">// After partial access: hybrid lazy</span></span>
1397
- <span id="cb58-11"><a href="#cb58-11" aria-hidden="true" tabindex="-1"></a>KValue hybrid <span class="op">=</span> <span class="op">{</span></span>
1398
- <span id="cb58-12"><a href="#cb58-12" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>form <span class="op">=</span> LAZY<span class="op">,</span></span>
1399
- <span id="cb58-13"><a href="#cb58-13" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>lazy<span class="op">.</span>root <span class="op">=</span> <span class="op">{</span></span>
1400
- <span id="cb58-14"><a href="#cb58-14" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>state <span class="op">=</span> <span class="dv">0</span><span class="op">,</span> <span class="op">.</span>tag <span class="op">=</span> <span class="op">-</span><span class="dv">1</span><span class="op">,</span> <span class="op">.</span>arity <span class="op">=</span> <span class="dv">3</span><span class="op">,</span></span>
1401
- <span id="cb58-15"><a href="#cb58-15" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>child <span class="op">=</span> <span class="op">{</span></span>
1402
- <span id="cb58-16"><a href="#cb58-16" aria-hidden="true" tabindex="-1"></a> <span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span> <span class="op">.</span>state <span class="op">=</span> MATERIALIZED_CHILD<span class="op">,</span> <span class="op">.</span>node <span class="op">=</span> materialized_string_node <span class="op">},</span> <span class="co">// name: materialized</span></span>
1403
- <span id="cb58-17"><a href="#cb58-17" aria-hidden="true" tabindex="-1"></a> <span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span> <span class="op">.</span>state <span class="op">=</span> SERIALIZED_CHILD<span class="op">,</span> <span class="op">.</span>serialized <span class="op">=</span> <span class="op">{</span>bits<span class="op">+</span>offset<span class="op">,</span> <span class="dv">64</span><span class="op">}</span> <span class="op">},</span> <span class="co">// data: still serialized </span></span>
1404
- <span id="cb58-18"><a href="#cb58-18" aria-hidden="true" tabindex="-1"></a> <span class="op">[</span><span class="dv">2</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span> <span class="op">.</span>state <span class="op">=</span> SERIALIZED_CHILD<span class="op">,</span> <span class="op">.</span>serialized <span class="op">=</span> <span class="op">{</span>bits<span class="op">+</span>offset<span class="op">,</span> <span class="dv">1088</span><span class="op">}</span> <span class="op">}</span> <span class="co">// meta: still serialized</span></span>
1405
- <span id="cb58-19"><a href="#cb58-19" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
1406
- <span id="cb58-20"><a href="#cb58-20" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
1407
- <span id="cb58-21"><a href="#cb58-21" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
1408
- <h3 id="external-type-integration-example"><strong>6.8.2 External type
1409
- integration example</strong></h3>
1410
- <div class="sourceCode" id="cb59"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb59-1"><a href="#cb59-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Built-in string type</span></span>
1411
- <span id="cb59-2"><a href="#cb59-2" aria-hidden="true" tabindex="-1"></a>KValue string_value <span class="op">=</span> <span class="op">{</span></span>
1412
- <span id="cb59-3"><a href="#cb59-3" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>form <span class="op">=</span> EXTERNAL<span class="op">,</span></span>
1413
- <span id="cb59-4"><a href="#cb59-4" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>external <span class="op">=</span> <span class="op">{</span></span>
1414
- <span id="cb59-5"><a href="#cb59-5" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>data <span class="op">=</span> utf8_string_data<span class="op">,</span></span>
1415
- <span id="cb59-6"><a href="#cb59-6" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>type_id <span class="op">=</span> BUILTIN_STRING<span class="op">,</span></span>
1416
- <span id="cb59-7"><a href="#cb59-7" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>ops <span class="op">=</span> <span class="op">&amp;</span>string_operations</span>
1417
- <span id="cb59-8"><a href="#cb59-8" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
1418
- <span id="cb59-9"><a href="#cb59-9" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
1419
- <span id="cb59-10"><a href="#cb59-10" aria-hidden="true" tabindex="-1"></a></span>
1420
- <span id="cb59-11"><a href="#cb59-11" aria-hidden="true" tabindex="-1"></a><span class="co">// The string_operations provide:</span></span>
1421
- <span id="cb59-12"><a href="#cb59-12" aria-hidden="true" tabindex="-1"></a>ExternalOps string_operations <span class="op">=</span> <span class="op">{</span></span>
1422
- <span id="cb59-13"><a href="#cb59-13" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>serialize <span class="op">=</span> string_to_canonical_bits<span class="op">,</span></span>
1423
- <span id="cb59-14"><a href="#cb59-14" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>deserialize <span class="op">=</span> canonical_bits_to_string<span class="op">,</span></span>
1424
- <span id="cb59-15"><a href="#cb59-15" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>apply_function <span class="op">=</span> string_builtin_functions<span class="op">,</span> <span class="co">// length, concat, etc.</span></span>
1425
- <span id="cb59-16"><a href="#cb59-16" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>equals <span class="op">=</span> utf8_string_compare<span class="op">,</span></span>
1426
- <span id="cb59-17"><a href="#cb59-17" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>hash <span class="op">=</span> utf8_string_hash<span class="op">,</span></span>
1427
- <span id="cb59-18"><a href="#cb59-18" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>destroy <span class="op">=</span> free_string_data</span>
1428
- <span id="cb59-19"><a href="#cb59-19" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
1429
- <hr />
1430
- <h2 id="summary-4"><strong>6.9 Summary</strong></h2>
1431
- <p>This unified representation provides several key advantages:</p>
1432
- <ul>
1433
- <li><strong>Performance</strong> — avoid unnecessary deserialization
1434
- through lazy evaluation</li>
1435
- <li><strong>Memory efficiency</strong> — share serialized data between
1436
- multiple references</li>
1437
- <li><strong>Composability</strong> — external types integrate seamlessly
1438
- with k’s type system</li>
1439
- <li><strong>Streaming</strong> — process large data structures with
1440
- bounded memory usage</li>
1441
- <li><strong>Determinism</strong> — canonical serialization ensures
1442
- reproducible computation</li>
1443
- </ul>
1444
- <p>The design supports the full spectrum from zero-copy identity
1445
- operations to fully materialized tree traversal, allowing the runtime to
1446
- automatically choose the most efficient representation for each use
1447
- case.</p>
1448
- <h3 id="key-design-principles"><strong>6.9.1 Key design
1449
- principles</strong></h3>
1450
- <ul>
1451
- <li><strong>Immutability</strong> — all representations are immutable,
1452
- enabling safe sharing</li>
1453
- <li><strong>Demand-driven</strong> — materialization happens only when
1454
- computation requires it</li>
1455
- <li><strong>Canonical</strong> — serialized forms are deterministic and
1456
- hashable</li>
1457
- <li><strong>Extensible</strong> — external types extend the system
1458
- without breaking canonical properties</li>
1459
- <li><strong>Unified</strong> — single abstraction handles all value
1460
- representations</li>
1461
- </ul>
1462
- <hr />
1463
- <h2 id="execution-model-with-decorated-pointers"><strong>6.10 Execution
1464
- model with decorated pointers</strong></h2>
1465
- <p>The formal execution model is based on decorated pointers, which
1466
- represent values during execution:</p>
1467
- <h3 id="decorated-pointers"><strong>6.10.1 Decorated
1468
- pointers</strong></h3>
1469
- <p>Every value during execution is represented by a <strong>decorated
1470
- pointer</strong>:</p>
1471
- <div class="sourceCode" id="cb60"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb60-1"><a href="#cb60-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> DecoratedPtr <span class="op">{</span></span>
1472
- <span id="cb60-2"><a href="#cb60-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> bits<span class="op">;</span> <span class="co">// pointer into serialized input heap</span></span>
1473
- <span id="cb60-3"><a href="#cb60-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">size_t</span> bit_offset<span class="op">;</span> <span class="co">// bit position within the stream</span></span>
1474
- <span id="cb60-4"><a href="#cb60-4" aria-hidden="true" tabindex="-1"></a> TypeState type_state<span class="op">;</span> <span class="co">// canonical automaton state (C0, C1, ...)</span></span>
1475
- <span id="cb60-5"><a href="#cb60-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> ref_count<span class="op">;</span> <span class="co">// for sharing and caching</span></span>
1476
- <span id="cb60-6"><a href="#cb60-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> <span class="op">{</span></span>
1477
- <span id="cb60-7"><a href="#cb60-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">bool</span> is_cached<span class="op">;</span> <span class="co">// memoization flag</span></span>
1478
- <span id="cb60-8"><a href="#cb60-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint64_t</span> content_hash<span class="op">;</span> <span class="co">// for cache lookup</span></span>
1479
- <span id="cb60-9"><a href="#cb60-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> cache<span class="op">;</span></span>
1480
- <span id="cb60-10"><a href="#cb60-10" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
1481
- <p>The key insight: <strong>decorated pointers are lightweight and can
1482
- be computed without memory allocation</strong>.</p>
1483
- <h3 id="program-execution-pipeline"><strong>6.10.2 Program execution
1484
- pipeline</strong></h3>
1485
- <p>A compiled k program is a composition of operations:
1486
- <code>projection ∘ product ∘ union ∘ builtin_call ∘ ...</code></p>
1487
- <p>Each operation transforms a decorated pointer:</p>
1488
- <pre class="text"><code>DecoratedPtr → DecoratedPtr</code></pre>
1489
- <h4 id="projection-operation"><strong>Projection operation</strong></h4>
1490
- <p>For field access <code>.field_name</code>:</p>
1491
- <div class="sourceCode" id="cb62"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb62-1"><a href="#cb62-1" aria-hidden="true" tabindex="-1"></a>DecoratedPtr project_field_optimized<span class="op">(</span>DecoratedPtr input<span class="op">,</span> <span class="dt">int</span> field_index<span class="op">)</span> <span class="op">{</span></span>
1492
- <span id="cb62-2"><a href="#cb62-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// Hardware-optimized field navigation</span></span>
1493
- <span id="cb62-3"><a href="#cb62-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> byte_ptr <span class="op">=</span> input<span class="op">.</span>bits <span class="op">+</span> <span class="op">(</span>input<span class="op">.</span>bit_offset <span class="op">&gt;&gt;</span> <span class="dv">3</span><span class="op">);</span></span>
1494
- <span id="cb62-4"><a href="#cb62-4" aria-hidden="true" tabindex="-1"></a> </span>
1495
- <span id="cb62-5"><a href="#cb62-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// Read encoding header</span></span>
1496
- <span id="cb62-6"><a href="#cb62-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> OptimalEncoding<span class="op">*</span> header <span class="op">=</span> <span class="op">(</span><span class="kw">struct</span> OptimalEncoding<span class="op">*)</span>byte_ptr<span class="op">;</span></span>
1497
- <span id="cb62-7"><a href="#cb62-7" aria-hidden="true" tabindex="-1"></a> </span>
1498
- <span id="cb62-8"><a href="#cb62-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>header<span class="op">-&gt;</span>arity <span class="op">&lt;=</span> <span class="dv">8</span><span class="op">)</span> <span class="op">{</span></span>
1499
- <span id="cb62-9"><a href="#cb62-9" aria-hidden="true" tabindex="-1"></a> <span class="co">// Small product: sequential scan (cache-friendly)</span></span>
1500
- <span id="cb62-10"><a href="#cb62-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> field_ptr <span class="op">=</span> byte_ptr <span class="op">+</span> <span class="kw">sizeof</span><span class="op">(</span><span class="kw">struct</span> OptimalEncoding<span class="op">);</span></span>
1501
- <span id="cb62-11"><a href="#cb62-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op">&lt;</span> field_index<span class="op">;</span> i<span class="op">++)</span> <span class="op">{</span></span>
1502
- <span id="cb62-12"><a href="#cb62-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span> field_size <span class="op">=</span> <span class="op">*(</span><span class="dt">uint32_t</span><span class="op">*)</span>field_ptr<span class="op">;</span> <span class="co">// First 4 bytes = size</span></span>
1503
- <span id="cb62-13"><a href="#cb62-13" aria-hidden="true" tabindex="-1"></a> field_ptr <span class="op">+=</span> field_size<span class="op">;</span></span>
1504
- <span id="cb62-14"><a href="#cb62-14" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
1505
- <span id="cb62-15"><a href="#cb62-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_ptr_from_bytes<span class="op">(</span>field_ptr<span class="op">);</span></span>
1506
- <span id="cb62-16"><a href="#cb62-16" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
1507
- <span id="cb62-17"><a href="#cb62-17" aria-hidden="true" tabindex="-1"></a> <span class="co">// Large product: offset table lookup (O(1) access)</span></span>
1508
- <span id="cb62-18"><a href="#cb62-18" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span> field_offset <span class="op">=</span> header<span class="op">-&gt;</span>field_offsets<span class="op">[</span>field_index<span class="op">];</span></span>
1509
- <span id="cb62-19"><a href="#cb62-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_ptr_from_bytes<span class="op">(</span>byte_ptr <span class="op">+</span> field_offset<span class="op">);</span></span>
1510
- <span id="cb62-20"><a href="#cb62-20" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
1511
- <span id="cb62-21"><a href="#cb62-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
1512
- <p><strong>Key property</strong>: Hardware-optimized navigation using
1513
- word-aligned loads and offset tables.</p>
1514
- <h4 id="union-operation"><strong>Union operation</strong></h4>
1515
- <p>For pattern matching
1516
- <code>case { tag1 → ..., tag2 → ... }</code>:</p>
1517
- <div class="sourceCode" id="cb63"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb63-1"><a href="#cb63-1" aria-hidden="true" tabindex="-1"></a>DecoratedPtr match_union_optimized<span class="op">(</span>DecoratedPtr input<span class="op">,</span> <span class="dt">int</span> expected_tag<span class="op">)</span> <span class="op">{</span></span>
1518
- <span id="cb63-2"><a href="#cb63-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// Read single-byte discriminator (hardware-friendly)</span></span>
1519
- <span id="cb63-3"><a href="#cb63-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> byte_ptr <span class="op">=</span> input<span class="op">.</span>bits <span class="op">+</span> <span class="op">(</span>input<span class="op">.</span>bit_offset <span class="op">&gt;&gt;</span> <span class="dv">3</span><span class="op">);</span></span>
1520
- <span id="cb63-4"><a href="#cb63-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> OptimalEncoding<span class="op">*</span> header <span class="op">=</span> <span class="op">(</span><span class="kw">struct</span> OptimalEncoding<span class="op">*)</span>byte_ptr<span class="op">;</span></span>
1521
- <span id="cb63-5"><a href="#cb63-5" aria-hidden="true" tabindex="-1"></a> </span>
1522
- <span id="cb63-6"><a href="#cb63-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> actual_tag <span class="op">=</span> header<span class="op">-&gt;</span>data<span class="op">[</span><span class="dv">0</span><span class="op">];</span> <span class="co">// First byte of data = discriminator</span></span>
1523
- <span id="cb63-7"><a href="#cb63-7" aria-hidden="true" tabindex="-1"></a> </span>
1524
- <span id="cb63-8"><a href="#cb63-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>actual_tag <span class="op">!=</span> expected_tag<span class="op">)</span> <span class="op">{</span></span>
1525
- <span id="cb63-9"><a href="#cb63-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> UNDEFINED_PTR<span class="op">;</span> <span class="co">// Pattern match failure</span></span>
1526
- <span id="cb63-10"><a href="#cb63-10" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
1527
- <span id="cb63-11"><a href="#cb63-11" aria-hidden="true" tabindex="-1"></a> </span>
1528
- <span id="cb63-12"><a href="#cb63-12" aria-hidden="true" tabindex="-1"></a> <span class="co">// Skip past header + discriminator</span></span>
1529
- <span id="cb63-13"><a href="#cb63-13" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> child_ptr <span class="op">=</span> byte_ptr <span class="op">+</span> <span class="kw">sizeof</span><span class="op">(</span><span class="kw">struct</span> OptimalEncoding<span class="op">)</span> <span class="op">+</span> <span class="dv">1</span><span class="op">;</span></span>
1530
- <span id="cb63-14"><a href="#cb63-14" aria-hidden="true" tabindex="-1"></a> </span>
1531
- <span id="cb63-15"><a href="#cb63-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_ptr_from_bytes<span class="op">(</span>child_ptr<span class="op">);</span></span>
1532
- <span id="cb63-16"><a href="#cb63-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
1533
- <h4 id="product-operation"><strong>Product operation</strong></h4>
1534
- <p>For product construction <code>{ field1, field2, ... }</code>:</p>
1535
- <div class="sourceCode" id="cb64"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb64-1"><a href="#cb64-1" aria-hidden="true" tabindex="-1"></a>DecoratedPtr construct_product<span class="op">(</span>DecoratedPtr<span class="op">*</span> field_ptrs<span class="op">,</span> <span class="dt">int</span> arity<span class="op">)</span> <span class="op">{</span></span>
1536
- <span id="cb64-2"><a href="#cb64-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// This is the primary point where memory allocation is required.</span></span>
1537
- <span id="cb64-3"><a href="#cb64-3" aria-hidden="true" tabindex="-1"></a> ProductNode<span class="op">*</span> result <span class="op">=</span> allocate_product_node<span class="op">(</span>arity<span class="op">);</span></span>
1538
- <span id="cb64-4"><a href="#cb64-4" aria-hidden="true" tabindex="-1"></a> </span>
1539
- <span id="cb64-5"><a href="#cb64-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// Evaluate each field (possibly in parallel)</span></span>
1540
- <span id="cb64-6"><a href="#cb64-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op">&lt;</span> arity<span class="op">;</span> i<span class="op">++)</span> <span class="op">{</span></span>
1541
- <span id="cb64-7"><a href="#cb64-7" aria-hidden="true" tabindex="-1"></a> result<span class="op">-&gt;</span>fields<span class="op">[</span>i<span class="op">]</span> <span class="op">=</span> evaluate_expression<span class="op">(</span>field_ptrs<span class="op">[</span>i<span class="op">]);</span></span>
1542
- <span id="cb64-8"><a href="#cb64-8" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
1543
- <span id="cb64-9"><a href="#cb64-9" aria-hidden="true" tabindex="-1"></a> </span>
1544
- <span id="cb64-10"><a href="#cb64-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_materialized_ptr<span class="op">(</span>result<span class="op">);</span></span>
1545
- <span id="cb64-11"><a href="#cb64-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
1546
- <h4 id="built-in-call-operation"><strong>Built-in call
1547
- operation</strong></h4>
1548
- <p>For external functions <code>string_length</code>,
1549
- <code>add_int</code>, etc.:</p>
1550
- <div class="sourceCode" id="cb65"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb65-1"><a href="#cb65-1" aria-hidden="true" tabindex="-1"></a>DecoratedPtr builtin_call<span class="op">(</span>DecoratedPtr input<span class="op">,</span> BuiltinFunc func<span class="op">)</span> <span class="op">{</span></span>
1551
- <span id="cb65-2"><a href="#cb65-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// Force materialization of the input</span></span>
1552
- <span id="cb65-3"><a href="#cb65-3" aria-hidden="true" tabindex="-1"></a> ExternalValue<span class="op">*</span> materialized <span class="op">=</span> force_external<span class="op">(</span>input<span class="op">);</span></span>
1553
- <span id="cb65-4"><a href="#cb65-4" aria-hidden="true" tabindex="-1"></a> </span>
1554
- <span id="cb65-5"><a href="#cb65-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// Delegate to external implementation</span></span>
1555
- <span id="cb65-6"><a href="#cb65-6" aria-hidden="true" tabindex="-1"></a> ExternalValue<span class="op">*</span> result <span class="op">=</span> func<span class="op">-&gt;</span>call<span class="op">(</span>materialized<span class="op">);</span></span>
1556
- <span id="cb65-7"><a href="#cb65-7" aria-hidden="true" tabindex="-1"></a> </span>
1557
- <span id="cb65-8"><a href="#cb65-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_external_ptr<span class="op">(</span>result<span class="op">);</span></span>
1558
- <span id="cb65-9"><a href="#cb65-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
1559
- <h3 id="execution-strategy"><strong>6.10.3 Execution
1560
- strategy</strong></h3>
1561
- <ol type="1">
1562
- <li><strong>Input setup</strong>: Place serialized input in heap, create
1563
- root decorated pointer</li>
1564
- <li><strong>Lazy evaluation</strong>: Transform decorated pointers
1565
- without allocation when possible</li>
1566
- <li><strong>Forced materialization</strong>: Allocate memory only when
1567
- constructing products or calling built-ins</li>
1568
- <li><strong>Reference counting</strong>: Share decorated pointers for
1569
- common subexpressions</li>
1570
- <li><strong>Output serialization</strong>: Convert final decorated
1571
- pointer back to canonical bits</li>
1572
- </ol>
1573
- <h3 id="example-execution-trace"><strong>6.10.4 Example execution
1574
- trace</strong></h3>
1575
- <p>For program <code>\x.(x.data.head.value, x.name)</code> on input
1576
- <code>{ name: "alice", data: [42, 17] }</code>:</p>
1577
- <pre class="text"><code>Step 1: input_ptr = {bits: heap_start, offset: 0, state: C0_record}
1578
-
1579
- Step 2: data_ptr = project_field(input_ptr, 1) // .data
1580
- = {bits: heap_start, offset: 120, state: C0_list}
1581
-
1582
- Step 3: head_ptr = match_union(data_ptr, CONS_TAG) // pattern match
1583
- = {bits: heap_start, offset: 122, state: C0_cons}
1584
-
1585
- Step 4: value_ptr = project_field(head_ptr, 0) // .value
1586
- = {bits: heap_start, offset: 122, state: C0_int}
1587
-
1588
- Step 5: name_ptr = project_field(input_ptr, 0) // .name
1589
- = {bits: heap_start, offset: 8, state: C0_string}
1590
-
1591
- Step 6: result_ptr = construct_product([value_ptr, name_ptr])
1592
- // Note: memory allocation for the result tuple occurs here.</code></pre>
1593
- <h3 id="optimization-opportunities-1"><strong>6.10.5 Optimization
1594
- opportunities</strong></h3>
1595
- <ul>
1596
- <li><strong>Parallel field evaluation</strong> — Independent fields can
1597
- be computed concurrently</li>
1598
- <li><strong>Memoization</strong> — Cache decorated pointers for repeated
1599
- subexpressions<br />
1600
- </li>
1601
- <li><strong>Streaming</strong> — Process parts of large inputs without
1602
- loading everything</li>
1603
- <li><strong>Zero-copy identity</strong> — <code>()</code> just returns
1604
- the input decorated pointer</li>
1605
- <li><strong>Prefix-free parsing</strong> — No backtracking needed,
1606
- linear-time navigation</li>
1607
- </ul>
1608
- <p>This model provides <strong>optimal performance</strong> for sparse
1609
- data access while maintaining the mathematical precision of k’s type
1610
- system.</p>
1611
- <hr />
1612
- <h2 id="implementation-considerations"><strong>6.11 Implementation
1613
- considerations</strong></h2>
1614
- <h3 id="prefix-free-code-requirements"><strong>6.11.1 Prefix-free code
1615
- requirements</strong></h3>
1616
- <p>The execution model depends critically on <strong>prefix-free
1617
- codes</strong> in the serialization:</p>
1618
- <ul>
1619
- <li><strong>Union discriminators</strong> — Fixed-length codes ensure
1620
- constant-time tag reading</li>
1621
- <li><strong>External data</strong> — Length-prefixed to enable skipping
1622
- without parsing</li>
1623
- <li><strong>Product fields</strong> — Implicit boundaries defined by
1624
- type structure</li>
1625
- </ul>
1626
- <p>This enables the <code>skip_field()</code> function to advance
1627
- pointers without full deserialization.</p>
1628
- <h3 id="reference-counting-and-caching"><strong>6.11.2 Reference
1629
- counting and caching</strong></h3>
1630
- <p>Decorated pointers should be reference-counted for several
1631
- reasons:</p>
1632
- <p>Benefits:</p>
1633
- <ul>
1634
- <li><strong>Sharing</strong> — Multiple references to the same
1635
- subexpression</li>
1636
- <li><strong>Caching</strong> — Avoid recomputation of expensive
1637
- operations</li>
1638
- <li><strong>Memory efficiency</strong> — Single copy of large serialized
1639
- inputs</li>
1640
- </ul>
1641
- <h3 id="parallel-evaluation"><strong>6.11.3 Parallel
1642
- evaluation</strong></h3>
1643
- <p>Product construction offers natural parallelization:</p>
1644
- <div class="sourceCode" id="cb67"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb67-1"><a href="#cb67-1" aria-hidden="true" tabindex="-1"></a>DecoratedPtr construct_product_parallel<span class="op">(</span>DecoratedPtr<span class="op">*</span> field_ptrs<span class="op">,</span> <span class="dt">int</span> arity<span class="op">)</span> <span class="op">{</span></span>
1645
- <span id="cb67-2"><a href="#cb67-2" aria-hidden="true" tabindex="-1"></a> ProductNode<span class="op">*</span> result <span class="op">=</span> allocate_product_node<span class="op">(</span>arity<span class="op">);</span></span>
1646
- <span id="cb67-3"><a href="#cb67-3" aria-hidden="true" tabindex="-1"></a> </span>
1647
- <span id="cb67-4"><a href="#cb67-4" aria-hidden="true" tabindex="-1"></a> <span class="pp">#pragma omp parallel for</span></span>
1648
- <span id="cb67-5"><a href="#cb67-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op">&lt;</span> arity<span class="op">;</span> i<span class="op">++)</span> <span class="op">{</span></span>
1649
- <span id="cb67-6"><a href="#cb67-6" aria-hidden="true" tabindex="-1"></a> result<span class="op">-&gt;</span>fields<span class="op">[</span>i<span class="op">]</span> <span class="op">=</span> evaluate_expression<span class="op">(</span>field_ptrs<span class="op">[</span>i<span class="op">]);</span></span>
1650
- <span id="cb67-7"><a href="#cb67-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
1651
- <span id="cb67-8"><a href="#cb67-8" aria-hidden="true" tabindex="-1"></a> </span>
1652
- <span id="cb67-9"><a href="#cb67-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_materialized_ptr<span class="op">(</span>result<span class="op">);</span></span>
1653
- <span id="cb67-10"><a href="#cb67-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
1654
- <p>Each field evaluation is independent and can run on separate
1655
- threads.</p>
1656
- <h3 id="memory-layout-optimization"><strong>6.11.4 Memory layout
1657
- optimization</strong></h3>
1658
- <p>The input heap should be designed for efficient navigation:</p>
1659
- <div class="sourceCode" id="cb68"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb68-1"><a href="#cb68-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> InputHeap <span class="op">{</span></span>
1660
- <span id="cb68-2"><a href="#cb68-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> serialized_data<span class="op">;</span> <span class="co">// the original bitstream</span></span>
1661
- <span id="cb68-3"><a href="#cb68-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">size_t</span> total_bits<span class="op">;</span> <span class="co">// total size</span></span>
1662
- <span id="cb68-4"><a href="#cb68-4" aria-hidden="true" tabindex="-1"></a> </span>
1663
- <span id="cb68-5"><a href="#cb68-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// Optional: precomputed navigation table for large inputs</span></span>
1664
- <span id="cb68-6"><a href="#cb68-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> <span class="op">{</span></span>
1665
- <span id="cb68-7"><a href="#cb68-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">size_t</span><span class="op">*</span> field_offsets<span class="op">;</span> <span class="co">// byte offsets for major fields</span></span>
1666
- <span id="cb68-8"><a href="#cb68-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> table_size<span class="op">;</span> <span class="co">// number of cached offsets</span></span>
1667
- <span id="cb68-9"><a href="#cb68-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> navigation_cache<span class="op">;</span></span>
1668
- <span id="cb68-10"><a href="#cb68-10" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
1669
- <p>For very large inputs, precomputing field offsets can eliminate
1670
- repeated prefix-free parsing.</p>
1671
- <hr />
1672
- <h2 id="final-summary"><strong>6.12 Final summary</strong></h2>
1673
- <p>This unified design achieves several important goals:</p>
1674
- <ol type="1">
1675
- <li><strong>Zero-copy operations</strong> — Identity and projection work
1676
- directly on serialized data</li>
1677
- <li><strong>Demand-driven materialization</strong> — Memory allocation
1678
- only when necessary</li>
1679
- <li><strong>External type integration</strong> — Built-ins fit
1680
- seamlessly into the execution model</li>
1681
- <li><strong>Parallel execution</strong> — Natural parallelization
1682
- opportunities</li>
1683
- <li><strong>Streaming capability</strong> — Process large inputs with
1684
- bounded memory</li>
1685
- </ol>
1686
- <p>The decorated pointer model provides a clean abstraction that bridges
1687
- the gap between the mathematical elegance of k’s type system and the
1688
- performance requirements of real-world data processing.</p>
1689
- <p><strong>Key insight</strong>: By treating serialized data as the
1690
- primary representation and materialized structures as secondary
1691
- optimization, we invert the traditional approach and achieve much better
1692
- performance for sparse data access patterns.</p>
1693
- <h3 id="hardware-optimized-encoding-summary"><strong>6.12.1
1694
- Hardware-optimized encoding summary</strong></h3>
1695
- <p>The final encoding strategy balances theoretical optimality with
1696
- practical hardware constraints:</p>
1697
- <p><strong>Trade-offs achieved</strong>:</p>
1698
- <ul>
1699
- <li><strong>Space efficiency</strong>: 80-90% of theoretical
1700
- optimum</li>
1701
- <li><strong>Decode performance</strong>: 5-10× faster than bit-level
1702
- encoding<br />
1703
- </li>
1704
- <li><strong>Cache behavior</strong>: Excellent (word-aligned, sequential
1705
- access)</li>
1706
- <li><strong>SIMD compatibility</strong>: Yes (bulk discriminator
1707
- processing)</li>
1708
- <li><strong>Architecture agnostic</strong>: Optimized for x86-64 and
1709
- ARM64</li>
1710
- </ul>
1711
- <p><strong>Performance characteristics</strong>:</p>
1712
- <pre class="text"><code>Operation Hardware-optimized Bit-level optimal
1713
- Field access 2-8 cycles 50-100 cycles
1714
- Union matching 1-3 cycles 20-40 cycles
1715
- Memory bandwidth 95% theoretical 60% theoretical
1716
- Cache miss ratio &lt;5% &gt;25%</code></pre>
1717
- <p><strong>Recommended for</strong>:</p>
1718
- <ul>
1719
- <li><strong>Production systems</strong> requiring high performance</li>
1720
- <li><strong>Streaming applications</strong> with large data volumes</li>
1721
- <li><strong>Mobile/embedded</strong> systems with limited CPU
1722
- resources</li>
1723
- <li><strong>SIMD-heavy workloads</strong> processing bulk data</li>
1724
- </ul>
1725
- <p>The hardware-optimized approach provides the best practical balance
1726
- for real-world k implementations.</p>
1727
- <hr />
1728
- <hr />
1729
- <h1 id="chapter-7-the-partial-function-abi">Chapter 7 — The Partial
1730
- Function ABI</h1>
1731
- <h2 id="purpose"><strong>7.1 Purpose</strong></h2>
1732
- <p>The <strong>application binary interface (ABI)</strong> defines how
1733
- partial functions in <code>k</code> are represented and invoked at
1734
- runtime. Its goal is to make all functions - whether user-defined or
1735
- compiled - compatible with the same calling convention and data
1736
- layout.</p>
1737
- <p>Every compiled <code>k</code> function receives a single argument (a
1738
- value tree) and may either produce a result or remain undefined. The ABI
1739
- provides a uniform way to express both outcomes.</p>
1740
- <hr />
1741
- <h2 id="function-result-representation"><strong>7.2 Function result
1742
- representation</strong></h2>
1743
- <p>The result of every function call is a pair of fields:</p>
1744
- <div class="sourceCode" id="cb70"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb70-1"><a href="#cb70-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> KOpt <span class="op">{</span></span>
1745
- <span id="cb70-2"><a href="#cb70-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">bool</span> ok<span class="op">;</span> <span class="co">// 1 if function is defined for the given input</span></span>
1746
- <span id="cb70-3"><a href="#cb70-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> KNode<span class="op">*</span> val<span class="op">;</span> <span class="co">// valid only if ok == true</span></span>
1747
- <span id="cb70-4"><a href="#cb70-4" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
1748
- <p>If <code>ok == 1</code>, the function succeeded and <code>val</code>
1749
- points to the root node of the resulting value. If <code>ok == 0</code>,
1750
- the function is undefined for the input, and <code>val</code> is
1751
- meaningless.</p>
1752
- <p>This structure carries both the success flag and the value pointer,
1753
- allowing partiality to be expressed directly in generated code.</p>
1754
- <hr />
1755
- <h2 id="function-parameter-representation"><strong>7.3 Function
1756
- parameter representation</strong></h2>
1757
- <p>Each function takes exactly one parameter:</p>
1758
- <div class="sourceCode" id="cb71"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb71-1"><a href="#cb71-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> KNode<span class="op">*</span> input<span class="op">;</span></span></code></pre></div>
1759
- <p>The parameter points to the root of the input value. Since all values
1760
- are immutable, the function must not modify this structure.</p>
1761
- <hr />
1762
- <h2 id="calling-convention"><strong>7.4 Calling convention</strong></h2>
1763
- <p>Every <code>k</code> function compiled to machine code follows this
1764
- C-style signature:</p>
1765
- <div class="sourceCode" id="cb72"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb72-1"><a href="#cb72-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> KOpt k_function<span class="op">(</span><span class="kw">struct</span> KNode<span class="op">*</span> input<span class="op">);</span></span></code></pre></div>
1766
- <p>The return value indicates success or failure. The convention is
1767
- uniform for all functions, regardless of the specific types
1768
- involved.</p>
1769
- <hr />
1770
- <h2 id="core-runtime-operations"><strong>7.5 Core runtime
1771
- operations</strong></h2>
1772
- <p>The runtime provides a small set of primitive functions implementing
1773
- the fundamental operations of <code>k</code>:</p>
1774
- <table>
1775
- <colgroup>
1776
- <col style="width: 32%" />
1777
- <col style="width: 25%" />
1778
- <col style="width: 42%" />
1779
- </colgroup>
1780
- <thead>
1781
- <tr>
1782
- <th>Operation</th>
1783
- <th>Purpose</th>
1784
- <th>Result</th>
1785
- </tr>
1786
- </thead>
1787
- <tbody>
1788
- <tr>
1789
- <td><code>k_project(input, label_id)</code></td>
1790
- <td>projection <code>.label</code></td>
1791
- <td>defined if the field or variant <code>label_id</code> exists</td>
1792
- </tr>
1793
- <tr>
1794
- <td><code>k_make_product(state, children[], n)</code></td>
1795
- <td>construct a product node</td>
1796
- <td>always defined</td>
1797
- </tr>
1798
- <tr>
1799
- <td><code>k_make_union(state, tag, child)</code></td>
1800
- <td>construct a union node</td>
1801
- <td>always defined</td>
1802
- </tr>
1803
- <tr>
1804
- <td><code>k_fail()</code></td>
1805
- <td>represent undefined result</td>
1806
- <td>returns <code>{ ok = 0 }</code></td>
1807
- </tr>
1808
- <tr>
1809
- <td><code>k_unit()</code></td>
1810
- <td>return the constant unit node</td>
1811
- <td>returns <code>{ ok = 1, val = &amp;unit_node }</code></td>
1812
- </tr>
1813
- </tbody>
1814
- </table>
1815
- <p>All user-defined functions can be compiled entirely in terms of these
1816
- operations.</p>
1817
- <hr />
1818
- <h2 id="metadata-tables"><strong>7.6 Metadata tables</strong></h2>
1819
- <p>To interpret or construct nodes correctly, the runtime holds constant
1820
- tables derived from canonical type definitions:</p>
1821
- <ul>
1822
- <li><code>state_kind[state]</code> — <code>0</code> for product,
1823
- <code>1</code> for union,</li>
1824
- <li><code>state_arity[state]</code> — number of child fields for
1825
- products (always 1 for unions),</li>
1826
- <li><code>field_index[state][label_id]</code> — index of field in
1827
- product (or <code>-1</code> if absent),</li>
1828
- <li><code>variant_index[state][label_id]</code> — index of variant in
1829
- union (or <code>-1</code> if absent).</li>
1830
- </ul>
1831
- <p>These tables are read-only and known at compile time for each
1832
- canonical type.</p>
1833
- <hr />
1834
- <h2 id="example-projection"><strong>7.7 Example:
1835
- projection</strong></h2>
1836
- <p>To implement the projection <code>.x</code>:</p>
1837
- <div class="sourceCode" id="cb73"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb73-1"><a href="#cb73-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> KOpt k_project_x<span class="op">(</span><span class="kw">struct</span> KNode<span class="op">*</span> input<span class="op">)</span> <span class="op">{</span></span>
1838
- <span id="cb73-2"><a href="#cb73-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> state <span class="op">=</span> input<span class="op">-&gt;</span>state<span class="op">;</span></span>
1839
- <span id="cb73-3"><a href="#cb73-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> kind <span class="op">=</span> state_kind<span class="op">[</span>state<span class="op">];</span></span>
1840
- <span id="cb73-4"><a href="#cb73-4" aria-hidden="true" tabindex="-1"></a></span>
1841
- <span id="cb73-5"><a href="#cb73-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>kind <span class="op">==</span> PRODUCT<span class="op">)</span> <span class="op">{</span></span>
1842
- <span id="cb73-6"><a href="#cb73-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> idx <span class="op">=</span> field_index<span class="op">[</span>state<span class="op">][</span><span class="st">&quot;x&quot;</span><span class="op">];</span></span>
1843
- <span id="cb73-7"><a href="#cb73-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>idx <span class="op">&lt;</span> <span class="dv">0</span> <span class="op">||</span> idx <span class="op">&gt;=</span> input<span class="op">-&gt;</span>arity<span class="op">)</span></span>
1844
- <span id="cb73-8"><a href="#cb73-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">(</span><span class="kw">struct</span> KOpt<span class="op">){</span><span class="dv">0</span><span class="op">,</span> NULL<span class="op">};</span></span>
1845
- <span id="cb73-9"><a href="#cb73-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">(</span><span class="kw">struct</span> KOpt<span class="op">){</span><span class="dv">1</span><span class="op">,</span> input<span class="op">-&gt;</span>child<span class="op">[</span>idx<span class="op">]};</span></span>
1846
- <span id="cb73-10"><a href="#cb73-10" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
1847
- <span id="cb73-11"><a href="#cb73-11" aria-hidden="true" tabindex="-1"></a></span>
1848
- <span id="cb73-12"><a href="#cb73-12" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>kind <span class="op">==</span> UNION<span class="op">)</span> <span class="op">{</span></span>
1849
- <span id="cb73-13"><a href="#cb73-13" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> tag <span class="op">=</span> variant_index<span class="op">[</span>state<span class="op">][</span><span class="st">&quot;x&quot;</span><span class="op">];</span></span>
1850
- <span id="cb73-14"><a href="#cb73-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>tag <span class="op">&lt;</span> <span class="dv">0</span> <span class="op">||</span> input<span class="op">-&gt;</span>tag <span class="op">!=</span> tag<span class="op">)</span></span>
1851
- <span id="cb73-15"><a href="#cb73-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">(</span><span class="kw">struct</span> KOpt<span class="op">){</span><span class="dv">0</span><span class="op">,</span> NULL<span class="op">};</span></span>
1852
- <span id="cb73-16"><a href="#cb73-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">(</span><span class="kw">struct</span> KOpt<span class="op">){</span><span class="dv">1</span><span class="op">,</span> input<span class="op">-&gt;</span>child<span class="op">[</span><span class="dv">0</span><span class="op">]};</span></span>
1853
- <span id="cb73-17"><a href="#cb73-17" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
1854
- <span id="cb73-18"><a href="#cb73-18" aria-hidden="true" tabindex="-1"></a></span>
1855
- <span id="cb73-19"><a href="#cb73-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">(</span><span class="kw">struct</span> KOpt<span class="op">){</span><span class="dv">0</span><span class="op">,</span> NULL<span class="op">};</span></span>
1856
- <span id="cb73-20"><a href="#cb73-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
1857
- <p>This code demonstrates the generic principle: the projection is
1858
- defined if and only if the input has a field or variant named
1859
- <code>x</code>.</p>
1860
- <hr />
1861
- <h2 id="error-propagation"><strong>7.8 Error propagation</strong></h2>
1862
- <p>When one function calls another, the success flag <code>ok</code>
1863
- propagates forward. If a subcall returns <code>ok == 0</code>, the
1864
- caller must return <code>{0, NULL}</code> immediately. This makes
1865
- undefinedness explicit and local—no exceptions, no global flags.</p>
1866
- <hr />
1867
- <h2 id="summary-5"><strong>7.9 Summary</strong></h2>
1868
- <ul>
1869
- <li>Every function has the form <code>KOpt f(KNode*)</code>.</li>
1870
- <li>Partiality is expressed by the <code>ok</code> flag.</li>
1871
- <li>Runtime operations handle projection and construction.</li>
1872
- <li>Metadata tables describe field positions and variant indices.</li>
1873
- <li>By inspecting <code>arity</code>, <code>state</code>, and
1874
- <code>tag</code>, the runtime can interpret any value correctly.</li>
1875
- <li>This ABI ensures all generated and runtime functions can
1876
- interoperate safely.</li>
1877
- </ul>
1878
- <hr />
1879
- <hr />
1880
- <h1 id="chapter-8-operational-semantics-and-execution">Chapter 8 —
1881
- Operational Semantics and Execution</h1>
1882
- <h2 id="purpose-1"><strong>8.1 Purpose</strong></h2>
1883
- <p>The <strong>operational semantics</strong> of <code>k</code> describe
1884
- how expressions are evaluated step by step on actual value trees. It
1885
- defines when a function is <em>defined</em> for a particular input and
1886
- what value it returns. All execution—interpretive or compiled—follows
1887
- these rules.</p>
1888
- <hr />
1889
- <h2 id="evaluation-relation"><strong>8.2 Evaluation
1890
- relation</strong></h2>
1891
- <p>Evaluation is written as:</p>
1892
- <pre class="text"><code>⟨ e , v ⟩ ⇓ r</code></pre>
1893
- <p>meaning that expression <code>e</code> applied to value
1894
- <code>v</code> yields result <code>r</code>. If <code>e</code> is
1895
- undefined for <code>v</code>, the relation does not hold.</p>
1896
- <p><code>r</code> is always a tree (or node) in memory, represented as
1897
- described in Chapter 6. Undefined results are expressed by the absence
1898
- of any rule that produces <code>r</code>.</p>
1899
- <hr />
1900
- <h2 id="rules-for-base-expressions"><strong>8.3 Rules for base
1901
- expressions</strong></h2>
1902
- <h3 id="identity"><strong>Identity</strong></h3>
1903
- <pre class="text"><code>⟨ () , v ⟩ ⇓ v</code></pre>
1904
- <p>The empty composition <code>()</code> returns its argument
1905
- unchanged.</p>
1906
- <h3 id="projection"><strong>Projection</strong></h3>
1907
- <p>Let <code>label</code> be a field or variant name. If <code>v</code>
1908
- has a child under <code>label</code>,</p>
1909
- <pre class="text"><code>⟨ .label , v ⟩ ⇓ v.label</code></pre>
1910
- <p>Otherwise the projection is undefined.</p>
1911
- <h3 id="type-expression"><strong>Type expression</strong></h3>
1912
- <p>For a type <code>T</code>,</p>
1913
- <pre class="text"><code>⟨ $T , v ⟩ ⇓ v if v ∈ T</code></pre>
1914
- <p>and undefined otherwise. Type expressions thus act as identity
1915
- functions restricted to their type.</p>
1916
- <hr />
1917
- <h2 id="rules-for-composition"><strong>8.4 Rules for
1918
- composition</strong></h2>
1919
- <h3 id="sequential-composition"><strong>Sequential
1920
- composition</strong></h3>
1921
- <pre class="text"><code>⟨ (f g) , v ⟩ ⇓ r</code></pre>
1922
- <p>if there exists <code>u</code> such that <code>⟨ f , v ⟩ ⇓ u</code>
1923
- and <code>⟨ g , u ⟩ ⇓ r</code>.</p>
1924
- <p>If either step is undefined, the composition is undefined. Because
1925
- composition is associative,</p>
1926
- <pre class="text"><code>(f (g h)) ≡ ((f g) h) ≡ (f g h)</code></pre>
1927
- <p>Parentheses are needed only for <code>()</code>.</p>
1928
- <hr />
1929
- <h2 id="rules-for-product-composition"><strong>8.5 Rules for product
1930
- composition</strong></h2>
1931
- <pre class="text"><code>⟨ { f₁ l₁ , f₂ l₂ , … , fₙ lₙ } , v ⟩ ⇓ { r₁ l₁ , r₂ l₂ , … , rₙ lₙ }</code></pre>
1932
- <p>if and only if all subfunctions <code>fᵢ</code> are defined on
1933
- <code>v</code> and yield <code>rᵢ</code>. If any subfunction is
1934
- undefined, the whole product composition is undefined.</p>
1935
- <p>A product composition constructs a new product node; each result
1936
- <code>rᵢ</code> becomes one child in canonical field order.</p>
1937
- <hr />
1938
- <h2 id="rules-for-union-composition"><strong>8.6 Rules for union
1939
- composition</strong></h2>
1940
- <pre class="text"><code>⟨ &lt; f₁ , f₂ , … , fₙ &gt; , v ⟩ ⇓ rⱼ</code></pre>
1941
- <p>if there exists the smallest index <code>j</code> such that
1942
- <code>⟨ fⱼ , v ⟩ ⇓ rⱼ</code>.</p>
1943
- <p>If no subfunction is defined, the union composition is undefined.</p>
1944
- <hr />
1945
- <h2 id="rules-for-filters"><strong>8.7 Rules for filters</strong></h2>
1946
- <p>If a filter <code>F</code> matches a single type <code>T</code></p>
1947
- <pre class="text"><code>⟨ ?F , v ⟩ ⇓ ⟨ $T , v ⟩ </code></pre>
1948
- <p>otherwise it is an identity</p>
1949
- <pre class="text"><code>⟨ ?F , v ⟩ ⇓ v</code></pre>
1950
- <p>Filters therefore act as compile time annotations for type checking
1951
- only. They are ignored at run-time, unless they lead to fully typed
1952
- expressions (i.e., can be replaced by a type).</p>
1953
- <hr />
1954
- <h2 id="evaluation-order"><strong>8.8 Evaluation order</strong></h2>
1955
- <p>Evaluation proceeds left to right. In products, all subfunctions
1956
- receive the same input; in unions, later functions are evaluated only if
1957
- earlier ones fail.</p>
1958
- <p>The semantics are deterministic: for any given input, at most one
1959
- result tree can be produced.</p>
1960
- <hr />
1961
- <h2 id="example-1"><strong>8.9 Example</strong></h2>
1962
- <p>Given:</p>
1963
- <pre class="k-lang"><code>$bool = &lt; {} true, {} false &gt;;
1964
- neg = $bool &lt; .true {{ } false}, .false {{ } true} &gt; $bool;</code></pre>
1965
- <p>and input value <code>{ {} true }</code> of type <code>bool</code>,
1966
- evaluation steps are:</p>
1967
- <ol type="1">
1968
- <li><code>⟨ $bool , { {} true } ⟩ ⇓ { {} true }</code></li>
1969
- <li><code>⟨ &lt; .true {{ } false}, .false {{ } true} &gt; , { {} true } ⟩ ⇓ {{ } false}</code></li>
1970
- <li><code>⟨ $bool , {{ } false} ⟩ ⇓ {{ } false}</code></li>
1971
- </ol>
1972
- <p>Final result: <code>{{ } false}</code>. If the input were of another
1973
- type, step 1 would be undefined.</p>
1974
- <hr />
1975
- <h2 id="implementation-correspondence"><strong>8.10 Implementation
1976
- correspondence</strong></h2>
1977
- <p>The evaluation rules map directly onto the runtime ABI:</p>
1978
- <table>
1979
- <thead>
1980
- <tr>
1981
- <th>Semantic rule</th>
1982
- <th>Runtime operation</th>
1983
- </tr>
1984
- </thead>
1985
- <tbody>
1986
- <tr>
1987
- <td>Projection</td>
1988
- <td><code>k_project</code></td>
1989
- </tr>
1990
- <tr>
1991
- <td>Product composition</td>
1992
- <td>multiple subcalls + <code>k_make_product</code></td>
1993
- </tr>
1994
- <tr>
1995
- <td>Union composition</td>
1996
- <td>sequential subcalls with early return</td>
1997
- </tr>
1998
- <tr>
1999
- <td>Type</td>
2000
- <td>runtime check of <code>state</code></td>
2001
- </tr>
2002
- <tr>
2003
- <td>Composition</td>
2004
- <td>function call chain</td>
2005
- </tr>
2006
- </tbody>
2007
- </table>
2008
- <p>In compiled form, the <code>ok</code> flag of <code>KOpt</code>
2009
- represents whether a rule applies; the node pointer represents the
2010
- result value.</p>
2011
- <hr />
2012
- <h2 id="summary-6"><strong>8.11 Summary</strong></h2>
2013
- <ul>
2014
- <li>Execution follows deterministic, left-to-right rules.</li>
2015
- <li>All expressions denote partial functions on value trees.</li>
2016
- <li>Type expressions act as restricted identities.</li>
2017
- <li>Composition is associative; undefined propagates automatically.</li>
2018
- <li>Runtime semantics match the formal evaluation relation exactly.</li>
2019
- </ul>
2020
- <hr />
2021
- <hr />
2022
- <h1 id="chapter-9-compiler-architecture">Chapter 9 — Compiler
2023
- Architecture</h1>
2024
- <h2 id="what-the-compiler-does"><strong>9.1 What the compiler
2025
- does</strong></h2>
2026
- <p>A <em>compiler</em> for the <code>k</code> language is a program that
2027
- reads another program (written in <code>k</code>) and produces a
2028
- lower-level version of it. The lower-level version can then be executed
2029
- efficiently by a computer.</p>
2030
- <p>For <code>k</code>, the compiler’s task is simple in concept:</p>
2031
- <ol type="1">
2032
- <li><strong>Read</strong> the definitions of types and functions.</li>
2033
- <li><strong>Understand</strong> their structure and the relationships
2034
- between them.</li>
2035
- <li><strong>Translate</strong> them into equivalent instructions that
2036
- follow the runtime conventions described in Chapters 6–8.</li>
2037
- </ol>
2038
- <p>The compiler must ensure that every function in the source program
2039
- becomes a machine-level function that behaves in exactly the same way:
2040
- it takes a value as input, may or may not be defined for it, and, if
2041
- defined, produces another value.</p>
2042
- <hr />
2043
- <h2 id="the-main-stages"><strong>9.2 The main stages</strong></h2>
2044
- <p>A <code>k</code> compiler is organized as a sequence of well-defined
2045
- stages. Each stage transforms one representation of the program into
2046
- another, simpler one.</p>
2047
- <ol type="1">
2048
- <li><p><strong>Reading and parsing</strong> — The compiler converts the
2049
- source text into a tree of syntactic objects. This tree is called the
2050
- <em>abstract syntax tree</em> (AST). It records the structure of
2051
- expressions such as <code>{ .x a, .y b }</code> or
2052
- <code>&lt; .x, .y &gt;</code>.</p></li>
2053
- <li><p><strong>Type analysis and normalization</strong> — The compiler
2054
- expands type names, checks their correctness, and replaces all filters
2055
- and meta-variables by concrete type information, following the procedure
2056
- from Chapter 5. The result is a fully typed AST.</p></li>
2057
- <li><p><strong>Preparation for execution</strong> — The compiler builds
2058
- a <em>type table</em> for all canonical type states (C0, C1, …). For
2059
- each type, it records whether it is a product or a union and the number
2060
- and names of its fields or variants. These tables become the metadata
2061
- used at runtime.</p></li>
2062
- <li><p><strong>Code generation</strong> — Finally, the compiler walks
2063
- through the typed AST and produces an equivalent description in a
2064
- lower-level form that follows the runtime conventions: functions
2065
- returning a success flag and a value pointer. This form can be expressed
2066
- directly in C or in the <em>LLVM intermediate representation</em>, which
2067
- is a platform-independent format understood by many compilers.</p></li>
2068
- </ol>
2069
- <hr />
2070
- <h2 id="internal-structure"><strong>9.3 Internal structure</strong></h2>
2071
- <p>A minimal compiler can be viewed as three connected modules:</p>
2072
- <ul>
2073
- <li><strong>Front end</strong> — reads source code, builds the AST,
2074
- performs type analysis.</li>
2075
- <li><strong>Middle</strong> — resolves all references, normalizes types,
2076
- and simplifies expressions.</li>
2077
- <li><strong>Back end</strong> — produces the executable form.</li>
2078
- </ul>
2079
- <p>Although these terms are traditional, the distinction is simple: the
2080
- front end <em>understands</em> the program, the back end <em>emits</em>
2081
- it, and the middle part connects the two.</p>
2082
- <hr />
2083
- <h2 id="data-kept-by-the-compiler"><strong>9.4 Data kept by the
2084
- compiler</strong></h2>
2085
- <p>During translation the compiler maintains several tables:</p>
2086
- <table>
2087
- <colgroup>
2088
- <col style="width: 21%" />
2089
- <col style="width: 78%" />
2090
- </colgroup>
2091
- <thead>
2092
- <tr>
2093
- <th>Name</th>
2094
- <th>Purpose</th>
2095
- </tr>
2096
- </thead>
2097
- <tbody>
2098
- <tr>
2099
- <td><strong>Type table</strong></td>
2100
- <td>Maps type names to canonical forms and assigns numeric state
2101
- IDs.</td>
2102
- </tr>
2103
- <tr>
2104
- <td><strong>Field table</strong></td>
2105
- <td>For each product type, records the order and index of its
2106
- fields.</td>
2107
- </tr>
2108
- <tr>
2109
- <td><strong>Variant table</strong></td>
2110
- <td>For each union type, records the tags and their numeric
2111
- indices.</td>
2112
- </tr>
2113
- <tr>
2114
- <td><strong>Function table</strong></td>
2115
- <td>Associates function names with their input and output types.</td>
2116
- </tr>
2117
- </tbody>
2118
- </table>
2119
- <p>These tables ensure that generated code can find fields and variants
2120
- by number rather than by name, which simplifies execution.</p>
2121
- <hr />
2122
- <h2 id="example-of-transformation"><strong>9.5 Example of
2123
- transformation</strong></h2>
2124
- <p>Consider a simple k program:</p>
2125
- <pre class="k-lang"><code>$bool = &lt; {} true, {} false &gt;;
2126
- neg = $bool &lt; /true | false, /false | true &gt; $bool;</code></pre>
2127
- <ol type="1">
2128
- <li><p><strong>Parsing:</strong> The compiler recognizes a type
2129
- definition <code>$bool</code> and a function <code>neg</code>.</p></li>
2130
- <li><p><strong>Type analysis:</strong> Both the input and output of
2131
- <code>neg</code> are of type <code>bool</code>.</p></li>
2132
- <li><p><strong>Internal representation:</strong> The compiler constructs
2133
- an internal tree describing that
2134
- <code>&lt; /true f₁, /false f₂ &gt;</code> means: try the projection
2135
- <code>/true</code>, then <code>/false</code>, each producing a constant
2136
- value.</p></li>
2137
- <li><p><strong>Generated form:</strong> In the target language,
2138
- <code>neg</code> becomes a small function that:</p>
2139
- <ul>
2140
- <li>calls <code>k_project</code> to check which variant the input
2141
- has,</li>
2142
- <li>creates a new node with the opposite variant using
2143
- <code>k_make_union</code>, and</li>
2144
- <li>returns the result with <code>ok = 1</code>.</li>
2145
- </ul></li>
2146
- </ol>
2147
- <p>This sequence of steps is fully automatic and follows directly from
2148
- the semantic rules in Chapter 8.</p>
2149
- <hr />
2150
- <h2 id="intermediate-representation"><strong>9.6 Intermediate
2151
- representation</strong></h2>
2152
- <p>Before producing final code, many compilers use an <em>intermediate
2153
- representation</em> (IR). It is a language designed to be easy to
2154
- generate and easy to translate further into real machine code. For
2155
- <code>k</code>, the IR mirrors the structure of partial functions:</p>
2156
- <table>
2157
- <thead>
2158
- <tr>
2159
- <th>Concept in k</th>
2160
- <th>IR operation</th>
2161
- </tr>
2162
- </thead>
2163
- <tbody>
2164
- <tr>
2165
- <td>Projection <code>.x</code> ‘/x’</td>
2166
- <td><code>PROJECT label_id</code></td>
2167
- </tr>
2168
- <tr>
2169
- <td>Composition <code>(f g)</code></td>
2170
- <td><code>CALL f; CALL g</code></td>
2171
- </tr>
2172
- <tr>
2173
- <td>Union <code>&lt;f,g&gt;</code></td>
2174
- <td><code>TRY f; IF undefined THEN TRY g</code></td>
2175
- </tr>
2176
- <tr>
2177
- <td>Product <code>{.x f, .y g}</code></td>
2178
- <td><code>PRODUCT_CALL (f, g); COMBINE</code></td>
2179
- </tr>
2180
- <tr>
2181
- <td>Type restriction <code>$T</code></td>
2182
- <td><code>CHECK_TYPE state_id</code></td>
2183
- </tr>
2184
- </tbody>
2185
- </table>
2186
- <p>The compiler converts each AST node into one or more IR instructions.
2187
- The <code>PRODUCT_CALL(f, g)</code> instruction is a higher-level
2188
- concept that implies applying both <code>f</code> and <code>g</code> to
2189
- the same input value. The low-level implementation of this would use
2190
- stack operations to duplicate the input, but the IR itself remains more
2191
- abstract. Later, these instructions are translated into LLVM or C code
2192
- using the runtime ABI.</p>
2193
- <hr />
2194
- <h2 id="linking-with-the-runtime"><strong>9.7 Linking with the
2195
- runtime</strong></h2>
2196
- <p>The generated code does not contain memory allocation or type tables
2197
- itself. Instead, it relies on the runtime library (<code>krt</code>),
2198
- which provides:</p>
2199
- <ul>
2200
- <li>functions such as <code>k_project</code> and
2201
- <code>k_make_union</code>,</li>
2202
- <li>metadata tables for each canonical type, and</li>
2203
- <li>the unit value <code>{}</code> shared by all programs.</li>
2204
- </ul>
2205
- <p>When the compiler finishes, it outputs a text file in the target
2206
- language plus references to this runtime library. The two together form
2207
- an executable program.</p>
2208
- <hr />
2209
- <h2 id="simplicity-of-the-model"><strong>9.8 Simplicity of the
2210
- model</strong></h2>
2211
- <p>Because every expression in <code>k</code> takes exactly one input
2212
- and may return one output or be undefined, the compiler never has to
2213
- deal with variable environments, loops, or side effects. This makes the
2214
- structure of the generated program very regular:</p>
2215
- <pre class="text"><code>input → [series of calls and checks] → output or undefined</code></pre>
2216
- <p>Each compiled function is independent and stateless. This regularity
2217
- is what allows <code>k</code> to map cleanly to low-level code.</p>
2218
- <hr />
2219
- <h2 id="summary-7"><strong>9.9 Summary</strong></h2>
2220
- <ul>
2221
- <li>The compiler transforms <code>k</code> programs into executable form
2222
- through a sequence of simple, deterministic steps.</li>
2223
- <li>Type information and structure are resolved before code
2224
- generation.</li>
2225
- <li>All generated functions follow the same calling convention
2226
- (<code>ok</code>, <code>val</code>).</li>
2227
- <li>The runtime library provides the shared operations needed by every
2228
- program.</li>
2229
- <li>The entire process mirrors the formal semantics defined earlier but
2230
- expresses it as concrete machine operations.</li>
2231
- </ul>
2232
- <hr />
2233
- <hr />
2234
- <h1 id="chapter-10-from-ast-to-intermediate-representation">Chapter 10 —
2235
- From AST to Intermediate Representation</h1>
2236
- <h2 id="the-purpose-of-an-intermediate-form"><strong>10.1 The purpose of
2237
- an intermediate form</strong></h2>
2238
- <p>The abstract syntax tree (AST) of a <code>k</code> program directly
2239
- reflects how the source code was written. It is easy to read but not
2240
- convenient for generating machine code. Before code can be produced, the
2241
- compiler rewrites this tree into a <strong>simpler, regular
2242
- structure</strong> called the <em>intermediate representation</em>
2243
- (IR).</p>
2244
- <p>The IR is close to what the machine will execute, but it still looks
2245
- like a structured program rather than raw binary instructions. Each node
2246
- in the IR corresponds to a single, well-defined operation such as
2247
- <em>project a field</em>, <em>apply a function</em>, or <em>combine
2248
- results</em>.</p>
2249
- <p>Using an intermediate form helps in three ways:</p>
2250
- <ol type="1">
2251
- <li>It separates understanding of the language from machine
2252
- details.</li>
2253
- <li>It allows the compiler to verify that every function is well
2254
- formed.</li>
2255
- <li>It provides a uniform surface for optimization and for later
2256
- translation into C or LLVM.</li>
2257
- </ol>
2258
- <hr />
2259
- <h2 id="shape-of-the-intermediate-representation"><strong>10.2 Shape of
2260
- the intermediate representation</strong></h2>
2261
- <p>Each IR instruction corresponds to one semantic rule from Chapter 8.
2262
- The IR does not need to represent filters or meta-variables, since those
2263
- are resolved earlier. Only concrete actions remain.</p>
2264
- <table>
2265
- <colgroup>
2266
- <col style="width: 31%" />
2267
- <col style="width: 68%" />
2268
- </colgroup>
2269
- <thead>
2270
- <tr>
2271
- <th>Operation</th>
2272
- <th>Meaning</th>
2273
- </tr>
2274
- </thead>
2275
- <tbody>
2276
- <tr>
2277
- <td><strong>PROJECT label_id</strong></td>
2278
- <td>Apply <code>.label</code> to the input value.</td>
2279
- </tr>
2280
- <tr>
2281
- <td><strong>TYPECHECK state_id</strong></td>
2282
- <td>Accept the input only if its root has the given canonical
2283
- state.</td>
2284
- </tr>
2285
- <tr>
2286
- <td><strong>CALL function_id</strong></td>
2287
- <td>Invoke another function following the ABI.</td>
2288
- </tr>
2289
- <tr>
2290
- <td><strong>UNION [f₁, f₂, …]</strong></td>
2291
- <td>Try several functions in order until one succeeds.</td>
2292
- </tr>
2293
- <tr>
2294
- <td><strong>PRODUCT [l₁=f₁, l₂=f₂, …]</strong></td>
2295
- <td>Apply each function to the same input and combine results.</td>
2296
- </tr>
2297
- <tr>
2298
- <td><strong>FAIL</strong></td>
2299
- <td>Always undefined.</td>
2300
- </tr>
2301
- <tr>
2302
- <td><strong>SEQ [f₁, f₂, …]</strong></td>
2303
- <td>Apply functions in sequence (composition).</td>
2304
- </tr>
2305
- </tbody>
2306
- </table>
2307
- <p>Each function in the program becomes a small list or tree of such IR
2308
- instructions.</p>
2309
- <hr />
2310
- <h2 id="example-2"><strong>10.3 Example</strong></h2>
2311
- <p>Source program:</p>
2312
- <pre class="k-lang"><code>$bool = &lt; {} true, {} false &gt;;
2313
- neg = $bool &lt; .true {{ } false}, .false {{ } true} &gt; $bool;</code></pre>
2314
- <p>The IR for <code>neg</code> can be written informally as:</p>
2315
- <pre class="text"><code>neg:
2316
- TYPECHECK bool
2317
- UNION [
2318
- SEQ [ PROJECT true, CONST false ],
2319
- SEQ [ PROJECT false, CONST true ]
2320
- ]
2321
- TYPECHECK bool</code></pre>
2322
- <p>This IR expresses the same logic as the source: check the type, then
2323
- try the first projection <code>.true</code>, otherwise the second, and
2324
- finally ensure the result is again of type <code>$bool</code>.</p>
2325
- <hr />
2326
- <h2 id="relation-to-evaluation"><strong>10.4 Relation to
2327
- evaluation</strong></h2>
2328
- <p>Every IR operation corresponds to a runtime action:</p>
2329
- <table>
2330
- <thead>
2331
- <tr>
2332
- <th>IR operation</th>
2333
- <th>Runtime function or behavior</th>
2334
- </tr>
2335
- </thead>
2336
- <tbody>
2337
- <tr>
2338
- <td>PROJECT</td>
2339
- <td><code>k_project(input, label_id)</code></td>
2340
- </tr>
2341
- <tr>
2342
- <td>TYPECHECK</td>
2343
- <td>verify <code>input-&gt;state == state_id</code></td>
2344
- </tr>
2345
- <tr>
2346
- <td>CALL</td>
2347
- <td>call another generated function</td>
2348
- </tr>
2349
- <tr>
2350
- <td>UNION</td>
2351
- <td>sequential <code>if</code>–<code>else</code> test on success
2352
- flags</td>
2353
- </tr>
2354
- <tr>
2355
- <td>PRODUCT</td>
2356
- <td>multiple subcalls + <code>k_make_product</code></td>
2357
- </tr>
2358
- <tr>
2359
- <td>FAIL</td>
2360
- <td>return <code>{ ok = 0 }</code> immediately</td>
2361
- </tr>
2362
- <tr>
2363
- <td>SEQ</td>
2364
- <td>connect the output of one step as input to the next</td>
2365
- </tr>
2366
- </tbody>
2367
- </table>
2368
- <p>By describing computation in these terms, the compiler can generate
2369
- executable code simply by replacing each IR instruction with its runtime
2370
- equivalent.</p>
2371
- <hr />
2372
- <h2 id="building-the-ir"><strong>10.5 Building the IR</strong></h2>
2373
- <p>The process of converting the AST to IR follows a recursive
2374
- pattern:</p>
2375
- <ol type="1">
2376
- <li><strong>Projections</strong> become single instructions
2377
- <code>PROJECT</code>.</li>
2378
- <li><strong>Compositions</strong> <code>(f g h)</code> become a
2379
- <code>SEQ</code> list of their components.</li>
2380
- <li><strong>Unions</strong> <code>&lt;f,g&gt;</code> become a
2381
- <code>UNION</code> list.</li>
2382
- <li><strong>Products</strong> <code>{f l₁, g l₂}</code> become a
2383
- <code>PRODUCT</code> list with labeled entries.</li>
2384
- <li><strong>Type expressions</strong> <code>$T</code> become
2385
- <code>TYPECHECK</code> instructions.</li>
2386
- <li><strong>Filters</strong> disappear; their meaning is already
2387
- captured by typechecks.</li>
2388
- </ol>
2389
- <p>Each transformation step produces IR nodes with fixed behavior and
2390
- explicit order.</p>
2391
- <hr />
2392
- <h2 id="verifying-the-ir"><strong>10.6 Verifying the IR</strong></h2>
2393
- <p>Because k programs are defined by simple composition, a small set of
2394
- checks ensures correctness:</p>
2395
- <ol type="1">
2396
- <li>Each <code>UNION</code> list must have at least one element.</li>
2397
- <li>Every <code>PROJECT</code> must have a valid label.</li>
2398
- <li>Input and output states of consecutive steps must match.</li>
2399
- <li>A function must end in an operation that produces a result
2400
- (<code>PROJECT</code>, <code>CALL</code>, or combination).</li>
2401
- </ol>
2402
- <p>After verification, the IR is guaranteed to represent a valid partial
2403
- function according to the semantics in Chapter 8.</p>
2404
- <hr />
2405
- <h2 id="intermediate-form-as-a-small-language"><strong>10.7 Intermediate
2406
- form as a small language</strong></h2>
2407
- <p>The IR can be viewed as a minimal language on its own. It has:</p>
2408
- <ul>
2409
- <li>one data type (<code>KNode*</code>),</li>
2410
- <li>one universal value format (trees),</li>
2411
- <li>and a fixed set of operators.</li>
2412
- </ul>
2413
- <p>Its execution model is the same as the runtime ABI. This means an
2414
- interpreter for the IR can serve as a reference implementation of the k
2415
- semantics before any machine code generation is added.</p>
2416
- <hr />
2417
- <h2 id="example-product-composition"><strong>10.8 Example: product
2418
- composition</strong></h2>
2419
- <p>For input function <code>{ .x a, .y b }</code>, the IR is:</p>
2420
- <pre class="text"><code>PRODUCT [
2421
- a = PROJECT x,
2422
- b = PROJECT y
2423
- ]</code></pre>
2424
- <p>The runtime sequence is:</p>
2425
- <ol type="1">
2426
- <li>Apply each projection.</li>
2427
- <li>If both succeed, build a new node with two children in order
2428
- <code>(a,b)</code>.</li>
2429
- </ol>
2430
- <p>This pattern covers all record-building operations in the
2431
- language.</p>
2432
- <hr />
2433
- <h2 id="why-this-representation-is-useful"><strong>10.9 Why this
2434
- representation is useful</strong></h2>
2435
- <p>This intermediate form provides three practical benefits:</p>
2436
- <ol type="1">
2437
- <li><strong>Clarity</strong> – every step is explicit and local.</li>
2438
- <li><strong>Verifiability</strong> – type consistency and definedness
2439
- can be checked mechanically.</li>
2440
- <li><strong>Flexibility</strong> – the same IR can be translated to many
2441
- targets (LLVM IR, C, or even interpreted directly).</li>
2442
- </ol>
2443
- <p>Because of these advantages, most compilers for declarative languages
2444
- use an intermediate form of this kind.</p>
2445
- <hr />
2446
- <h2 id="summary-8"><strong>10.10 Summary</strong></h2>
2447
- <ul>
2448
- <li>The abstract syntax tree is rewritten into a simpler,
2449
- machine-oriented form.</li>
2450
- <li>Each IR instruction represents one operation defined by the
2451
- <code>k</code> semantics.</li>
2452
- <li>Type and filter information appear as explicit checks.</li>
2453
- <li>The IR is easy to verify and to translate into executable code.</li>
2454
- <li>The IR can also serve as a precise description of how <code>k</code>
2455
- functions behave step by step.</li>
2456
- </ul>
2457
- <hr />
2458
- <hr />
2459
- <h1 id="chapter-11-llvm-basics">Chapter 11 — LLVM Basics</h1>
2460
- <h2 id="purpose-2"><strong>11.1 Purpose</strong></h2>
2461
- <p>The previous chapters described how a <code>k</code> program can be
2462
- reduced to a small set of intermediate operations. To execute these
2463
- operations efficiently, the compiler must translate them into an actual
2464
- machine language. Instead of generating raw machine code directly, we
2465
- use a common intermediate format called <strong>LLVM IR</strong> (LLVM
2466
- <em>Intermediate Representation</em>).</p>
2467
- <p>LLVM IR is a low-level, strongly typed language that resembles a
2468
- simplified form of assembly. It can be read and written as text,
2469
- analyzed, optimized, and compiled to machine code for almost any
2470
- processor. For the compiler writer, it provides a bridge between
2471
- high-level language semantics and executable programs.</p>
2472
- <hr />
2473
- <h2 id="structure-of-an-llvm-program"><strong>11.2 Structure of an LLVM
2474
- program</strong></h2>
2475
- <p>An LLVM program consists of <strong>global definitions</strong> and
2476
- <strong>functions</strong>.</p>
2477
- <ul>
2478
- <li><p><em>Global definitions</em> describe data structures shared
2479
- between functions. In the <code>k</code> compiler, this includes the
2480
- runtime metadata tables and constant nodes such as
2481
- <code>{}</code>.</p></li>
2482
- <li><p><em>Functions</em> contain sequences of instructions grouped into
2483
- <strong>basic blocks</strong>. A basic block is a straight-line segment
2484
- of code with no branches except at the end. Branches connect blocks,
2485
- forming a control-flow graph.</p></li>
2486
- </ul>
2487
- <p>Each instruction produces a new value; values are immutable once
2488
- created. This property is called <em>single static assignment</em>
2489
- (SSA).</p>
2490
- <hr />
2491
- <h2 id="data-types"><strong>11.3 Data types</strong></h2>
2492
- <p>LLVM provides several primitive types. Only a few are required for
2493
- the <code>k</code> compiler:</p>
2494
- <table>
2495
- <thead>
2496
- <tr>
2497
- <th>LLVM type</th>
2498
- <th>Meaning</th>
2499
- </tr>
2500
- </thead>
2501
- <tbody>
2502
- <tr>
2503
- <td><code>i1</code></td>
2504
- <td>one-bit boolean (used for success flag)</td>
2505
- </tr>
2506
- <tr>
2507
- <td><code>i32</code></td>
2508
- <td>32-bit integer (used for state IDs, indices, tags)</td>
2509
- </tr>
2510
- <tr>
2511
- <td><code>ptr</code> or <code>%T*</code></td>
2512
- <td>pointer to data in memory</td>
2513
- </tr>
2514
- <tr>
2515
- <td><code>%struct {...}</code></td>
2516
- <td>user-defined record (used for <code>KNode</code> and
2517
- <code>KOpt</code>)</td>
2518
- </tr>
2519
- </tbody>
2520
- </table>
2521
- <p>The main structures used by generated code are:</p>
2522
- <div class="sourceCode" id="cb90"><pre
2523
- class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb90-1"><a href="#cb90-1" aria-hidden="true" tabindex="-1"></a><span class="fu">%KNode</span> = <span class="kw">type</span> { <span class="dt">i32</span>, <span class="dt">i32</span>, <span class="dt">i32</span>, [<span class="dv">0</span> x <span class="fu">%KNode</span>*] }</span>
2524
- <span id="cb90-2"><a href="#cb90-2" aria-hidden="true" tabindex="-1"></a><span class="fu">%KVal</span> = <span class="kw">type</span> { <span class="fu">%KNode</span>* }</span>
2525
- <span id="cb90-3"><a href="#cb90-3" aria-hidden="true" tabindex="-1"></a><span class="fu">%KOpt</span> = <span class="kw">type</span> { <span class="dt">i1</span>, <span class="fu">%KVal</span> }</span></code></pre></div>
2526
- <p><code>%KNode</code> represents one tree node in memory;
2527
- <code>%KOpt</code> represents the result of a partial function, with an
2528
- <code>ok</code> flag and a value pointer.</p>
2529
- <hr />
2530
- <h2 id="function-signatures"><strong>11.4 Function
2531
- signatures</strong></h2>
2532
- <p>Every compiled <code>k</code> function is translated into one LLVM
2533
- function with the following signature:</p>
2534
- <div class="sourceCode" id="cb91"><pre
2535
- class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb91-1"><a href="#cb91-1" aria-hidden="true" tabindex="-1"></a><span class="kw">define</span> <span class="fu">%KOpt</span> <span class="fu">@f_name</span>(<span class="fu">%KVal</span> <span class="fu">%in</span>) { ... }</span></code></pre></div>
2536
- <p>The function takes a single argument <code>%in</code>, which holds
2537
- the pointer to the input value. It returns a <code>%KOpt</code>
2538
- structure containing the success flag and the resulting value.</p>
2539
- <p>This mirrors the runtime ABI introduced in Chapter 7. By using the
2540
- same layout, all functions can call each other without conversions.</p>
2541
- <hr />
2542
- <h2 id="control-flow"><strong>11.5 Control flow</strong></h2>
2543
- <p>LLVM IR uses <strong>conditional branches</strong> to express choices
2544
- and <strong>phi-nodes</strong> to merge results from different
2545
- paths.</p>
2546
- <p>A typical pattern for union composition <code>&lt;f,g&gt;</code>
2547
- is:</p>
2548
- <div class="sourceCode" id="cb92"><pre
2549
- class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb92-1"><a href="#cb92-1" aria-hidden="true" tabindex="-1"></a><span class="fu">%r1</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@f</span>(<span class="fu">%in</span>)</span>
2550
- <span id="cb92-2"><a href="#cb92-2" aria-hidden="true" tabindex="-1"></a><span class="fu">%ok1</span> = <span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%r1</span>, <span class="dv">0</span></span>
2551
- <span id="cb92-3"><a href="#cb92-3" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">i1</span> <span class="fu">%ok1</span>, <span class="dt">label</span> <span class="fu">%success</span>, <span class="dt">label</span> <span class="fu">%try_next</span></span>
2552
- <span id="cb92-4"><a href="#cb92-4" aria-hidden="true" tabindex="-1"></a></span>
2553
- <span id="cb92-5"><a href="#cb92-5" aria-hidden="true" tabindex="-1"></a><span class="fu">try_next:</span></span>
2554
- <span id="cb92-6"><a href="#cb92-6" aria-hidden="true" tabindex="-1"></a><span class="fu">%r2</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@g</span>(<span class="fu">%in</span>)</span>
2555
- <span id="cb92-7"><a href="#cb92-7" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">label</span> <span class="fu">%merge</span></span>
2556
- <span id="cb92-8"><a href="#cb92-8" aria-hidden="true" tabindex="-1"></a></span>
2557
- <span id="cb92-9"><a href="#cb92-9" aria-hidden="true" tabindex="-1"></a><span class="fu">success:</span></span>
2558
- <span id="cb92-10"><a href="#cb92-10" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">label</span> <span class="fu">%merge</span></span>
2559
- <span id="cb92-11"><a href="#cb92-11" aria-hidden="true" tabindex="-1"></a></span>
2560
- <span id="cb92-12"><a href="#cb92-12" aria-hidden="true" tabindex="-1"></a><span class="fu">merge:</span></span>
2561
- <span id="cb92-13"><a href="#cb92-13" aria-hidden="true" tabindex="-1"></a><span class="fu">%res</span> = <span class="kw">phi</span> <span class="fu">%KOpt</span> [ <span class="fu">%r1</span>, <span class="fu">%success</span> ], [ <span class="fu">%r2</span>, <span class="fu">%try_next</span> ]</span>
2562
- <span id="cb92-14"><a href="#cb92-14" aria-hidden="true" tabindex="-1"></a><span class="kw">ret</span> <span class="fu">%res</span></span></code></pre></div>
2563
- <p>This code means: try <code>f</code>; if it succeeds, use that result;
2564
- otherwise, try <code>g</code>. The <code>phi</code> instruction chooses
2565
- between values coming from different blocks.</p>
2566
- <hr />
2567
- <h2 id="memory-operations"><strong>11.6 Memory operations</strong></h2>
2568
- <p>Most functions in k do not modify existing nodes; they create new
2569
- ones. Node creation is implemented as calls to runtime functions:</p>
2570
- <div class="sourceCode" id="cb93"><pre
2571
- class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb93-1"><a href="#cb93-1" aria-hidden="true" tabindex="-1"></a><span class="kw">declare</span> <span class="fu">%KVal</span> <span class="fu">@k_make_product</span>(<span class="dt">i32</span> <span class="fu">%state</span>, <span class="dt">i32</span> <span class="fu">%n</span>, <span class="fu">%KVal</span>* <span class="fu">%children</span>)</span>
2572
- <span id="cb93-2"><a href="#cb93-2" aria-hidden="true" tabindex="-1"></a><span class="kw">declare</span> <span class="fu">%KVal</span> <span class="fu">@k_make_union</span>(<span class="dt">i32</span> <span class="fu">%state</span>, <span class="dt">i32</span> <span class="fu">%tag</span>, <span class="fu">%KVal</span> <span class="fu">%child</span>)</span></code></pre></div>
2573
- <p>These calls allocate new immutable nodes. The compiler provides the
2574
- correct <code>state</code>, <code>tag</code>, and child references
2575
- according to the canonical type.</p>
2576
- <hr />
2577
- <h2 id="constants-1"><strong>11.7 Constants</strong></h2>
2578
- <p>Constant values such as <code>{{} true}</code> are represented as
2579
- global variables in LLVM:</p>
2580
- <div class="sourceCode" id="cb94"><pre
2581
- class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb94-1"><a href="#cb94-1" aria-hidden="true" tabindex="-1"></a><span class="fu">@unit_node</span> = <span class="kw">constant</span> <span class="fu">%KNode</span> { <span class="dv">1</span>, -<span class="dv">1</span>, <span class="dv">0</span>, [] }</span>
2582
- <span id="cb94-2"><a href="#cb94-2" aria-hidden="true" tabindex="-1"></a><span class="fu">@true_node</span> = <span class="kw">constant</span> <span class="fu">%KNode</span> { <span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">1</span>, [<span class="fu">@unit_node</span>] }</span>
2583
- <span id="cb94-3"><a href="#cb94-3" aria-hidden="true" tabindex="-1"></a><span class="fu">@false_node</span> = <span class="kw">constant</span> <span class="fu">%KNode</span> { <span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">1</span>, [<span class="fu">@unit_node</span>] }</span></code></pre></div>
2584
- <p>Each constant is a fully formed node with fixed fields. When a
2585
- constant function is called, the compiler returns a pointer to the
2586
- corresponding global node.</p>
2587
- <hr />
2588
- <h2 id="from-ir-to-llvm"><strong>11.8 From IR to LLVM</strong></h2>
2589
- <p>Translating the compiler’s intermediate form (Chapter 10) into LLVM
2590
- is mechanical:</p>
2591
- <table>
2592
- <colgroup>
2593
- <col style="width: 18%" />
2594
- <col style="width: 81%" />
2595
- </colgroup>
2596
- <thead>
2597
- <tr>
2598
- <th>IR operation</th>
2599
- <th>LLVM translation</th>
2600
- </tr>
2601
- </thead>
2602
- <tbody>
2603
- <tr>
2604
- <td><code>PROJECT</code></td>
2605
- <td>call <code>@k_project</code></td>
2606
- </tr>
2607
- <tr>
2608
- <td><code>TYPECHECK</code></td>
2609
- <td>compare <code>input-&gt;state</code> with constant</td>
2610
- </tr>
2611
- <tr>
2612
- <td><code>CONST</code></td>
2613
- <td>return constant node</td>
2614
- </tr>
2615
- <tr>
2616
- <td><code>PRODUCT</code></td>
2617
- <td>evaluate subcalls, check flags, call
2618
- <code>@k_make_product</code></td>
2619
- </tr>
2620
- <tr>
2621
- <td><code>UNION</code></td>
2622
- <td>generate branching structure as above</td>
2623
- </tr>
2624
- <tr>
2625
- <td><code>SEQ</code></td>
2626
- <td>chain calls: feed output to next input</td>
2627
- </tr>
2628
- <tr>
2629
- <td><code>FAIL</code></td>
2630
- <td>return <code>%KOpt { 0, undef }</code></td>
2631
- </tr>
2632
- </tbody>
2633
- </table>
2634
- <p>These mappings produce correct, low-level code while remaining
2635
- faithful to the language semantics.</p>
2636
- <hr />
2637
- <h2 id="example-3"><strong>11.9 Example</strong></h2>
2638
- <p>For the function <code>neg</code> from earlier:</p>
2639
- <pre class="k-lang"><code>$bool = &lt; {} true, {} false &gt;;
2640
- neg = $bool &lt; .true {{ } false}, .false {{ } true} &gt; $bool;</code></pre>
2641
- <p>The simplified LLVM version may look as follows (comments added):</p>
2642
- <div class="sourceCode" id="cb96"><pre
2643
- class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb96-1"><a href="#cb96-1" aria-hidden="true" tabindex="-1"></a><span class="kw">define</span> <span class="fu">%KOpt</span> <span class="fu">@neg</span>(<span class="fu">%KVal</span> <span class="fu">%in</span>) {</span>
2644
- <span id="cb96-2"><a href="#cb96-2" aria-hidden="true" tabindex="-1"></a><span class="fu">entry:</span></span>
2645
- <span id="cb96-3"><a href="#cb96-3" aria-hidden="true" tabindex="-1"></a> <span class="co">; Try the .true branch</span></span>
2646
- <span id="cb96-4"><a href="#cb96-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">%r1</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@project_true</span>(<span class="fu">%in</span>)</span>
2647
- <span id="cb96-5"><a href="#cb96-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">%ok1</span> = <span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%r1</span>, <span class="dv">0</span></span>
2648
- <span id="cb96-6"><a href="#cb96-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">br</span> <span class="dt">i1</span> <span class="fu">%ok1</span>, <span class="dt">label</span> <span class="fu">%case_true</span>, <span class="dt">label</span> <span class="fu">%case_false</span></span>
2649
- <span id="cb96-7"><a href="#cb96-7" aria-hidden="true" tabindex="-1"></a></span>
2650
- <span id="cb96-8"><a href="#cb96-8" aria-hidden="true" tabindex="-1"></a><span class="fu">case_true:</span></span>
2651
- <span id="cb96-9"><a href="#cb96-9" aria-hidden="true" tabindex="-1"></a> <span class="fu">%res_true</span> = <span class="kw">insertvalue</span> <span class="fu">%KOpt</span> <span class="kw">undef</span>, <span class="dt">i1</span> <span class="dv">1</span>, <span class="dv">0</span></span>
2652
- <span id="cb96-10"><a href="#cb96-10" aria-hidden="true" tabindex="-1"></a> <span class="fu">%res_true2</span> = <span class="kw">insertvalue</span> <span class="fu">%KOpt</span> <span class="fu">%res_true</span>, <span class="fu">%KVal</span> <span class="fu">@false_node</span>, <span class="dv">1</span></span>
2653
- <span id="cb96-11"><a href="#cb96-11" aria-hidden="true" tabindex="-1"></a> <span class="kw">ret</span> <span class="fu">%KOpt</span> <span class="fu">%res_true2</span></span>
2654
- <span id="cb96-12"><a href="#cb96-12" aria-hidden="true" tabindex="-1"></a></span>
2655
- <span id="cb96-13"><a href="#cb96-13" aria-hidden="true" tabindex="-1"></a><span class="fu">case_false:</span></span>
2656
- <span id="cb96-14"><a href="#cb96-14" aria-hidden="true" tabindex="-1"></a> <span class="fu">%r2</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@project_false</span>(<span class="fu">%in</span>)</span>
2657
- <span id="cb96-15"><a href="#cb96-15" aria-hidden="true" tabindex="-1"></a> <span class="fu">%ok2</span> = <span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%r2</span>, <span class="dv">0</span></span>
2658
- <span id="cb96-16"><a href="#cb96-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">br</span> <span class="dt">i1</span> <span class="fu">%ok2</span>, <span class="dt">label</span> <span class="fu">%case_false_valid</span>, <span class="dt">label</span> <span class="fu">%undefined</span></span>
2659
- <span id="cb96-17"><a href="#cb96-17" aria-hidden="true" tabindex="-1"></a></span>
2660
- <span id="cb96-18"><a href="#cb96-18" aria-hidden="true" tabindex="-1"></a><span class="fu">case_false_valid:</span></span>
2661
- <span id="cb96-19"><a href="#cb96-19" aria-hidden="true" tabindex="-1"></a> <span class="fu">%res_false</span> = <span class="kw">insertvalue</span> <span class="fu">%KOpt</span> <span class="kw">undef</span>, <span class="dt">i1</span> <span class="dv">1</span>, <span class="dv">0</span></span>
2662
- <span id="cb96-20"><a href="#cb96-20" aria-hidden="true" tabindex="-1"></a> <span class="fu">%res_false2</span> = <span class="kw">insertvalue</span> <span class="fu">%KOpt</span> <span class="fu">%res_false</span>, <span class="fu">%KVal</span> <span class="fu">@true_node</span>, <span class="dv">1</span></span>
2663
- <span id="cb96-21"><a href="#cb96-21" aria-hidden="true" tabindex="-1"></a> <span class="kw">ret</span> <span class="fu">%KOpt</span> <span class="fu">%res_false2</span></span>
2664
- <span id="cb96-22"><a href="#cb96-22" aria-hidden="true" tabindex="-1"></a></span>
2665
- <span id="cb96-23"><a href="#cb96-23" aria-hidden="true" tabindex="-1"></a><span class="fu">undefined:</span></span>
2666
- <span id="cb96-24"><a href="#cb96-24" aria-hidden="true" tabindex="-1"></a> <span class="kw">ret</span> <span class="fu">%KOpt</span> { <span class="dt">i1</span> <span class="dv">0</span>, <span class="fu">%KVal</span> <span class="kw">undef</span> }</span>
2667
- <span id="cb96-25"><a href="#cb96-25" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
2668
- <p>While verbose, this code mirrors the evaluation rules exactly and can
2669
- be optimized by standard LLVM tools.</p>
2670
- <hr />
2671
- <h2 id="optimization-and-verification"><strong>11.10 Optimization and
2672
- verification</strong></h2>
2673
- <p>LLVM provides built-in passes that simplify generated code:</p>
2674
- <ul>
2675
- <li><strong>mem2reg</strong> — removes unnecessary memory
2676
- operations,</li>
2677
- <li><strong>instcombine</strong> — merges simple operations,</li>
2678
- <li><strong>gvn</strong> — removes redundant calculations,</li>
2679
- <li><strong>simplifycfg</strong> — cleans up control flow.</li>
2680
- </ul>
2681
- <p>The compiler can run these passes automatically to produce compact
2682
- and efficient output. LLVM also verifies that all types and values are
2683
- consistent before emitting machine code.</p>
2684
- <hr />
2685
- <h2 id="summary-9"><strong>11.11 Summary</strong></h2>
2686
- <ul>
2687
- <li>LLVM IR is a portable, low-level language ideal for code
2688
- generation.</li>
2689
- <li>Every <code>k</code> function becomes an LLVM function returning the
2690
- pair <code>{ok, value}</code>.</li>
2691
- <li>All constants, type checks, and runtime calls are represented
2692
- explicitly.</li>
2693
- <li>The translation from <code>k</code>’s intermediate form to LLVM is
2694
- direct and systematic.</li>
2695
- <li>Standard LLVM tools can then optimize and compile the result into
2696
- executable machine code.</li>
2697
- </ul>
2698
- <hr />
2699
- <hr />
2700
- <h1 id="chapter-12-code-generation">Chapter 12 — Code Generation</h1>
2701
- <h2 id="purpose-3"><strong>12.1 Purpose</strong></h2>
2702
- <p>The <strong>code generation</strong> phase translates the
2703
- intermediate representation (IR) of each k function into executable code
2704
- using the LLVM format described in Chapter 11. This translation is
2705
- systematic: every IR operation corresponds to a specific sequence of
2706
- LLVM instructions or calls to the runtime library.</p>
2707
- <p>The compiler’s objective is to produce code that behaves exactly like
2708
- the formal semantics of k—no more and no less. Each step of the
2709
- translation can therefore be viewed as a mechanical implementation of
2710
- one of the rules introduced in Chapter 8.</p>
2711
- <hr />
2712
- <h2 id="structure-of-generated-functions"><strong>12.2 Structure of
2713
- generated functions</strong></h2>
2714
- <p>Each k function becomes a stand-alone LLVM function with the
2715
- signature:</p>
2716
- <div class="sourceCode" id="cb97"><pre
2717
- class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb97-1"><a href="#cb97-1" aria-hidden="true" tabindex="-1"></a><span class="kw">define</span> <span class="fu">%KOpt</span> <span class="fu">@f_name</span>(<span class="fu">%KVal</span> <span class="fu">%in</span>)</span></code></pre></div>
2718
- <p>Internally, the function has one or more <em>basic blocks</em>. Each
2719
- block performs a small action: a projection, a check, a call, or a node
2720
- construction. Blocks are connected by explicit branches that depend on
2721
- the <code>ok</code> flag of intermediate results.</p>
2722
- <p>At the end of the function, exactly one <code>%KOpt</code> value is
2723
- returned.</p>
2724
- <hr />
2725
- <h2 id="translating-core-operations"><strong>12.3 Translating core
2726
- operations</strong></h2>
2727
- <p>The compiler maintains a mapping from IR operations (Chapter 10) to
2728
- LLVM code patterns.</p>
2729
- <table>
2730
- <colgroup>
2731
- <col style="width: 21%" />
2732
- <col style="width: 78%" />
2733
- </colgroup>
2734
- <thead>
2735
- <tr>
2736
- <th>IR Operation</th>
2737
- <th>Generated Code Pattern</th>
2738
- </tr>
2739
- </thead>
2740
- <tbody>
2741
- <tr>
2742
- <td><strong>PROJECT label</strong></td>
2743
- <td><code>call %KOpt @k_project(%KVal %in, i32 label_id)</code></td>
2744
- </tr>
2745
- <tr>
2746
- <td><strong>TYPECHECK state</strong></td>
2747
- <td>Compare <code>input-&gt;state</code> with constant
2748
- <code>state</code>; if unequal, return <code>{0, undef}</code></td>
2749
- </tr>
2750
- <tr>
2751
- <td><strong>CONST node</strong></td>
2752
- <td>Return <code>{1, node_pointer}</code></td>
2753
- </tr>
2754
- <tr>
2755
- <td><strong>SEQ [f₁,f₂,…]</strong></td>
2756
- <td>Emit each function call in order, test <code>ok</code> after
2757
- each</td>
2758
- </tr>
2759
- <tr>
2760
- <td><strong>UNION [f₁,f₂,…]</strong></td>
2761
- <td>Emit chained <code>if</code> blocks; return first successful
2762
- result</td>
2763
- </tr>
2764
- <tr>
2765
- <td><strong>PRODUCT [l₁=f₁, …]</strong></td>
2766
- <td>Call all subfunctions; if all succeed, collect children and call
2767
- <code>@k_make_product</code></td>
2768
- </tr>
2769
- <tr>
2770
- <td><strong>FAIL</strong></td>
2771
- <td>Return <code>{0, undef}</code> immediately</td>
2772
- </tr>
2773
- </tbody>
2774
- </table>
2775
- <p>These templates cover the entire language.</p>
2776
- <hr />
2777
- <h2 id="example-sequential-composition"><strong>12.4 Example: sequential
2778
- composition</strong></h2>
2779
- <p>For IR:</p>
2780
- <pre><code>SEQ [ PROJECT x, CALL f, CALL g ]</code></pre>
2781
- <p>the compiler emits:</p>
2782
- <div class="sourceCode" id="cb99"><pre
2783
- class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb99-1"><a href="#cb99-1" aria-hidden="true" tabindex="-1"></a><span class="fu">%r1</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@k_project_x</span>(<span class="fu">%in</span>)</span>
2784
- <span id="cb99-2"><a href="#cb99-2" aria-hidden="true" tabindex="-1"></a><span class="fu">%ok1</span> = <span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%r1</span>, <span class="dv">0</span></span>
2785
- <span id="cb99-3"><a href="#cb99-3" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">i1</span> <span class="fu">%ok1</span>, <span class="dt">label</span> <span class="fu">%cont1</span>, <span class="dt">label</span> <span class="fu">%fail</span></span>
2786
- <span id="cb99-4"><a href="#cb99-4" aria-hidden="true" tabindex="-1"></a></span>
2787
- <span id="cb99-5"><a href="#cb99-5" aria-hidden="true" tabindex="-1"></a><span class="fu">cont1:</span></span>
2788
- <span id="cb99-6"><a href="#cb99-6" aria-hidden="true" tabindex="-1"></a><span class="fu">%r2</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@f</span>(<span class="fu">%r1.val</span>)</span>
2789
- <span id="cb99-7"><a href="#cb99-7" aria-hidden="true" tabindex="-1"></a><span class="fu">%ok2</span> = <span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%r2</span>, <span class="dv">0</span></span>
2790
- <span id="cb99-8"><a href="#cb99-8" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">i1</span> <span class="fu">%ok2</span>, <span class="dt">label</span> <span class="fu">%cont2</span>, <span class="dt">label</span> <span class="fu">%fail</span></span>
2791
- <span id="cb99-9"><a href="#cb99-9" aria-hidden="true" tabindex="-1"></a></span>
2792
- <span id="cb99-10"><a href="#cb99-10" aria-hidden="true" tabindex="-1"></a><span class="fu">cont2:</span></span>
2793
- <span id="cb99-11"><a href="#cb99-11" aria-hidden="true" tabindex="-1"></a><span class="fu">%r3</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@g</span>(<span class="fu">%r2.val</span>)</span>
2794
- <span id="cb99-12"><a href="#cb99-12" aria-hidden="true" tabindex="-1"></a><span class="kw">ret</span> <span class="fu">%KOpt</span> <span class="fu">%r3</span></span>
2795
- <span id="cb99-13"><a href="#cb99-13" aria-hidden="true" tabindex="-1"></a></span>
2796
- <span id="cb99-14"><a href="#cb99-14" aria-hidden="true" tabindex="-1"></a><span class="fu">fail:</span></span>
2797
- <span id="cb99-15"><a href="#cb99-15" aria-hidden="true" tabindex="-1"></a><span class="kw">ret</span> <span class="fu">%KOpt</span> { <span class="dt">i1</span> <span class="dv">0</span>, <span class="fu">%KVal</span> <span class="kw">undef</span> }</span></code></pre></div>
2798
- <p>Each block corresponds to one stage in the composition. The use of
2799
- conditional branches ensures that undefinedness propagates
2800
- correctly.</p>
2801
- <hr />
2802
- <h2 id="example-product-composition-1"><strong>12.5 Example: product
2803
- composition</strong></h2>
2804
- <p>For IR:</p>
2805
- <pre><code>PRODUCT [ a = PROJECT x, b = PROJECT y ]</code></pre>
2806
- <p>the compiler generates code equivalent to:</p>
2807
- <div class="sourceCode" id="cb101"><pre
2808
- class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb101-1"><a href="#cb101-1" aria-hidden="true" tabindex="-1"></a><span class="fu">%ra</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@k_project_x</span>(<span class="fu">%in</span>)</span>
2809
- <span id="cb101-2"><a href="#cb101-2" aria-hidden="true" tabindex="-1"></a><span class="fu">%ok_a</span> = <span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%ra</span>, <span class="dv">0</span></span>
2810
- <span id="cb101-3"><a href="#cb101-3" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">i1</span> <span class="fu">%ok_a</span>, <span class="dt">label</span> <span class="fu">%try_b</span>, <span class="dt">label</span> <span class="fu">%fail</span></span>
2811
- <span id="cb101-4"><a href="#cb101-4" aria-hidden="true" tabindex="-1"></a></span>
2812
- <span id="cb101-5"><a href="#cb101-5" aria-hidden="true" tabindex="-1"></a><span class="fu">try_b:</span></span>
2813
- <span id="cb101-6"><a href="#cb101-6" aria-hidden="true" tabindex="-1"></a><span class="fu">%rb</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@k_project_y</span>(<span class="fu">%in</span>)</span>
2814
- <span id="cb101-7"><a href="#cb101-7" aria-hidden="true" tabindex="-1"></a><span class="fu">%ok_b</span> = <span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%rb</span>, <span class="dv">0</span></span>
2815
- <span id="cb101-8"><a href="#cb101-8" aria-hidden="true" tabindex="-1"></a><span class="fu">%ok_all</span> = <span class="kw">and</span> <span class="dt">i1</span> <span class="fu">%ok_a</span>, <span class="fu">%ok_b</span></span>
2816
- <span id="cb101-9"><a href="#cb101-9" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">i1</span> <span class="fu">%ok_all</span>, <span class="dt">label</span> <span class="fu">%build</span>, <span class="dt">label</span> <span class="fu">%fail</span></span>
2817
- <span id="cb101-10"><a href="#cb101-10" aria-hidden="true" tabindex="-1"></a></span>
2818
- <span id="cb101-11"><a href="#cb101-11" aria-hidden="true" tabindex="-1"></a><span class="fu">build:</span></span>
2819
- <span id="cb101-12"><a href="#cb101-12" aria-hidden="true" tabindex="-1"></a><span class="fu">%children</span> = <span class="kw">alloca</span> [<span class="fu">%KVal</span>, <span class="dv">2</span>]</span>
2820
- <span id="cb101-13"><a href="#cb101-13" aria-hidden="true" tabindex="-1"></a><span class="fu">%p0</span> = <span class="kw">getelementptr</span> [<span class="fu">%KVal</span>,<span class="dv">2</span>], [<span class="fu">%KVal</span>,<span class="dv">2</span>]* <span class="fu">%children</span>, <span class="dt">i32</span> <span class="dv">0</span>, <span class="dt">i32</span> <span class="dv">0</span></span>
2821
- <span id="cb101-14"><a href="#cb101-14" aria-hidden="true" tabindex="-1"></a><span class="kw">store</span> <span class="fu">%KVal</span> (<span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%ra</span>, <span class="dv">1</span>), <span class="fu">%KVal</span>* <span class="fu">%p0</span></span>
2822
- <span id="cb101-15"><a href="#cb101-15" aria-hidden="true" tabindex="-1"></a><span class="fu">%p1</span> = <span class="kw">getelementptr</span> [<span class="fu">%KVal</span>,<span class="dv">2</span>], [<span class="fu">%KVal</span>,<span class="dv">2</span>]* <span class="fu">%children</span>, <span class="dt">i32</span> <span class="dv">0</span>, <span class="dt">i32</span> <span class="dv">1</span></span>
2823
- <span id="cb101-16"><a href="#cb101-16" aria-hidden="true" tabindex="-1"></a><span class="kw">store</span> <span class="fu">%KVal</span> (<span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%rb</span>, <span class="dv">1</span>), <span class="fu">%KVal</span>* <span class="fu">%p1</span></span>
2824
- <span id="cb101-17"><a href="#cb101-17" aria-hidden="true" tabindex="-1"></a><span class="fu">%res</span> = <span class="kw">call</span> <span class="fu">%KVal</span> <span class="fu">@k_make_product</span>(<span class="dt">i32</span> state_id, <span class="dt">i32</span> <span class="dv">2</span>, <span class="fu">%KVal</span>* <span class="fu">%children</span>)</span>
2825
- <span id="cb101-18"><a href="#cb101-18" aria-hidden="true" tabindex="-1"></a><span class="kw">ret</span> <span class="fu">%KOpt</span> { <span class="dt">i1</span> <span class="dv">1</span>, <span class="fu">%KVal</span> <span class="fu">%res</span> }</span>
2826
- <span id="cb101-19"><a href="#cb101-19" aria-hidden="true" tabindex="-1"></a></span>
2827
- <span id="cb101-20"><a href="#cb101-20" aria-hidden="true" tabindex="-1"></a><span class="fu">fail:</span></span>
2828
- <span id="cb101-21"><a href="#cb101-21" aria-hidden="true" tabindex="-1"></a><span class="kw">ret</span> <span class="fu">%KOpt</span> { <span class="dt">i1</span> <span class="dv">0</span>, <span class="fu">%KVal</span> <span class="kw">undef</span> }</span></code></pre></div>
2829
- <p>The resulting LLVM code faithfully follows the semantic rule: the
2830
- product is defined only if all components are defined.</p>
2831
- <hr />
2832
- <h2 id="example-union-composition"><strong>12.6 Example: union
2833
- composition</strong></h2>
2834
- <p>For IR:</p>
2835
- <pre><code>UNION [ .x, .y ]</code></pre>
2836
- <p>the compiler produces a branching structure:</p>
2837
- <div class="sourceCode" id="cb103"><pre
2838
- class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb103-1"><a href="#cb103-1" aria-hidden="true" tabindex="-1"></a><span class="fu">%r1</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@k_project_x</span>(<span class="fu">%in</span>)</span>
2839
- <span id="cb103-2"><a href="#cb103-2" aria-hidden="true" tabindex="-1"></a><span class="fu">%ok1</span> = <span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%r1</span>, <span class="dv">0</span></span>
2840
- <span id="cb103-3"><a href="#cb103-3" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">i1</span> <span class="fu">%ok1</span>, <span class="dt">label</span> <span class="fu">%merge</span>, <span class="dt">label</span> <span class="fu">%try_next</span></span>
2841
- <span id="cb103-4"><a href="#cb103-4" aria-hidden="true" tabindex="-1"></a></span>
2842
- <span id="cb103-5"><a href="#cb103-5" aria-hidden="true" tabindex="-1"></a><span class="fu">try_next:</span></span>
2843
- <span id="cb103-6"><a href="#cb103-6" aria-hidden="true" tabindex="-1"></a><span class="fu">%r2</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@k_project_y</span>(<span class="fu">%in</span>)</span>
2844
- <span id="cb103-7"><a href="#cb103-7" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">label</span> <span class="fu">%merge</span></span>
2845
- <span id="cb103-8"><a href="#cb103-8" aria-hidden="true" tabindex="-1"></a></span>
2846
- <span id="cb103-9"><a href="#cb103-9" aria-hidden="true" tabindex="-1"></a><span class="fu">merge:</span></span>
2847
- <span id="cb103-10"><a href="#cb103-10" aria-hidden="true" tabindex="-1"></a><span class="fu">%res</span> = <span class="kw">phi</span> <span class="fu">%KOpt</span> [ <span class="fu">%r1</span>, <span class="fu">%ok1</span> ], [ <span class="fu">%r2</span>, <span class="fu">%try_next</span> ]</span>
2848
- <span id="cb103-11"><a href="#cb103-11" aria-hidden="true" tabindex="-1"></a><span class="kw">ret</span> <span class="fu">%KOpt</span> <span class="fu">%res</span></span></code></pre></div>
2849
- <p>This pattern ensures that the first defined branch wins, as specified
2850
- by the semantics.</p>
2851
- <hr />
2852
- <h2 id="managing-constants-and-types"><strong>12.7 Managing constants
2853
- and types</strong></h2>
2854
- <p>Whenever an expression references a constant value or a type
2855
- restriction:</p>
2856
- <ul>
2857
- <li><strong>Constant values</strong> are replaced by pointers to global
2858
- constant nodes.</li>
2859
- <li><strong>Type expressions <code>$T</code></strong> are compiled to a
2860
- <code>TYPECHECK</code> instruction: if
2861
- <code>input-&gt;state != T_state</code>, the function returns
2862
- undefined.</li>
2863
- </ul>
2864
- <p>This approach removes all high-level notation before reaching machine
2865
- level.</p>
2866
- <hr />
2867
- <h2 id="optimizing-during-generation"><strong>12.8 Optimizing during
2868
- generation</strong></h2>
2869
- <p>Because the structure of k is very regular, many optimizations can be
2870
- applied while generating code:</p>
2871
- <ul>
2872
- <li><strong>Eliminate redundant checks</strong> — consecutive type
2873
- checks on the same state can be merged.</li>
2874
- <li><strong>Inline small functions</strong> — short constant or
2875
- projection functions can be inserted directly into their callers.</li>
2876
- <li><strong>Remove unreachable branches</strong> — if a type restriction
2877
- guarantees that one union branch can never apply, it is omitted.</li>
2878
- </ul>
2879
- <p>Such simplifications can be done by the compiler itself or delegated
2880
- to LLVM’s optimization passes.</p>
2881
- <hr />
2882
- <h2 id="interaction-with-the-runtime"><strong>12.9 Interaction with the
2883
- runtime</strong></h2>
2884
- <p>All allocation and field access are performed through runtime calls.
2885
- The compiler never manipulates pointers directly beyond passing them to
2886
- these helpers. This design ensures that compiled code is independent of
2887
- the internal memory layout.</p>
2888
- <p>The generated functions thus resemble small graphs of calls and
2889
- conditionals built entirely on top of the fixed ABI.</p>
2890
- <hr />
2891
- <h2 id="linking-and-verification"><strong>12.10 Linking and
2892
- verification</strong></h2>
2893
- <p>After all functions are emitted, the compiler writes a single LLVM
2894
- module containing:</p>
2895
- <ul>
2896
- <li>all generated functions,</li>
2897
- <li>declarations of runtime primitives (<code>k_project</code>,
2898
- <code>k_make_product</code>, etc.),</li>
2899
- <li>and constant nodes representing literal values.</li>
2900
- </ul>
2901
- <p>The LLVM verifier then checks that:</p>
2902
- <ul>
2903
- <li>every function returns a correctly typed <code>%KOpt</code>,</li>
2904
- <li>all control-flow paths end with a <code>ret</code>,</li>
2905
- <li>and all global references are defined.</li>
2906
- </ul>
2907
- <p>Only verified code is passed to the optimizer or the machine-code
2908
- generator.</p>
2909
- <hr />
2910
- <h2 id="summary-10"><strong>12.11 Summary</strong></h2>
2911
- <ul>
2912
- <li>Code generation turns IR into real executable instructions.</li>
2913
- <li>Each k function maps to an LLVM function returning
2914
- <code>{ok, value}</code>.</li>
2915
- <li>Projection, composition, union, and product translate into small,
2916
- fixed code patterns.</li>
2917
- <li>Type restrictions become simple integer comparisons.</li>
2918
- <li>The compiler can apply immediate simplifications during
2919
- translation.</li>
2920
- <li>The final output is a verified LLVM module ready for optimization
2921
- and linking.</li>
2922
- </ul>
2923
- <h1 id="chapter-13-linking-and-execution">Chapter 13 — Linking and
2924
- Execution</h1>
2925
- <h2 id="purpose-4"><strong>13.1 Purpose</strong></h2>
2926
- <p>The last stage of compilation connects the generated code with the
2927
- runtime library and produces an executable program. This process is
2928
- called <strong>linking</strong>. Once linked, the program can be run
2929
- like any other compiled program: it reads input values, executes the
2930
- compiled k functions, and returns a result.</p>
2931
- <p>The linking and execution stages ensure that the compiled code, the
2932
- runtime library, and the data it manipulates all agree on structure and
2933
- conventions.</p>
2934
- <hr />
2935
- <h2 id="the-runtime-library"><strong>13.2 The runtime
2936
- library</strong></h2>
2937
- <p>All compiled k programs depend on a small runtime component, often
2938
- distributed as a file named <code>krt.c</code> or <code>krt.o</code>.
2939
- This library provides:</p>
2940
- <table>
2941
- <colgroup>
2942
- <col style="width: 41%" />
2943
- <col style="width: 58%" />
2944
- </colgroup>
2945
- <thead>
2946
- <tr>
2947
- <th>Function</th>
2948
- <th>Purpose</th>
2949
- </tr>
2950
- </thead>
2951
- <tbody>
2952
- <tr>
2953
- <td><code>k_make_product(state, n, children)</code></td>
2954
- <td>Allocate a product node with <code>n</code> fields.</td>
2955
- </tr>
2956
- <tr>
2957
- <td><code>k_make_union(state, tag, child)</code></td>
2958
- <td>Allocate a union node with a single variant.</td>
2959
- </tr>
2960
- <tr>
2961
- <td><code>k_project(input, label_id)</code></td>
2962
- <td>Perform projection <code>.label</code>.</td>
2963
- </tr>
2964
- <tr>
2965
- <td><code>k_fail()</code></td>
2966
- <td>Return a predefined undefined result <code>{ ok = 0 }</code>.</td>
2967
- </tr>
2968
- <tr>
2969
- <td><code>k_unit()</code></td>
2970
- <td>Return the constant unit value <code>{}</code>.</td>
2971
- </tr>
2972
- </tbody>
2973
- </table>
2974
- <p>These functions implement the same concepts as the semantic rules
2975
- described earlier, but at the level of actual memory operations. They
2976
- are compiled once in a low-level language such as C and reused by all
2977
- generated programs.</p>
2978
- <hr />
2979
- <h2 id="metadata-tables-1"><strong>13.3 Metadata tables</strong></h2>
2980
- <p>Along with the runtime functions, the compiler produces
2981
- <strong>metadata</strong> describing each canonical type used in the
2982
- program:</p>
2983
- <ul>
2984
- <li><code>state_kind[state]</code> — <code>0</code> for product,
2985
- <code>1</code> for union</li>
2986
- <li><code>state_arity[state]</code> — number of children</li>
2987
- <li><code>field_index[state][label_id]</code> — position of field
2988
- <code>label_id</code> within product</li>
2989
- <li><code>variant_index[state][label_id]</code> — tag number for variant
2990
- <code>label_id</code> within union</li>
2991
- </ul>
2992
- <p>These tables are stored as constant arrays in the compiled module.
2993
- Runtime functions use them to interpret and construct nodes correctly
2994
- without needing any dynamic reflection.</p>
2995
- <hr />
2996
- <h2 id="linking"><strong>13.4 Linking</strong></h2>
2997
- <p>The generated LLVM file is compiled and linked with the runtime
2998
- library in two simple steps:</p>
2999
- <div class="sourceCode" id="cb104"><pre
3000
- class="sourceCode bash"><code class="sourceCode bash"><span id="cb104-1"><a href="#cb104-1" aria-hidden="true" tabindex="-1"></a><span class="fu">clang</span> <span class="at">-O2</span> <span class="at">-c</span> krt.c <span class="at">-o</span> krt.o</span>
3001
- <span id="cb104-2"><a href="#cb104-2" aria-hidden="true" tabindex="-1"></a><span class="fu">clang</span> <span class="at">-O2</span> program.ll krt.o <span class="at">-o</span> program</span></code></pre></div>
3002
- <p>The first command compiles the runtime once. The second command
3003
- combines the runtime with the program’s own functions and constant
3004
- definitions.</p>
3005
- <p>The result is a native executable file named <code>program</code>.
3006
- When run, it behaves exactly like the original k program.</p>
3007
- <hr />
3008
- <h2 id="initialization"><strong>13.5 Initialization</strong></h2>
3009
- <p>When the executable starts, it performs a few basic steps:</p>
3010
- <ol type="1">
3011
- <li>Allocate an <strong>arena</strong> for storing newly created
3012
- nodes.</li>
3013
- <li>Initialize constant nodes such as the unit <code>{}</code> and any
3014
- user-defined constants.</li>
3015
- <li>Optionally, prepare a table of function pointers for fast
3016
- invocation.</li>
3017
- </ol>
3018
- <p>After initialization, the main compiled function can be called
3019
- directly.</p>
3020
- <hr />
3021
- <h2 id="executing-a-compiled-function"><strong>13.6 Executing a compiled
3022
- function</strong></h2>
3023
- <p>Every compiled function has the signature:</p>
3024
- <div class="sourceCode" id="cb105"><pre
3025
- class="sourceCode c"><code class="sourceCode c"><span id="cb105-1"><a href="#cb105-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> KOpt function<span class="op">(</span><span class="kw">struct</span> KNode<span class="op">*</span> input<span class="op">);</span></span></code></pre></div>
3026
- <p>To run a program, a caller must supply an input value tree in the
3027
- expected canonical form. The value is typically created by another
3028
- function or loaded from serialized data.</p>
3029
- <p>For example, to execute a function <code>neg</code> expecting a
3030
- <code>$bool</code>:</p>
3031
- <div class="sourceCode" id="cb106"><pre
3032
- class="sourceCode c"><code class="sourceCode c"><span id="cb106-1"><a href="#cb106-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> KOpt result <span class="op">=</span> neg<span class="op">(&amp;</span>true_node<span class="op">);</span></span>
3033
- <span id="cb106-2"><a href="#cb106-2" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="op">(</span>result<span class="op">.</span>ok<span class="op">)</span></span>
3034
- <span id="cb106-3"><a href="#cb106-3" aria-hidden="true" tabindex="-1"></a> print_value<span class="op">(</span>result<span class="op">.</span>val<span class="op">);</span></span>
3035
- <span id="cb106-4"><a href="#cb106-4" aria-hidden="true" tabindex="-1"></a><span class="cf">else</span></span>
3036
- <span id="cb106-5"><a href="#cb106-5" aria-hidden="true" tabindex="-1"></a> printf<span class="op">(</span><span class="st">&quot;undefined</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span></code></pre></div>
3037
- <p>If the input is <code>{ {} true }</code>, the output will be
3038
- <code>{ {} false }</code>.</p>
3039
- <hr />
3040
- <h2 id="input-and-output-conventions"><strong>13.7 Input and output
3041
- conventions</strong></h2>
3042
- <p>At the machine level, a “value” is always represented by a pointer to
3043
- a <code>KNode</code>. Each compiled function expects exactly one such
3044
- pointer. When a function returns, its output pointer may refer to an
3045
- existing constant node, a new node allocated in the arena, or nothing at
3046
- all if undefined.</p>
3047
- <p>There is no special I/O system in k itself; printing or reading
3048
- values is the responsibility of the host environment. In practice,
3049
- programs are tested by calling compiled functions from C or Python and
3050
- inspecting their returned structures.</p>
3051
- <hr />
3052
- <h2 id="debugging-and-inspection"><strong>13.8 Debugging and
3053
- inspection</strong></h2>
3054
- <p>Because both the generated code and the runtime library are
3055
- deterministic and memory-safe, debugging usually consists of examining
3056
- node contents.</p>
3057
- <p>Two simple runtime utilities are useful:</p>
3058
- <ul>
3059
- <li><code>print_value(node)</code> — prints a tree in human-readable
3060
- form.</li>
3061
- <li><code>print_type(state)</code> — prints the canonical description of
3062
- a type state.</li>
3063
- </ul>
3064
- <p>They allow the user to confirm that compiled functions construct the
3065
- correct tree shapes.</p>
3066
- <hr />
3067
- <h2 id="verification"><strong>13.9 Verification</strong></h2>
3068
- <p>After linking, the compiler can run a <em>self-verification
3069
- pass</em>:</p>
3070
- <ol type="1">
3071
- <li>Construct small sample inputs for each exported function.</li>
3072
- <li>Execute the compiled function.</li>
3073
- <li>Compare results with the interpreter’s result using structural
3074
- equality.</li>
3075
- </ol>
3076
- <p>If all match, the compiler’s translation is confirmed correct for
3077
- those test cases. This method is especially valuable during compiler
3078
- development and textbook exercises.</p>
3079
- <hr />
3080
- <h2 id="example-complete-run"><strong>13.10 Example: complete
3081
- run</strong></h2>
3082
- <p>Example program:</p>
3083
- <pre><code>$bool = &lt; {} true, {} false &gt;;
3084
- neg = $bool &lt; .true {{ } false}, .false {{ } true} &gt; $bool;</code></pre>
3085
- <p>Steps:</p>
3086
- <ol type="1">
3087
- <li>Compile to <code>neg.ll</code>.</li>
3088
- <li>Link with <code>krt.o</code>.</li>
3089
- <li>Run a small C driver that calls <code>neg</code>.</li>
3090
- </ol>
3091
- <p>Output:</p>
3092
- <pre><code>input = {{ } true}
3093
- result = {{ } false}</code></pre>
3094
- <p>If <code>input</code> is <code>{}</code> or any
3095
- non-<code>$bool</code> value, the function is undefined and prints
3096
- “undefined”.</p>
3097
- <hr />
3098
- <h2 id="summary-11"><strong>13.11 Summary</strong></h2>
3099
- <ul>
3100
- <li>Linking combines generated LLVM code with the shared runtime
3101
- library.</li>
3102
- <li>The runtime provides allocation, projection, and constant
3103
- handling.</li>
3104
- <li>Metadata tables describe type structure to the runtime.</li>
3105
- <li>Every compiled function follows the uniform calling convention
3106
- <code>KOpt f(KNode*)</code>.</li>
3107
- <li>Execution produces immutable tree values exactly matching the
3108
- semantics of k.</li>
3109
- <li>Verification against the interpreter ensures correctness of the
3110
- translation.</li>
3111
- </ul>
3112
- <h1 id="chapter-14-canonical-serialization">Chapter 14 — Canonical
3113
- Serialization</h1>
3114
- <h2 id="purpose-5"><strong>14.1 Purpose</strong></h2>
3115
- <p>Serialization is the process of converting a value in memory into a
3116
- compact sequence of bits or bytes that can be stored or transmitted. For
3117
- the k language, serialization serves an additional goal: it defines a
3118
- <strong>canonical representation</strong> of each value that is unique
3119
- and independent of the machine on which it was produced.</p>
3120
- <p>A canonical encoding allows values to be compared, hashed, or stored
3121
- in a registry in a reproducible way. Two values that are structurally
3122
- identical will always produce the same bit sequence.</p>
3123
- <hr />
3124
- <h2 id="canonical-type-information"><strong>14.2 Canonical type
3125
- information</strong></h2>
3126
- <p>Serialization always depends on the <strong>canonical form of the
3127
- type</strong>. A type in canonical form is a finite tree automaton
3128
- (Chapter 3) that describes the structure of all its values. Because this
3129
- form is unique, every possible value of the type can be encoded
3130
- deterministically.</p>
3131
- <p>Before any value is serialized, the compiler or runtime must
3132
- know:</p>
3133
- <ul>
3134
- <li>the list of states (C0, C1, …),</li>
3135
- <li>for each state, whether it is a product or a union,</li>
3136
- <li>the number of possible transitions, and</li>
3137
- <li>for unions, the order of their variants.</li>
3138
- </ul>
3139
- <p>This information acts as the grammar from which all bit sequences are
3140
- derived.</p>
3141
- <hr />
3142
- <h2 id="encoding-principle"><strong>14.3 Encoding
3143
- principle</strong></h2>
3144
- <p>Each node in a value tree corresponds to one of the type’s
3145
- states.</p>
3146
- <ul>
3147
- <li><strong>Product node</strong> – emits no bits; the encoder simply
3148
- serializes each child in canonical field order.</li>
3149
- <li><strong>Union node</strong> – emits a small binary code that
3150
- identifies which variant is used, then serializes its single child.</li>
3151
- <li><strong>Unit node</strong> (empty product) – emits nothing; it has
3152
- no children.</li>
3153
- <li><strong>Empty union</strong> – cannot be encoded because it has no
3154
- possible values.</li>
3155
- </ul>
3156
- <p>Thus, the sequence of bits records exactly which union branches were
3157
- taken while descending the tree.</p>
3158
- <hr />
3159
- <h2 id="fixed-length-codes-per-state"><strong>14.4 Fixed-length codes
3160
- per state</strong></h2>
3161
- <p>For simplicity, each union state uses fixed-length binary codes of
3162
- equal size.</p>
3163
- <p>If a union has <em>m</em> variants, then</p>
3164
- <pre><code>k = ceil(log2(m))</code></pre>
3165
- <p>bits are needed. Each variant is numbered in canonical order from 0
3166
- to m − 1 and represented by the binary form of its index.</p>
3167
- <p>Products and units use k = 0 and emit no bits.</p>
3168
- <p>This rule allows the decoder to know, from the type alone, how many
3169
- bits to read at each step.</p>
3170
- <hr />
3171
- <h2 id="example-natural-numbers-1"><strong>14.5 Example: natural
3172
- numbers</strong></h2>
3173
- <p>For the type</p>
3174
- <pre><code>$bnat = &lt; bnat 0, bnat 1, {} _ &gt;;</code></pre>
3175
- <p>the canonical form has three transitions from state C0. Therefore,
3176
- <code>k = ceil(log2(3)) = 2</code> bits are required per union node.</p>
3177
- <p>Assigning codes in order:</p>
3178
- <table>
3179
- <thead>
3180
- <tr>
3181
- <th>Rule</th>
3182
- <th>Code</th>
3183
- </tr>
3184
- </thead>
3185
- <tbody>
3186
- <tr>
3187
- <td>C0 → {C0 “0”}</td>
3188
- <td><code>00</code></td>
3189
- </tr>
3190
- <tr>
3191
- <td>C0 → {C0 “1”}</td>
3192
- <td><code>01</code></td>
3193
- </tr>
3194
- <tr>
3195
- <td>C0 → {C1 “_” }</td>
3196
- <td><code>10</code></td>
3197
- </tr>
3198
- </tbody>
3199
- </table>
3200
- <p>The value <code>{ {{ {} _ } 1 } 0 }</code> is encoded by
3201
- concatenating the codes of the transitions chosen during a leftmost
3202
- derivation:</p>
3203
- <pre><code>00 → first C0
3204
- 01 → next C0
3205
- 10 → final C0</code></pre>
3206
- <p>Resulting bit sequence: <code>000110</code>.</p>
3207
- <hr />
3208
- <h2 id="decoding"><strong>14.6 Decoding</strong></h2>
3209
- <p>Decoding is deterministic and mirrors the encoding process:</p>
3210
- <ol type="1">
3211
- <li>Start at the root state (C0).</li>
3212
- <li>If the current state is a union, read k bits to choose a rule.</li>
3213
- <li>Create the corresponding node, then recursively decode its child or
3214
- children.</li>
3215
- <li>For products, decode all children in order; for units, stop.</li>
3216
- </ol>
3217
- <p>The decoder stops when the entire tree has been reconstructed and all
3218
- bits have been consumed.</p>
3219
- <p>Because every union code is of fixed length, the decoding process
3220
- requires no backtracking and can be implemented as a simple loop.</p>
3221
- <hr />
3222
- <h2 id="folding-repeated-subtrees"><strong>14.7 Folding repeated
3223
- subtrees</strong></h2>
3224
- <p>Many values contain repeated substructures. To avoid serializing the
3225
- same tree several times, identical subtrees can be <em>folded</em> into
3226
- a <strong>directed acyclic graph (DAG)</strong> before encoding.</p>
3227
- <p>Each unique node is assigned an identifier. When the encoder
3228
- encounters a repeated node, it emits a reference to its identifier
3229
- instead of encoding it again.</p>
3230
- <p>During decoding, the identifier is resolved to the corresponding
3231
- subtree, reconstructing the shared structure.</p>
3232
- <p>Folding is optional; it saves space without changing the logical
3233
- value.</p>
3234
- <hr />
3235
- <h2 id="stream-format"><strong>14.8 Stream format</strong></h2>
3236
- <p>A minimal canonical bitstream consists of:</p>
3237
- <ol type="1">
3238
- <li><strong>Header</strong> – type hash (e.g., 8 bytes) identifying the
3239
- canonical type.</li>
3240
- <li><strong>Node count</strong> – integer <em>N</em> if DAG encoding is
3241
- used.</li>
3242
- <li><strong>Encoded data</strong> – concatenation of all fixed-length
3243
- union codes and, if folded, node references.</li>
3244
- </ol>
3245
- <p>If two systems share the same canonical type table, the bitstream
3246
- alone is enough to reconstruct the original value.</p>
3247
- <hr />
3248
- <h2 id="implementation-sketch"><strong>14.9 Implementation
3249
- sketch</strong></h2>
3250
- <p>A compact encoder can be written as follows:</p>
3251
- <pre><code>procedure encode(node):
3252
- if node.arity == 0:
3253
- return
3254
- if node.arity == 1:
3255
- write_bits(code_for(node.state, node.tag))
3256
- encode(node.child[0])
3257
- else:
3258
- for each child in node.children:
3259
- encode(child)</code></pre>
3260
- <p>The corresponding decoder reverses the process. Both procedures
3261
- require only the canonical type tables and simple bit operations.</p>
3262
- <hr />
3263
- <h2 id="determinism-and-equality"><strong>14.10 Determinism and
3264
- equality</strong></h2>
3265
- <p>Because encoding is fully determined by the canonical type and field
3266
- order, two equal values always produce identical bit sequences.
3267
- Conversely, decoding the same bit sequence always yields the same
3268
- tree.</p>
3269
- <p>This property allows equality comparison by direct byte comparison of
3270
- serialized forms, without traversing the trees in memory.</p>
3271
- <hr />
3272
- <h2 id="summary-12"><strong>14.11 Summary</strong></h2>
3273
- <ul>
3274
- <li>Every type’s canonical automaton defines a unique bit-level grammar
3275
- for its values.</li>
3276
- <li>Products emit no bits; unions emit fixed-length variant codes.</li>
3277
- <li>The number of bits required for each state depends only on the
3278
- number of variants in that state.</li>
3279
- <li>Optional DAG folding eliminates repeated subtrees.</li>
3280
- <li>The resulting bitstream is compact, deterministic, and
3281
- machine-independent.</li>
3282
- </ul>
3283
- <h1 id="chapter-15-optimization-and-folding">Chapter 15 — Optimization
3284
- and Folding</h1>
3285
- <h2 id="purpose-6"><strong>15.1 Purpose</strong></h2>
3286
- <p>Optimization in the k compiler is the process of simplifying
3287
- functions without changing their meaning. The goal is to make the
3288
- generated code smaller, faster, and easier to verify. Because k is
3289
- purely functional and has no side effects, optimizations are safe
3290
- whenever the simplified function is equivalent to the original one.</p>
3291
- <p>This chapter describes a few basic optimizations that follow directly
3292
- from the semantics introduced earlier.</p>
3293
- <hr />
3294
- <h2 id="constant-folding"><strong>15.2 Constant folding</strong></h2>
3295
- <p>A <strong>constant</strong> is a function that ignores its input and
3296
- always produces the same value. If a composition of functions can be
3297
- evaluated entirely at compile time, it can be replaced by a single
3298
- constant function.</p>
3299
- <p>Example:</p>
3300
- <pre><code>true_bool = {{ } true} $bool;
3301
- not_true = (true_bool neg);</code></pre>
3302
- <p>The compiler observes that <code>(true_bool neg)</code> always yields
3303
- <code>false_bool</code>, so it replaces it with a constant:</p>
3304
- <pre><code>not_true = {{ } false} $bool;</code></pre>
3305
- <p>Constant folding removes unnecessary runtime computation.</p>
3306
- <hr />
3307
- <h2 id="type-based-simplifications"><strong>15.3 Type-based
3308
- simplifications</strong></h2>
3309
- <p>Since type expressions act as identity functions defined only on
3310
- specific values, they can be eliminated when redundant:</p>
3311
- <pre><code>$bool $bool f → $bool f</code></pre>
3312
- <p>If a function’s input or output type is already known from context,
3313
- repeated checks can be omitted. The compiler ensures that at least one
3314
- valid check remains to preserve correctness.</p>
3315
- <hr />
3316
- <h2 id="inlining"><strong>15.4 Inlining</strong></h2>
3317
- <p>Inlining replaces a call to a small function by its body. It avoids
3318
- the overhead of a function call and often exposes further
3319
- simplifications.</p>
3320
- <p>Example:</p>
3321
- <pre><code>id = ();
3322
- f = (id g);</code></pre>
3323
- <p>Because <code>id</code> is the identity function, <code>(id g)</code>
3324
- is equivalent to <code>g</code>. Inlining removes the useless call.</p>
3325
- <p>For larger functions, inlining is applied selectively—only when it
3326
- shortens the resulting code or eliminates intermediate values.</p>
3327
- <hr />
3328
- <h2 id="dead-branch-elimination"><strong>15.5 Dead-branch
3329
- elimination</strong></h2>
3330
- <p>In a union composition <code>&lt;f, g&gt;</code>, if type analysis
3331
- shows that the input type can only satisfy the first branch, the second
3332
- branch can never be defined and is removed.</p>
3333
- <p>Example:</p>
3334
- <pre><code>$bool = &lt; {} true, {} false &gt;;
3335
- f = $bool &lt; .true {{ } false} &gt;;</code></pre>
3336
- <p>Here, since <code>$bool</code> restricts the input to only the two
3337
- variants <code>true</code> and <code>false</code>, and the second
3338
- variant <code>.false</code> is not handled, the compiler infers that
3339
- <code>f</code> is undefined for <code>.false</code> and simplifies the
3340
- code accordingly.</p>
3341
- <p>Dead-branch elimination keeps the generated control flow minimal.</p>
3342
- <hr />
3343
- <h2 id="common-subexpression-elimination"><strong>15.6 Common
3344
- subexpression elimination</strong></h2>
3345
- <p>If the same partial function is applied multiple times to the same
3346
- input, the result will always be the same. The compiler can compute it
3347
- once and reuse the result.</p>
3348
- <p>Example:</p>
3349
- <pre><code>{ .x .y, .x .z }</code></pre>
3350
- <p>Both fields start with the projection <code>.x</code>. The compiler
3351
- computes <code>.x</code> once, stores the result, and reuses it for
3352
- <code>.y</code> and <code>.z</code>. This optimization reduces repeated
3353
- traversal of the same input structure.</p>
3354
- <hr />
3355
- <h2 id="canonical-folding"><strong>15.7 Canonical folding</strong></h2>
3356
- <p>During evaluation, many values share identical subtrees. A
3357
- <strong>folding pass</strong> replaces identical subtrees by shared
3358
- nodes, forming a minimal DAG (directed acyclic graph).</p>
3359
- <p>At compile time, folding may also apply to constant expressions. If
3360
- two constant subtrees are identical, they are merged and stored as a
3361
- single global node.</p>
3362
- <p>This process ensures that structural equality corresponds to pointer
3363
- equality: two values are identical if they share the same root node.</p>
3364
- <hr />
3365
- <h2 id="function-canonicalization"><strong>15.8 Function
3366
- canonicalization</strong></h2>
3367
- <p>Every function can be normalized by expanding all type aliases,
3368
- inlining trivial definitions, and folding identical subfunctions. The
3369
- normalized form of a function depends only on its semantics, not on the
3370
- way it was written.</p>
3371
- <p>A stable hash computed from this canonical representation serves as a
3372
- permanent identifier for the function, just as type hashes identify
3373
- canonical types.</p>
3374
- <p>This property is essential for the schema registry described in the
3375
- next chapter.</p>
3376
- <hr />
3377
- <h2 id="runtime-simplifications"><strong>15.9 Runtime
3378
- simplifications</strong></h2>
3379
- <p>At runtime, additional micro-optimizations are possible:</p>
3380
- <ul>
3381
- <li><strong>Arena reuse:</strong> allocate nodes in a memory region that
3382
- is cleared after each function call.</li>
3383
- <li><strong>Hash-consing:</strong> maintain a small table of recently
3384
- created nodes to reuse identical ones automatically.</li>
3385
- <li><strong>Shortcut constants:</strong> return pointers to global
3386
- constants instead of allocating new copies for unit or boolean
3387
- values.</li>
3388
- </ul>
3389
- <p>Such optimizations reduce memory usage without changing program
3390
- behavior.</p>
3391
- <hr />
3392
- <h2 id="equivalence-and-correctness"><strong>15.10 Equivalence and
3393
- correctness</strong></h2>
3394
- <p>Each optimization must preserve <em>semantic equivalence</em>: for
3395
- every input, the optimized function must be defined for exactly the same
3396
- values and must return the same result when defined.</p>
3397
- <p>Because k’s semantics are purely functional, equivalence can be
3398
- tested mechanically by comparing evaluation results on all finite inputs
3399
- of a small type, or by structural reasoning when types are infinite.</p>
3400
- <hr />
3401
- <h2 id="summary-13"><strong>15.11 Summary</strong></h2>
3402
- <ul>
3403
- <li>Optimization in k relies on algebraic properties of pure
3404
- functions.</li>
3405
- <li>Common transformations include constant folding, inlining,
3406
- dead-branch elimination, and subexpression reuse.</li>
3407
- <li>Folding shared subtrees yields compact DAG representations of
3408
- values.</li>
3409
- <li>Canonical function forms allow stable hashing and reproducible
3410
- compilation results.</li>
3411
- <li>All optimizations preserve exact semantic behavior.</li>
3412
- </ul>
3413
- <h1 id="chapter-16-toward-a-universal-schema-registry">Chapter 16 —
3414
- Toward a Universal Schema Registry</h1>
3415
- <h2 id="motivation-1"><strong>16.1 Motivation</strong></h2>
3416
- <p>Every canonical type and function in k has a unique structural form
3417
- and a stable hash. These hashes can serve as global identifiers. A
3418
- registry that maps such identifiers to definitions allows programs and
3419
- systems to exchange schemas and functions safely and reproducibly.</p>
3420
- <hr />
3421
- <h2 id="basic-structure"><strong>16.2 Basic structure</strong></h2>
3422
- <p>A schema registry stores entries of two kinds:</p>
3423
- <table>
3424
- <colgroup>
3425
- <col style="width: 16%" />
3426
- <col style="width: 83%" />
3427
- </colgroup>
3428
- <thead>
3429
- <tr>
3430
- <th>Kind</th>
3431
- <th>Example content</th>
3432
- </tr>
3433
- </thead>
3434
- <tbody>
3435
- <tr>
3436
- <td><strong>Type</strong></td>
3437
- <td>canonical automaton text for a type hash</td>
3438
- </tr>
3439
- <tr>
3440
- <td><strong>Function</strong></td>
3441
- <td>canonical IR or serialized representation for a function hash</td>
3442
- </tr>
3443
- </tbody>
3444
- </table>
3445
- <p>Each entry is immutable. New versions are added as new hashes.</p>
3446
- <hr />
3447
- <h2 id="key-operations"><strong>16.3 Key operations</strong></h2>
3448
- <ol type="1">
3449
- <li><strong>Lookup by hash</strong> — return the canonical
3450
- definition.</li>
3451
- <li><strong>Lookup by shape</strong> — search for functions with given
3452
- input/output type hashes.</li>
3453
- <li><strong>Verification</strong> — ensure that two parties share the
3454
- same canonical form before exchanging values.</li>
3455
- </ol>
3456
- <p>These operations can be implemented as simple key–value queries.</p>
3457
- <hr />
3458
- <h2 id="example-format"><strong>16.4 Example format</strong></h2>
3459
- <p>A minimal JSON entry:</p>
3460
- <div class="sourceCode" id="cb119"><pre
3461
- class="sourceCode json"><code class="sourceCode json"><span id="cb119-1"><a href="#cb119-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
3462
- <span id="cb119-2"><a href="#cb119-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;hash&quot;</span><span class="fu">:</span> <span class="st">&quot;C0ABCDEF&quot;</span><span class="fu">,</span></span>
3463
- <span id="cb119-3"><a href="#cb119-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;kind&quot;</span><span class="fu">:</span> <span class="st">&quot;type&quot;</span><span class="fu">,</span></span>
3464
- <span id="cb119-4"><a href="#cb119-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;definition&quot;</span><span class="fu">:</span> <span class="st">&quot;$C0=&lt;C0</span><span class="ch">\&quot;</span><span class="st">0</span><span class="ch">\&quot;</span><span class="st">,C0</span><span class="ch">\&quot;</span><span class="st">1</span><span class="ch">\&quot;</span><span class="st">,C1</span><span class="ch">\&quot;</span><span class="st">_</span><span class="ch">\&quot;</span><span class="st">&gt;;$C1={};&quot;</span></span>
3465
- <span id="cb119-5"><a href="#cb119-5" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
3466
- <p>or for a function:</p>
3467
- <div class="sourceCode" id="cb120"><pre
3468
- class="sourceCode json"><code class="sourceCode json"><span id="cb120-1"><a href="#cb120-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
3469
- <span id="cb120-2"><a href="#cb120-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;hash&quot;</span><span class="fu">:</span> <span class="st">&quot;F7B1A2&quot;</span><span class="fu">,</span></span>
3470
- <span id="cb120-3"><a href="#cb120-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;kind&quot;</span><span class="fu">:</span> <span class="st">&quot;function&quot;</span><span class="fu">,</span></span>
3471
- <span id="cb120-4"><a href="#cb120-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;input&quot;</span><span class="fu">:</span> <span class="st">&quot;C0ABCDEF&quot;</span><span class="fu">,</span></span>
3472
- <span id="cb120-5"><a href="#cb120-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;output&quot;</span><span class="fu">:</span> <span class="st">&quot;C9FFF1&quot;</span><span class="fu">,</span></span>
3473
- <span id="cb120-6"><a href="#cb120-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;ir&quot;</span><span class="fu">:</span> <span class="st">&quot;SEQ [PROJECT x, CONST true]&quot;</span></span>
3474
- <span id="cb120-7"><a href="#cb120-7" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
3475
- <hr />
3476
- <h2 id="uses"><strong>16.5 Uses</strong></h2>
3477
- <ul>
3478
- <li>Preventing schema mismatches in distributed systems.</li>
3479
- <li>Deduplicating identical definitions across projects.</li>
3480
- <li>Enabling reproducible builds where all types and functions are
3481
- referenced by hash.</li>
3482
- </ul>
3483
- <hr />
3484
- <h2 id="summary-14"><strong>16.6 Summary</strong></h2>
3485
- <ul>
3486
- <li>Canonical types and functions can be globally identified by stable
3487
- hashes.</li>
3488
- <li>A simple registry provides lookup and verification of these
3489
- definitions.</li>
3490
- <li>Such registries make k programs portable, self-describing, and safe
3491
- to share between systems.</li>
3492
- </ul>
3493
- <h1 id="appendix-a-implementing-a-prototype-compiler-in-python">Appendix
3494
- A — Implementing a Prototype Compiler in Python</h1>
3495
- <h2 id="a.1-purpose"><strong>A.1 Purpose</strong></h2>
3496
- <p>This appendix outlines how to implement a simple, working prototype
3497
- of the k compiler in Python. The goal is to let the reader experiment
3498
- with parsing, type normalization, and LLVM code generation using only
3499
- standard tools and a few small libraries. The prototype does not need to
3500
- support optimization or a full runtime—only the basic translation
3501
- pipeline.</p>
3502
- <hr />
3503
- <h2 id="a.2-required-environment"><strong>A.2 Required
3504
- environment</strong></h2>
3505
- <p>Install:</p>
3506
- <div class="sourceCode" id="cb121"><pre
3507
- class="sourceCode bash"><code class="sourceCode bash"><span id="cb121-1"><a href="#cb121-1" aria-hidden="true" tabindex="-1"></a><span class="ex">python3</span> <span class="at">-m</span> venv kenv</span>
3508
- <span id="cb121-2"><a href="#cb121-2" aria-hidden="true" tabindex="-1"></a><span class="bu">source</span> kenv/bin/activate</span>
3509
- <span id="cb121-3"><a href="#cb121-3" aria-hidden="true" tabindex="-1"></a><span class="ex">pip</span> install llvmlite</span></code></pre></div>
3510
- <p><code>llvmlite</code> provides an interface to LLVM for code
3511
- generation. No additional dependencies are required.</p>
3512
- <hr />
3513
- <h2 id="a.3-recommended-directory-structure"><strong>A.3 Recommended
3514
- directory structure</strong></h2>
3515
- <pre><code>k-compiler/
3516
- ├── main.py # command-line driver
3517
- ├── parser.py # converts source text to AST
3518
- ├── types.py # canonical type construction
3519
- ├── normalize.py # filter resolution and typing
3520
- ├── ir.py # intermediate representation
3521
- ├── codegen.py # translation from IR to LLVM
3522
- ├── runtime.ll # minimal runtime in LLVM
3523
- └── examples/ # sample k programs</code></pre>
3524
- <p>Each module is small and focused on one task.</p>
3525
- <hr />
3526
- <h2 id="a.4-the-ast"><strong>A.4 The AST</strong></h2>
3527
- <p>Represent the language syntax with Python classes:</p>
3528
- <div class="sourceCode" id="cb123"><pre
3529
- class="sourceCode python"><code class="sourceCode python"><span id="cb123-1"><a href="#cb123-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Expr: <span class="cf">pass</span></span>
3530
- <span id="cb123-2"><a href="#cb123-2" aria-hidden="true" tabindex="-1"></a></span>
3531
- <span id="cb123-3"><a href="#cb123-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Composition(Expr):</span>
3532
- <span id="cb123-4"><a href="#cb123-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, parts): <span class="va">self</span>.parts <span class="op">=</span> parts</span>
3533
- <span id="cb123-5"><a href="#cb123-5" aria-hidden="true" tabindex="-1"></a></span>
3534
- <span id="cb123-6"><a href="#cb123-6" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Product(Expr):</span>
3535
- <span id="cb123-7"><a href="#cb123-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, fields): <span class="va">self</span>.fields <span class="op">=</span> fields <span class="co"># [(label, expr), ...]</span></span>
3536
- <span id="cb123-8"><a href="#cb123-8" aria-hidden="true" tabindex="-1"></a></span>
3537
- <span id="cb123-9"><a href="#cb123-9" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Union(Expr):</span>
3538
- <span id="cb123-10"><a href="#cb123-10" aria-hidden="true" tabindex="-1"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, options): <span class="va">self</span>.options <span class="op">=</span> options <span class="co"># [expr, ...]</span></span>
3539
- <span id="cb123-11"><a href="#cb123-11" aria-hidden="true" tabindex="-1"></a></span>
3540
- <span id="cb123-12"><a href="#cb123-12" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Projection(Expr):</span>
3541
- <span id="cb123-13"><a href="#cb123-13" aria-hidden="true" tabindex="-1"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, label): <span class="va">self</span>.label <span class="op">=</span> label</span>
3542
- <span id="cb123-14"><a href="#cb123-14" aria-hidden="true" tabindex="-1"></a></span>
3543
- <span id="cb123-15"><a href="#cb123-15" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Constant(Expr):</span>
3544
- <span id="cb123-16"><a href="#cb123-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, name): <span class="va">self</span>.name <span class="op">=</span> name</span></code></pre></div>
3545
- <p>The parser builds these objects from source text.</p>
3546
- <hr />
3547
- <h2 id="a.5-type-normalization"><strong>A.5 Type
3548
- normalization</strong></h2>
3549
- <p>Maintain canonical type states as small Python objects:</p>
3550
- <div class="sourceCode" id="cb124"><pre
3551
- class="sourceCode python"><code class="sourceCode python"><span id="cb124-1"><a href="#cb124-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> TypeState:</span>
3552
- <span id="cb124-2"><a href="#cb124-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, kind, transitions):</span>
3553
- <span id="cb124-3"><a href="#cb124-3" aria-hidden="true" tabindex="-1"></a> <span class="va">self</span>.kind <span class="op">=</span> kind <span class="co"># &#39;product&#39; or &#39;union&#39;</span></span>
3554
- <span id="cb124-4"><a href="#cb124-4" aria-hidden="true" tabindex="-1"></a> <span class="va">self</span>.transitions <span class="op">=</span> transitions <span class="co"># [(label, next_state)]</span></span></code></pre></div>
3555
- <p>Normalization expands type aliases and assigns numeric state IDs
3556
- (<code>C0</code>, <code>C1</code>, …). For a prototype, a simple
3557
- structural hash (using <code>json.dumps</code>) can serve as the
3558
- canonical identifier.</p>
3559
- <hr />
3560
- <h2 id="a.6-intermediate-representation"><strong>A.6 Intermediate
3561
- representation</strong></h2>
3562
- <p>Represent IR instructions as simple tuples or small classes:</p>
3563
- <div class="sourceCode" id="cb125"><pre
3564
- class="sourceCode python"><code class="sourceCode python"><span id="cb125-1"><a href="#cb125-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Project: <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, label): <span class="va">self</span>.label <span class="op">=</span> label</span>
3565
- <span id="cb125-2"><a href="#cb125-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Const: <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, node): <span class="va">self</span>.node <span class="op">=</span> node</span>
3566
- <span id="cb125-3"><a href="#cb125-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Seq: <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, parts): <span class="va">self</span>.parts <span class="op">=</span> parts</span>
3567
- <span id="cb125-4"><a href="#cb125-4" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> UnionIR: <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, parts): <span class="va">self</span>.parts <span class="op">=</span> parts</span>
3568
- <span id="cb125-5"><a href="#cb125-5" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> ProductIR:<span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, fields):<span class="va">self</span>.fields <span class="op">=</span> fields</span></code></pre></div>
3569
- <p>A recursive function converts an AST expression into IR following
3570
- Chapter 10.</p>
3571
- <hr />
3572
- <h2 id="a.7-generating-llvm-code"><strong>A.7 Generating LLVM
3573
- code</strong></h2>
3574
- <p>Using <code>llvmlite.ir</code>, create one LLVM function per compiled
3575
- function:</p>
3576
- <div class="sourceCode" id="cb126"><pre
3577
- class="sourceCode python"><code class="sourceCode python"><span id="cb126-1"><a href="#cb126-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> llvmlite <span class="im">import</span> ir</span>
3578
- <span id="cb126-2"><a href="#cb126-2" aria-hidden="true" tabindex="-1"></a></span>
3579
- <span id="cb126-3"><a href="#cb126-3" aria-hidden="true" tabindex="-1"></a>mod <span class="op">=</span> ir.Module(name<span class="op">=</span><span class="st">&quot;k&quot;</span>)</span>
3580
- <span id="cb126-4"><a href="#cb126-4" aria-hidden="true" tabindex="-1"></a></span>
3581
- <span id="cb126-5"><a href="#cb126-5" aria-hidden="true" tabindex="-1"></a><span class="co"># LLVM type definitions</span></span>
3582
- <span id="cb126-6"><a href="#cb126-6" aria-hidden="true" tabindex="-1"></a>KNodePtr <span class="op">=</span> ir.PointerType(ir.IntType(<span class="dv">8</span>))</span>
3583
- <span id="cb126-7"><a href="#cb126-7" aria-hidden="true" tabindex="-1"></a>KVal <span class="op">=</span> ir.LiteralStructType([KNodePtr])</span>
3584
- <span id="cb126-8"><a href="#cb126-8" aria-hidden="true" tabindex="-1"></a>KOpt <span class="op">=</span> ir.LiteralStructType([ir.IntType(<span class="dv">1</span>), KVal])</span>
3585
- <span id="cb126-9"><a href="#cb126-9" aria-hidden="true" tabindex="-1"></a></span>
3586
- <span id="cb126-10"><a href="#cb126-10" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> emit_function(name, ir_expr):</span>
3587
- <span id="cb126-11"><a href="#cb126-11" aria-hidden="true" tabindex="-1"></a> fn_type <span class="op">=</span> ir.FunctionType(KOpt, [KVal])</span>
3588
- <span id="cb126-12"><a href="#cb126-12" aria-hidden="true" tabindex="-1"></a> fn <span class="op">=</span> ir.Function(mod, fn_type, name<span class="op">=</span>name)</span>
3589
- <span id="cb126-13"><a href="#cb126-13" aria-hidden="true" tabindex="-1"></a> block <span class="op">=</span> fn.append_basic_block(<span class="st">&#39;entry&#39;</span>)</span>
3590
- <span id="cb126-14"><a href="#cb126-14" aria-hidden="true" tabindex="-1"></a> builder <span class="op">=</span> ir.IRBuilder(block)</span>
3591
- <span id="cb126-15"><a href="#cb126-15" aria-hidden="true" tabindex="-1"></a> <span class="co"># translate ir_expr recursively into builder calls</span></span>
3592
- <span id="cb126-16"><a href="#cb126-16" aria-hidden="true" tabindex="-1"></a> builder.ret(ir.Constant(KOpt, (ir.Constant(ir.IntType(<span class="dv">1</span>), <span class="dv">0</span>),</span>
3593
- <span id="cb126-17"><a href="#cb126-17" aria-hidden="true" tabindex="-1"></a> ir.Constant(KVal, ir.Constant(KNodePtr, <span class="va">None</span>)))))</span></code></pre></div>
3594
- <p>The translation patterns follow those described in Chapter 12. Each
3595
- IR node is emitted as a call or conditional block using
3596
- <code>builder.call</code>, <code>builder.if_then</code>, and so on.</p>
3597
- <hr />
3598
- <h2 id="a.8-minimal-runtime"><strong>A.8 Minimal runtime</strong></h2>
3599
- <p>Write a minimal <code>runtime.ll</code> that defines stubs for:</p>
3600
- <div class="sourceCode" id="cb127"><pre
3601
- class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb127-1"><a href="#cb127-1" aria-hidden="true" tabindex="-1"></a><span class="kw">declare</span> <span class="fu">%KOpt</span> <span class="fu">@k_project</span>(<span class="fu">%KVal</span> <span class="fu">%v</span>, <span class="dt">i32</span> <span class="fu">%label</span>)</span>
3602
- <span id="cb127-2"><a href="#cb127-2" aria-hidden="true" tabindex="-1"></a><span class="kw">declare</span> <span class="fu">%KVal</span> <span class="fu">@k_make_product</span>(<span class="dt">i32</span> <span class="fu">%state</span>, <span class="dt">i32</span> <span class="fu">%n</span>, <span class="fu">%KVal</span>* <span class="fu">%children</span>)</span>
3603
- <span id="cb127-3"><a href="#cb127-3" aria-hidden="true" tabindex="-1"></a><span class="kw">declare</span> <span class="fu">%KVal</span> <span class="fu">@k_make_union</span>(<span class="dt">i32</span> <span class="fu">%state</span>, <span class="dt">i32</span> <span class="fu">%tag</span>, <span class="fu">%KVal</span> <span class="fu">%child</span>)</span></code></pre></div>
3604
- <p>These can simply return placeholder constants for testing. Later,
3605
- they can be replaced with the real runtime implemented in C.</p>
3606
- <hr />
3607
- <h2 id="a.9-putting-it-together"><strong>A.9 Putting it
3608
- together</strong></h2>
3609
- <p>A small driver script (<code>main.py</code>) can compile a file and
3610
- emit LLVM text:</p>
3611
- <div class="sourceCode" id="cb128"><pre
3612
- class="sourceCode python"><code class="sourceCode python"><span id="cb128-1"><a href="#cb128-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> parser, normalize, ir, codegen</span>
3613
- <span id="cb128-2"><a href="#cb128-2" aria-hidden="true" tabindex="-1"></a></span>
3614
- <span id="cb128-3"><a href="#cb128-3" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> compile_file(path):</span>
3615
- <span id="cb128-4"><a href="#cb128-4" aria-hidden="true" tabindex="-1"></a> src <span class="op">=</span> <span class="bu">open</span>(path).read()</span>
3616
- <span id="cb128-5"><a href="#cb128-5" aria-hidden="true" tabindex="-1"></a> ast <span class="op">=</span> parser.parse(src)</span>
3617
- <span id="cb128-6"><a href="#cb128-6" aria-hidden="true" tabindex="-1"></a> typed <span class="op">=</span> normalize.process(ast)</span>
3618
- <span id="cb128-7"><a href="#cb128-7" aria-hidden="true" tabindex="-1"></a> ir_tree <span class="op">=</span> ir.from_ast(typed)</span>
3619
- <span id="cb128-8"><a href="#cb128-8" aria-hidden="true" tabindex="-1"></a> llvm_module <span class="op">=</span> codegen.emit(ir_tree)</span>
3620
- <span id="cb128-9"><a href="#cb128-9" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="bu">str</span>(llvm_module))</span></code></pre></div>
3621
- <p>Run:</p>
3622
- <div class="sourceCode" id="cb129"><pre
3623
- class="sourceCode bash"><code class="sourceCode bash"><span id="cb129-1"><a href="#cb129-1" aria-hidden="true" tabindex="-1"></a><span class="ex">python</span> main.py examples/neg.k <span class="op">&gt;</span> neg.ll</span>
3624
- <span id="cb129-2"><a href="#cb129-2" aria-hidden="true" tabindex="-1"></a><span class="fu">clang</span> <span class="at">-O2</span> neg.ll runtime.ll <span class="at">-o</span> neg</span></code></pre></div>
3625
- <hr />
3626
- <h2 id="a.10-suggested-extensions"><strong>A.10 Suggested
3627
- extensions</strong></h2>
3628
- <ol type="1">
3629
- <li>Implement the runtime functions in Python for quick testing.</li>
3630
- <li>Add a textual REPL that reads a k expression and prints its IR.</li>
3631
- <li>Integrate a simple interpreter to compare interpreter and compiled
3632
- results.</li>
3633
- <li>Use hashing of canonical forms to name generated LLVM
3634
- functions.</li>
3635
- </ol>
3636
- <hr />
3637
- <h2 id="a.11-summary"><strong>A.11 Summary</strong></h2>
3638
- <p>A prototype compiler can be realized in fewer than a thousand lines
3639
- of Python. It can parse k definitions, construct canonical types,
3640
- translate expressions into IR, and generate valid LLVM code. Such a
3641
- prototype is enough to experiment with all ideas presented in this
3642
- textbook and to verify the semantics of the k language in practice.</p>
3643
- <hr />
3644
- <h1
3645
- id="appendix-b-incorporating-external-predefined-types-and-functions">Appendix
3646
- B — Incorporating External Predefined Types and Functions</h1>
3647
- <h2 id="b.1-purpose"><strong>B.1 Purpose</strong></h2>
3648
- <p>The k language is intentionally minimal. Nevertheless, real systems
3649
- often need to interact with data types and operations defined outside of
3650
- k—for example, numeric values, text, or platform-specific constants.
3651
- This appendix explains how external predefined types and functions can
3652
- be introduced into a k compiler without changing the language
3653
- itself.</p>
3654
- <hr />
3655
- <h2 id="b.2-external-types"><strong>B.2 External types</strong></h2>
3656
- <p>An <strong>external type</strong> is a canonical type that is
3657
- <em>not</em> expressed through k’s own product-and-union syntax but is
3658
- known to the compiler through registration.</p>
3659
- <p>Each external type has:</p>
3660
- <table>
3661
- <colgroup>
3662
- <col style="width: 21%" />
3663
- <col style="width: 78%" />
3664
- </colgroup>
3665
- <thead>
3666
- <tr>
3667
- <th>Field</th>
3668
- <th>Description</th>
3669
- </tr>
3670
- </thead>
3671
- <tbody>
3672
- <tr>
3673
- <td><strong>Name</strong></td>
3674
- <td>symbolic name (e.g., <code>$int</code>, <code>$string</code>)</td>
3675
- </tr>
3676
- <tr>
3677
- <td><strong>Hash</strong></td>
3678
- <td>unique stable identifier, just like canonical types</td>
3679
- </tr>
3680
- <tr>
3681
- <td><strong>Runtime kind</strong></td>
3682
- <td>how the value is stored in memory (pointer, immediate integer,
3683
- etc.)</td>
3684
- </tr>
3685
- <tr>
3686
- <td><strong>Adapter functions</strong></td>
3687
- <td>conversion between the external representation and the standard
3688
- <code>KNode</code> tree</td>
3689
- </tr>
3690
- </tbody>
3691
- </table>
3692
- <p>Example registry entry:</p>
3693
- <div class="sourceCode" id="cb130"><pre
3694
- class="sourceCode json"><code class="sourceCode json"><span id="cb130-1"><a href="#cb130-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
3695
- <span id="cb130-2"><a href="#cb130-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;hash&quot;</span><span class="fu">:</span> <span class="st">&quot;E001&quot;</span><span class="fu">,</span></span>
3696
- <span id="cb130-3"><a href="#cb130-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;kind&quot;</span><span class="fu">:</span> <span class="st">&quot;type&quot;</span><span class="fu">,</span></span>
3697
- <span id="cb130-4"><a href="#cb130-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;external&quot;</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
3698
- <span id="cb130-5"><a href="#cb130-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;name&quot;</span><span class="fu">:</span> <span class="st">&quot;$int&quot;</span><span class="fu">,</span></span>
3699
- <span id="cb130-6"><a href="#cb130-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;runtime_kind&quot;</span><span class="fu">:</span> <span class="st">&quot;primitive_i64&quot;</span></span>
3700
- <span id="cb130-7"><a href="#cb130-7" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
3701
- <p>The compiler treats such a type as an atomic node, represented
3702
- internally as a single <code>KNode</code> with <code>arity = 0</code>
3703
- but tagged as <em>external</em>.</p>
3704
- <hr />
3705
- <h2 id="b.3-external-constructors"><strong>B.3 External
3706
- constructors</strong></h2>
3707
- <p>External types may provide special constructors or constants. For
3708
- example, <code>$int</code> might include predefined constant
3709
- functions:</p>
3710
- <pre><code>zero = {} $int;
3711
- one = {} $int;</code></pre>
3712
- <p>At compile time these appear as constant functions returning fixed
3713
- external nodes provided by the runtime.</p>
3714
- <hr />
3715
- <h2 id="b.4-external-functions"><strong>B.4 External
3716
- functions</strong></h2>
3717
- <p>External functions are partial functions implemented outside of k but
3718
- declared inside a k program. They have known input and output types,
3719
- possibly external.</p>
3720
- <p>Declaration syntax:</p>
3721
- <pre><code>extern add : $int $int → $int;
3722
- extern less : $int $int → $bool;</code></pre>
3723
- <p>At compile time the compiler records the signature and associates it
3724
- with a runtime symbol name such as <code>k_ext_add</code>.</p>
3725
- <p>When generating code, each external call becomes a standard function
3726
- call following the ABI:</p>
3727
- <div class="sourceCode" id="cb133"><pre
3728
- class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb133-1"><a href="#cb133-1" aria-hidden="true" tabindex="-1"></a><span class="kw">declare</span> <span class="fu">%KOpt</span> <span class="fu">@k_ext_add</span>(<span class="fu">%KVal</span> <span class="fu">%a</span>, <span class="fu">%KVal</span> <span class="fu">%b</span>)</span></code></pre></div>
3729
- <p>The runtime library provides these implementations in a native
3730
- language (C, C++, Rust, etc.).</p>
3731
- <hr />
3732
- <h2 id="b.5-integration-with-canonical-types"><strong>B.5 Integration
3733
- with canonical types</strong></h2>
3734
- <p>External types are integrated into the canonical system as <em>leaf
3735
- states</em>. They can appear as components in products or unions just
3736
- like built-in ones.</p>
3737
- <p>Example:</p>
3738
- <pre><code>$point = { $int x, $int y };</code></pre>
3739
- <p>Canonical form:</p>
3740
- <pre><code>$C0 = { C1 &quot;x&quot;, C1 &quot;y&quot; };
3741
- $C1 = external $int;</code></pre>
3742
- <p>This allows normal serialization and type comparison; the external
3743
- leaf is treated as opaque but identified by its hash.</p>
3744
- <hr />
3745
- <h2 id="b.6-serialization-and-external-values"><strong>B.6 Serialization
3746
- and external values</strong></h2>
3747
- <p>During serialization, an external node is encoded by:</p>
3748
- <ol type="1">
3749
- <li>Its type hash (to indicate which external kind it represents).</li>
3750
- <li>A binary blob produced by a runtime-supplied encoder for that
3751
- type.</li>
3752
- </ol>
3753
- <p>Deserialization reverses the process using the corresponding decoder.
3754
- All external codecs must be deterministic and version-stable to preserve
3755
- canonical equality.</p>
3756
- <hr />
3757
- <h2 id="b.7-example"><strong>B.7 Example</strong></h2>
3758
- <p>Suppose we introduce <code>$int</code> and external function
3759
- <code>add</code>:</p>
3760
- <pre><code>$pair_int = { $int a, $int b };
3761
- sum = { .a x, .b y } (add x y);</code></pre>
3762
- <p>The compiler generates code that:</p>
3763
- <ul>
3764
- <li>projects fields <code>.a</code> and <code>.b</code>,</li>
3765
- <li>passes them as <code>KVal</code> pointers to
3766
- <code>@k_ext_add</code>,</li>
3767
- <li>and returns the result as a new <code>$int</code> node.</li>
3768
- </ul>
3769
- <p>All logic outside arithmetic remains standard k code.</p>
3770
- <hr />
3771
- <h2 id="b.8-practical-implementation"><strong>B.8 Practical
3772
- implementation</strong></h2>
3773
- <p>In a Python prototype:</p>
3774
- <div class="sourceCode" id="cb137"><pre
3775
- class="sourceCode python"><code class="sourceCode python"><span id="cb137-1"><a href="#cb137-1" aria-hidden="true" tabindex="-1"></a>EXTERNAL_TYPES <span class="op">=</span> {</span>
3776
- <span id="cb137-2"><a href="#cb137-2" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;$int&quot;</span>: {<span class="st">&quot;hash&quot;</span>: <span class="st">&quot;E001&quot;</span>, <span class="st">&quot;kind&quot;</span>: <span class="st">&quot;external&quot;</span>, <span class="st">&quot;runtime_kind&quot;</span>: <span class="st">&quot;primitive_i64&quot;</span>}</span>
3777
- <span id="cb137-3"><a href="#cb137-3" aria-hidden="true" tabindex="-1"></a>}</span>
3778
- <span id="cb137-4"><a href="#cb137-4" aria-hidden="true" tabindex="-1"></a></span>
3779
- <span id="cb137-5"><a href="#cb137-5" aria-hidden="true" tabindex="-1"></a>EXTERNAL_FUNCS <span class="op">=</span> {</span>
3780
- <span id="cb137-6"><a href="#cb137-6" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;add&quot;</span>: {<span class="st">&quot;inputs&quot;</span>: [<span class="st">&quot;$int&quot;</span>, <span class="st">&quot;$int&quot;</span>], <span class="st">&quot;output&quot;</span>: <span class="st">&quot;$int&quot;</span>, <span class="st">&quot;symbol&quot;</span>: <span class="st">&quot;k_ext_add&quot;</span>},</span>
3781
- <span id="cb137-7"><a href="#cb137-7" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;less&quot;</span>: {<span class="st">&quot;inputs&quot;</span>: [<span class="st">&quot;$int&quot;</span>, <span class="st">&quot;$int&quot;</span>], <span class="st">&quot;output&quot;</span>: <span class="st">&quot;$bool&quot;</span>, <span class="st">&quot;symbol&quot;</span>: <span class="st">&quot;k_ext_less&quot;</span>}</span>
3782
- <span id="cb137-8"><a href="#cb137-8" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
3783
- <p>During code generation, when a call refers to an external function,
3784
- the compiler emits a call to the symbol given in the table.</p>
3785
- <hr />
3786
- <h2 id="b.9-summary"><strong>B.9 Summary</strong></h2>
3787
- <ul>
3788
- <li>External predefined types extend k without altering its core
3789
- semantics.</li>
3790
- <li>They are registered with hashes and treated as atomic nodes.</li>
3791
- <li>External functions follow the same calling convention as normal
3792
- ones.</li>
3793
- <li>Serialization of external values uses type-specific codecs.</li>
3794
- <li>This mechanism allows integration of native computations (numbers,
3795
- strings, system data) while preserving the purity and determinism of the
3796
- k language.</li>
3797
- </ul>
3798
- <hr />