@fraczak/k 7.0.2 → 7.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +75 -0
- package/DOCS/CODECS.md +37 -2
- package/DOCS/CODEC_ARCHITECTURE.md +12 -5
- package/DOCS/FILE_FORMATS.md +238 -15
- package/DOCS/POLYMORPHIC_IR.md +104 -0
- package/DOCS/REPL.md +11 -3
- package/DOCS/WEB_REPL_REQUIREMENTS.md +1 -1
- package/JOURNAL.md +288 -0
- package/README.md +12 -3
- package/Value.mjs +28 -3
- package/access-table.mjs +343 -0
- package/backend-api.mjs +23 -1
- package/backends/llvm/README.md +20 -21
- package/backends/llvm/bin/k-llvm-build.mjs +105 -32
- package/backends/llvm/bin/k-llvm-compile.mjs +63 -24
- package/backends/llvm/bin/k-llvm.mjs +292 -0
- package/backends/llvm/runtime/krt.c +8 -0
- package/backends/llvm/runtime/krt.h +1 -0
- package/backends/llvm/src/cli.mjs +95 -17
- package/backends/llvm/src/executable.mjs +128 -11
- package/backends/llvm/src/kvm2llvm.mjs +10 -5
- package/backends/llvm/src/llvm.mjs +121 -9
- package/backends/llvm/tests/integration.sh +11 -11
- package/backends/llvm/{bin → tests}/k-llvm-run.mjs +48 -22
- package/backends/llvm/tests/perf-support.mjs +24 -3
- package/backends/llvm/tests/test-llvm.mjs +22 -1
- package/backends/wasm/bin/k-wasm-compile.mjs +46 -20
- package/backends/wasm/bin/k-wasm-run.mjs +61 -20
- package/backends/wasm/bin/k-wasm.mjs +47 -13
- package/backends/wasm/src/cli.mjs +141 -19
- package/backends/wasm/src/wasm.mjs +130 -23
- package/browser/repl-browser.mjs +16 -5
- package/browser/tree-view.mjs +47 -8
- package/browser/vfs-data.mjs +6 -5
- package/codecs/README.md +1 -0
- package/codecs/djson.mjs +270 -0
- package/codecs/int.mjs +2 -1
- package/codecs/json.mjs +7 -2
- package/codecs/k-parse.mjs +36 -9
- package/codecs/k-print.mjs +26 -6
- package/codecs/runtime/codec-sdk.mjs +24 -6
- package/codecs/runtime/pattern-json.mjs +80 -1
- package/codecs/runtime/prefix-codec.mjs +629 -67
- package/codecs/runtime/show-value.mjs +93 -51
- package/codecs/runtime/unicode-string.mjs +29 -6
- package/codecs/show.mjs +24 -6
- package/codecs/utf16.mjs +2 -1
- package/k.mjs +56 -16
- package/kir.mjs +58 -19
- package/kvm.mjs +49 -12
- package/objects/compile.mjs +37 -23
- package/objects/decompile.mjs +40 -10
- package/objects/extract-aliases.mjs +44 -14
- package/objects/inspect.mjs +19 -14
- package/objects/validate.mjs +18 -11
- package/package.json +11 -3
- package/pkir.mjs +772 -0
- package/repl.mjs +92 -23
- package/scripts/build-repl-html.mjs +22 -3
- package/scripts/perf-ieee.mjs +264 -13
- package/scripts/perf-int.mjs +315 -22
- package/scripts/perf-multiplication.mjs +58 -7
- package/scripts/perf-poly.mjs +306 -24
- package/scripts/run-tests.mjs +3 -0
- package/tests/test-access-table.mjs +213 -0
- package/tests/test-codecs.mjs +168 -0
- package/tests/test-pkir.mjs +530 -0
- package/tests/test-polymorphic-tdd.mjs +196 -0
- package/tests/test-repl-html.mjs +16 -2
- package/tests/test-repl.mjs +63 -1
- package/backends/llvm/bin/k-llvm-jit.mjs +0 -160
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,81 @@ All notable changes to this project will be documented here.
|
|
|
5
5
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
6
|
This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [7.2.0] — 2026-10-17 — Dynamic JSON Codec (djson) & Lazy Wire Decoding
|
|
9
|
+
|
|
10
|
+
### Features & Performance Improvements
|
|
11
|
+
|
|
12
|
+
- **Universal Dynamic JSON Codec (`codecs/djson.mjs`, `k-djson`)**:
|
|
13
|
+
- Added a standalone dynamic JSON codec (`djson.mjs` / `k-djson`)
|
|
14
|
+
based on a single 29-node recursive pattern `JSON = < number,
|
|
15
|
+
string, bool, null, list, object >`, where arrays are encoded as
|
|
16
|
+
arbitrary-length `cons`/`nil` lists and objects as `cons`/`nil`
|
|
17
|
+
lists of `{ key, val }` pairs.
|
|
18
|
+
- Kept the existing schema-specializing `json.mjs` (`k-json`) as an
|
|
19
|
+
alternative record-oriented JSON codec.
|
|
20
|
+
- Integrated `djson.mjs` into the CLI, REPL, and Web REPL (`repl.html`
|
|
21
|
+
VFS).
|
|
22
|
+
|
|
23
|
+
- **Lazy Prefix-Free Wire Decoding & Fast Bitstream I/O**:
|
|
24
|
+
- Implemented lazy wire decoding (`LazyGeneralProduct` and
|
|
25
|
+
`LazyGeneralVariant`) with precomputed fixed-width bit sizes and
|
|
26
|
+
static field offsets on pattern graphs.
|
|
27
|
+
- Optimized bitstream reading/writing (`BitReader` / `BitWriter`) with
|
|
28
|
+
word-level operations, pre-encoded closed pattern bytes, and direct
|
|
29
|
+
bitstream-to-codepoint UTF-8 string decoding without intermediate
|
|
30
|
+
AST allocations.
|
|
31
|
+
|
|
32
|
+
- **Stack-Safe & Bounded Value Rendering**:
|
|
33
|
+
- Converted `valueToK`, `valueWithEnvelopeToK`, and wire serialization
|
|
34
|
+
to iterative stack-safe algorithms with early character truncation
|
|
35
|
+
(`maxChars`).
|
|
36
|
+
- Added `:limit [num|none]` command and `--limit=<num>` CLI flag in
|
|
37
|
+
`repl.mjs` (default: `4096` chars) and bounded DOM tree previews in
|
|
38
|
+
`repl.html`.
|
|
39
|
+
- Handled broken pipe (`EPIPE`) cleanly across codec CLI entrypoints.
|
|
40
|
+
|
|
41
|
+
## [7.1.0] — 2026-10-16 — Polymorphic K IR (PKIR) & CLI Standardization
|
|
42
|
+
|
|
43
|
+
### Features & Architecture Improvements
|
|
44
|
+
|
|
45
|
+
- **Polymorphic K IR (PKIR) & Access Table Engine**:
|
|
46
|
+
- Implemented `pkir.mjs` providing an intermediate representation
|
|
47
|
+
tailored for polymorphic relations with variant dispatch, projection
|
|
48
|
+
tables, and partial function failure semantics.
|
|
49
|
+
- Implemented `access-table.mjs` (`buildAccessTable`) for resolving
|
|
50
|
+
field offsets and variant selectors across arbitrary schemas.
|
|
51
|
+
- Added PKIR specialization (`specializePKIR`) eliminating dead
|
|
52
|
+
branches and baking in direct physical offsets.
|
|
53
|
+
- Supported PKIR execution and standalone executable generation across
|
|
54
|
+
both WebAssembly and LLVM backends.
|
|
55
|
+
- Added dedicated test suites: `tests/test-pkir.mjs`,
|
|
56
|
+
`tests/test-access-table.mjs`, and `tests/test-polymorphic-tdd.mjs`.
|
|
57
|
+
- Added specification and documentation in `DOCS/POLYMORPHIC_IR.md`
|
|
58
|
+
and updated `DOCS/FILE_FORMATS.md`.
|
|
59
|
+
|
|
60
|
+
- **Web REPL (`repl.html`) & Wasm Integration**:
|
|
61
|
+
- Enabled `.pkir` generation and lowering to WebAssembly in
|
|
62
|
+
`repl.mjs` and `repl.html`.
|
|
63
|
+
- Promoted Web REPL visibility in `README.md` (top banner,
|
|
64
|
+
zero-install section, further reading).
|
|
65
|
+
|
|
66
|
+
- **Multi-Backend CLI Standardization & Help Completeness**:
|
|
67
|
+
- Standardized CLI syntax, argument parsing, options, and help text
|
|
68
|
+
(`-h` / `--help`) across tools in `backends/*/bin/` and
|
|
69
|
+
`objects/`.
|
|
70
|
+
- Consolidated `backends/llvm/bin/` (`k-llvm.mjs`, `k-llvm-build.mjs`,
|
|
71
|
+
`k-llvm-compile.mjs`) to mirror `backends/wasm/bin/`.
|
|
72
|
+
- Aligned `--lib` and `--export` options across LLVM, Wasm, and object
|
|
73
|
+
tools.
|
|
74
|
+
- Documented explicit defaults (such as cache directories, Clang
|
|
75
|
+
optimization levels, and runtime modes) in CLI help texts.
|
|
76
|
+
|
|
77
|
+
- **Concurrent Multi-Backend Performance Benchmarks**:
|
|
78
|
+
- Added concurrent `llvm` and `llvm-pkir` execution lanes across all
|
|
79
|
+
performance suites (`perf:ieee`, `perf:int`, `perf:poly`,
|
|
80
|
+
`perf:mult`).
|
|
81
|
+
- Documented benchmark findings and throughput in `JOURNAL.md`.
|
|
82
|
+
|
|
8
83
|
## [7.0.2] — 2026-10-13 — LLVM Squaring Scaling & Backend Streamlining
|
|
9
84
|
|
|
10
85
|
### Features & Performance Improvements
|
package/DOCS/CODECS.md
CHANGED
|
@@ -141,6 +141,40 @@ printf 'yes\n' | ./codecs/yesno.mjs --parse | ./codecs/yesno.mjs --print
|
|
|
141
141
|
# Output: yes
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
+
## Built-in Codecs
|
|
145
|
+
|
|
146
|
+
The `codecs/` directory provides the following standard codecs:
|
|
147
|
+
|
|
148
|
+
- **`int.mjs` (`k-int`)**: Decimal integers and bracketed integer lists
|
|
149
|
+
(e.g. `42`, `-15`, `[1, 2, 3]`) mapped to signed binary bit trees and
|
|
150
|
+
`cons`/`nil` lists.
|
|
151
|
+
- **`ieee.mjs` (`k-ieee`)**: IEEE 754 64-bit floating-point numbers
|
|
152
|
+
(`sign`, `exponent`, `fraction`).
|
|
153
|
+
- **`utf8.mjs` (`k-utf8`) & `utf16.mjs` (`k-utf16`)**: Unicode strings
|
|
154
|
+
encoded as `cons`/`nil` code-point lists (`str` in `core.k`).
|
|
155
|
+
- **`unit.mjs` (`k-unit`)**: The unit value `{}`.
|
|
156
|
+
- **`json.mjs` (`k-json`) — Schema-Specializing JSON**:
|
|
157
|
+
Derives a document-specific pattern for each JSON value:
|
|
158
|
+
- JSON objects map directly to products `{ field: val, ... }`.
|
|
159
|
+
- JSON arrays map to indexed products `{ "0": a0, "1": a1, ... }`.
|
|
160
|
+
- Ideal for record-oriented projection (e.g. `.user .name`).
|
|
161
|
+
- **`djson.mjs` (`k-djson`) — Universal Dynamic JSON**:
|
|
162
|
+
Maps every JSON document to a single universal recursive pattern
|
|
163
|
+
`JSON`:
|
|
164
|
+
```k
|
|
165
|
+
?<
|
|
166
|
+
float64 number,
|
|
167
|
+
str string,
|
|
168
|
+
< {} true, {} false > bool,
|
|
169
|
+
{} null,
|
|
170
|
+
< {} nil, { JSON car, LIST cdr } cons >=LIST list,
|
|
171
|
+
< {} nil, { { str key, JSON val } car, OBJ cdr } cons >=OBJ object
|
|
172
|
+
>=JSON
|
|
173
|
+
```
|
|
174
|
+
Because every JSON value shares the exact same static 29-node pattern,
|
|
175
|
+
a `k` relation can be compiled once against `JSON` and process
|
|
176
|
+
arbitrary JSON documents of any shape or array/object length.
|
|
177
|
+
|
|
144
178
|
## Testing a Codec
|
|
145
179
|
|
|
146
180
|
For CLI codecs, test both directions in a pipeline:
|
|
@@ -174,8 +208,9 @@ npm test
|
|
|
174
208
|
## Web REPL (VFS) Bundling
|
|
175
209
|
|
|
176
210
|
When `repl.html` is generated (`npm run build:repl-html`):
|
|
177
|
-
- Codecs (`int.mjs`, `json.mjs`, `
|
|
178
|
-
bundled into 100% self-contained ES modules with zero
|
|
211
|
+
- Codecs (`int.mjs`, `json.mjs`, `djson.mjs`, `utf8.mjs`, `unit.mjs`,
|
|
212
|
+
`ieee.mjs`) are bundled into 100% self-contained ES modules with zero
|
|
213
|
+
imports.
|
|
179
214
|
- `runCodecCLI` is shimmed as a no-op, and `Value` helpers are directly
|
|
180
215
|
inlined.
|
|
181
216
|
- In the browser, the VFS serves these self-contained modules directly to
|
|
@@ -192,11 +192,16 @@ runCodecCLI(import.meta.url, { parse, print, doc });
|
|
|
192
192
|
pathToFileURL(process.argv[1]).href`). If imported as a module or
|
|
193
193
|
running in a browser, it is a no-op.
|
|
194
194
|
2. **Flag Parsing**: Handles `--parse`, `--print`, and `-h` / `--help`.
|
|
195
|
-
3. **Stream Piping**:
|
|
195
|
+
3. **Stream Piping & Lazy Wire Decoding**:
|
|
196
196
|
- For `--parse`: reads `stdin` to string, calls `parse(text)`, encodes
|
|
197
197
|
enveloped value `(P, v)` to binary wire format on `stdout`.
|
|
198
|
-
- For `--print`: decodes wire format from `stdin` into
|
|
199
|
-
`
|
|
198
|
+
- For `--print`: lazily decodes the wire format from `stdin` into
|
|
199
|
+
bitstream-backed `Value` proxies (`LazyGeneralProduct`,
|
|
200
|
+
`LazyGeneralVariant`) with precomputed fixed-width bit sizes and
|
|
201
|
+
static field offsets, calls `print(value)`, and writes formatted text
|
|
202
|
+
to `stdout`.
|
|
203
|
+
- Cleanly exits on `EPIPE` when piped into downstream consumers like
|
|
204
|
+
`head`.
|
|
200
205
|
|
|
201
206
|
---
|
|
202
207
|
|
|
@@ -207,7 +212,8 @@ To make `codecs/` intuitive and self-contained:
|
|
|
207
212
|
```text
|
|
208
213
|
codecs/
|
|
209
214
|
├── int.mjs # Integer & list codec
|
|
210
|
-
├── json.mjs # JSON codec
|
|
215
|
+
├── json.mjs # JSON codec (schema-specializing)
|
|
216
|
+
├── djson.mjs # Dynamic JSON codec (singleton pattern)
|
|
211
217
|
├── utf8.mjs # UTF-8 string codec
|
|
212
218
|
├── utf16.mjs # UTF-16 string codec
|
|
213
219
|
├── ieee.mjs # IEEE 754 float codec
|
|
@@ -236,7 +242,8 @@ In the browser REPL (`repl.html`):
|
|
|
236
242
|
imports**.
|
|
237
243
|
- **No Runtime Files in VFS**: `codecs/runtime/*` is not included in the
|
|
238
244
|
browser VFS. The VFS only contains verified, self-contained user-facing
|
|
239
|
-
files (`int.mjs`, `json.mjs`, `
|
|
245
|
+
files (`int.mjs`, `json.mjs`, `djson.mjs`, `utf8.mjs`, `unit.mjs`,
|
|
246
|
+
`ieee.mjs`).
|
|
240
247
|
- **Native Browser Loading**: In `repl-codecs.mjs`, the browser reads the
|
|
241
248
|
codec source from VFS, wraps it in a Blob, and invokes native `await
|
|
242
249
|
import(blobUrl)`. No regex manipulation, import stripping, or global
|
package/DOCS/FILE_FORMATS.md
CHANGED
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
# File Formats in the K Universe
|
|
2
2
|
|
|
3
|
-
The `k` toolchain operates across
|
|
4
|
-
`.ko`, `.klib`, and `.
|
|
5
|
-
in the pipeline from human-authored source to ahead-of-time
|
|
6
|
-
type-checked artifacts
|
|
3
|
+
The `k` toolchain operates across five primary file formats: `.k`,
|
|
4
|
+
`.ko`, `.klib`, `.kvm`, and `.pkir`. Each format occupies a distinct
|
|
5
|
+
position in the pipeline from human-authored source to ahead-of-time
|
|
6
|
+
(AOT) type-checked artifacts, intermediate representations, and
|
|
7
|
+
JIT/native execution.
|
|
7
8
|
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
## Overview & Comparison
|
|
11
12
|
|
|
12
|
-
| Extension
|
|
13
|
-
|
|
14
|
-
| **`.k`**
|
|
15
|
-
| **`.ko`**
|
|
16
|
-
| **`.klib
|
|
17
|
-
| **`.kvm`** | Polymorphic kVM
|
|
13
|
+
| Extension | Role | Format / Magic | Entrypoint |
|
|
14
|
+
|:---:|:---|:---|:---|
|
|
15
|
+
| **`.k`** | Human source code | UTF-8 plain text | Optional |
|
|
16
|
+
| **`.ko`** | Executable object | Binary (`KOBJ\n`) | Required |
|
|
17
|
+
| **`.klib`** | Reusable library | UTF-8 JSON | None |
|
|
18
|
+
| **`.kvm`** | Polymorphic kVM IR | `k-vm` (KVM-P) | Relations |
|
|
19
|
+
| **`.pkir`** | Polymorphic IR | `pk-ir` (v1) | Relations |
|
|
20
|
+
|
|
21
|
+
| Extension | Generated By | Consumed By |
|
|
22
|
+
|:---:|:---|:---|
|
|
23
|
+
| **`.k`** | Editor, `k-decompile` | `k.mjs`, `k-compile`, backends |
|
|
24
|
+
| **`.ko`** | `k-compile`, REPL (`:ko`) | `k.mjs`, backends, tools |
|
|
25
|
+
| **`.klib`** | `k-compile --lib` | REPL, linkers (`--lib`) |
|
|
26
|
+
| **`.kvm`** | `k-compile --format kvm` | `kvm.mjs`, backends |
|
|
27
|
+
| **`.pkir`** | `compileRelationToPKIR` | `executePKIR`, specializer |
|
|
18
28
|
|
|
19
29
|
### Format Transformation Workflow
|
|
20
30
|
|
|
@@ -30,20 +40,22 @@ flowchart TD
|
|
|
30
40
|
KO[".ko (Executable Object)"]
|
|
31
41
|
end
|
|
32
42
|
|
|
33
|
-
subgraph IR_Artifacts ["
|
|
34
|
-
KVM[".kvm (
|
|
43
|
+
subgraph IR_Artifacts ["Intermediate Representations"]
|
|
44
|
+
KVM[".kvm (kVM Bytecode)"]
|
|
45
|
+
PKIR[".pkir (Polymorphic IR)"]
|
|
35
46
|
end
|
|
36
47
|
|
|
37
48
|
subgraph Targets ["Execution Targets"]
|
|
38
49
|
WASM[".wasm (WebAssembly)"]
|
|
39
50
|
NATIVE["Native Binary"]
|
|
40
|
-
INTERP["Interpreter
|
|
51
|
+
INTERP["Interpreter / kVM / PKIR"]
|
|
41
52
|
end
|
|
42
53
|
|
|
43
54
|
%% Transformations from .k
|
|
44
55
|
K -->|"k-compile"| KO
|
|
45
56
|
K -->|"k-compile --lib"| KLIB
|
|
46
57
|
K -->|"k-compile --format kvm"| KVM
|
|
58
|
+
K -->|"compileRelationToPKIR"| PKIR
|
|
47
59
|
K -->|":load"| REPL
|
|
48
60
|
|
|
49
61
|
%% REPL exports
|
|
@@ -60,11 +72,22 @@ flowchart TD
|
|
|
60
72
|
KO -->|"k-llvm-build"| NATIVE
|
|
61
73
|
KO -->|"k.mjs"| INTERP
|
|
62
74
|
KO -->|"k-decompile"| K
|
|
75
|
+
KO -->|"compileRelationToPKIR"| PKIR
|
|
63
76
|
|
|
64
77
|
%% Lowering from .kvm
|
|
65
78
|
KVM -->|"k-wasm-compile"| WASM
|
|
66
79
|
KVM -->|"k-llvm-build"| NATIVE
|
|
67
80
|
KVM -->|"kvm.mjs / specializeKVM"| INTERP
|
|
81
|
+
|
|
82
|
+
%% Execution and Specialization from .pkir
|
|
83
|
+
PKIR -->|"executePKIR + AccessTable"| INTERP
|
|
84
|
+
PKIR -->|"specializePKIR"| PKIR_SPEC["Specialized PKIR"]
|
|
85
|
+
PKIR -->|"k-wasm-compile"| WASM
|
|
86
|
+
PKIR -->|"k-llvm-compile"| LLVM[".ll (LLVM IR)"]
|
|
87
|
+
PKIR -->|"k-llvm-build"| NATIVE
|
|
88
|
+
PKIR_SPEC -->|"executePKIR"| INTERP
|
|
89
|
+
PKIR_SPEC -->|"backend lowering"| WASM
|
|
90
|
+
PKIR_SPEC -->|"backend lowering"| NATIVE
|
|
68
91
|
```
|
|
69
92
|
|
|
70
93
|
---
|
|
@@ -365,6 +388,204 @@ k-compile add5.ko add5.kvm
|
|
|
365
388
|
|
|
366
389
|
---
|
|
367
390
|
|
|
391
|
+
## 5. `.pkir` — Polymorphic K Intermediate Representation File
|
|
392
|
+
|
|
393
|
+
### What It Is
|
|
394
|
+
`.pkir` is a state-indexed, slot-addressed intermediate representation
|
|
395
|
+
artifact (`format: "pk-ir"`, `version: 1`).
|
|
396
|
+
|
|
397
|
+
While `.kvm` models imperative register control-flow using symbolic
|
|
398
|
+
field strings (`project_field`, `inst.label`), `.pkir` addresses the
|
|
399
|
+
fundamental data-layout problem for polymorphic functions. It unifies
|
|
400
|
+
streaming bitstream processing and random-access memory tables:
|
|
401
|
+
|
|
402
|
+
1. **Slot Addressing & State Indexing:**
|
|
403
|
+
Eliminates all runtime string lookups (`val.product[label]`). Every
|
|
404
|
+
field access is compiled to an integer slot relative to an abstract
|
|
405
|
+
pattern state (`project_slot`, `slot`, `state`). Every variant test
|
|
406
|
+
is compiled to a branch index (`match_variant`, `branchId`, `state`).
|
|
407
|
+
|
|
408
|
+
2. **Duality of Transducers & Witnesses:**
|
|
409
|
+
- **Streaming Pushdown Transducers:** Navigates prefix-free serialized
|
|
410
|
+
wire streams using static skip counts (`skipCount`). Erasing and
|
|
411
|
+
linear operations execute in $O(\text{depth})$ stack memory with zero
|
|
412
|
+
node materialization.
|
|
413
|
+
- **Layout Witnesses (`AccessTable`):** Operates on random-access
|
|
414
|
+
memory arenas. Given any concrete input schema $S$ and function
|
|
415
|
+
access profile $P$, `buildAccessTable(S, P)` resolves physical byte
|
|
416
|
+
offsets $\Omega(S, P)$ in a single array load.
|
|
417
|
+
|
|
418
|
+
3. **Hybrid `KVal` Fat-Pointer Representation:**
|
|
419
|
+
Values remain compact serialized wire slices by default. When
|
|
420
|
+
non-linear access occurs (e.g. repeated reads or field reordering),
|
|
421
|
+
demand-driven **Spine Promotion** materializes only the outer product
|
|
422
|
+
node into an arena record while leaving child payloads as untouched
|
|
423
|
+
slices. Opaque payloads are never re-encoded or reconstructed.
|
|
424
|
+
|
|
425
|
+
### Payload Structure
|
|
426
|
+
|
|
427
|
+
A `.pkir` artifact is structured as follows:
|
|
428
|
+
|
|
429
|
+
```json
|
|
430
|
+
{
|
|
431
|
+
"format": "pk-ir",
|
|
432
|
+
"version": 1,
|
|
433
|
+
"name": "extract_id",
|
|
434
|
+
"inputReg": "%v0",
|
|
435
|
+
"outputReg": "%v1",
|
|
436
|
+
"inputPattern": 3,
|
|
437
|
+
"outputPattern": 4,
|
|
438
|
+
"patternGraph": { ... },
|
|
439
|
+
"accessProfile": {
|
|
440
|
+
"0": { "fields": ["id"], "variants": [] },
|
|
441
|
+
"3": { "fields": [], "variants": ["click", "sensor", "ping"] }
|
|
442
|
+
},
|
|
443
|
+
"instructions": [
|
|
444
|
+
{
|
|
445
|
+
"op": "union",
|
|
446
|
+
"dest": "%v1",
|
|
447
|
+
"src": "%v0",
|
|
448
|
+
"branches": [ ... ]
|
|
449
|
+
}
|
|
450
|
+
]
|
|
451
|
+
}
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
#### Instruction Set Summary
|
|
455
|
+
- `id`: Register assignment (`{ op: "id", dest, src }`).
|
|
456
|
+
- `project_slot`: State-indexed slot projection
|
|
457
|
+
(`{ op: "project_slot", dest, src, state, slot, label }`).
|
|
458
|
+
- `match_variant`: State-indexed variant match
|
|
459
|
+
(`{ op: "match_variant", dest, src, state, tag, branchId }`).
|
|
460
|
+
- `make_variant`: Variant construction
|
|
461
|
+
(`{ op: "make_variant", dest, src, tag }`).
|
|
462
|
+
- `product`: Product construction with sub-instruction streams.
|
|
463
|
+
- `union`: Multi-branch selection with failure backtracking.
|
|
464
|
+
- `call_rel`: Relation call / recursion
|
|
465
|
+
(`{ op: "call_rel", dest, ref, src }`).
|
|
466
|
+
- `fail`: Unconditional branch failure (`{ op: "fail" }`).
|
|
467
|
+
- **Specialized Instructions:**
|
|
468
|
+
- `project_offset`: Direct memory offset projection:
|
|
469
|
+
`{ op: "project_offset", dest, src, offset, skipCount, childState }`.
|
|
470
|
+
- `match_tag_imm`: Immediate discriminator test
|
|
471
|
+
(`{ op: "match_tag_imm", dest, src, tagId, branchId, childState }`).
|
|
472
|
+
|
|
473
|
+
### Why `.pkir` Exists (What You Gain)
|
|
474
|
+
|
|
475
|
+
1. **Elimination of the Envelope Tax (26x Speedup):**
|
|
476
|
+
Previous polymorphic execution required wrapping values in dynamic
|
|
477
|
+
envelopes $(v, P_v)$, suffering a 26x performance penalty during
|
|
478
|
+
envelope packing/unpacking (`scripts/perf-poly.mjs`). PKIR navigates
|
|
479
|
+
heterogeneous records directly via layout witnesses without envelopes.
|
|
480
|
+
|
|
481
|
+
2. **Sub-30µs Specialization Latency:**
|
|
482
|
+
`specializePKIR` bakes static byte offsets into instructions and prunes
|
|
483
|
+
dead union branches in ~27 microseconds (compared to 100–1500 ms for
|
|
484
|
+
traditional AOT/Wasm compilation), enabling instant JIT tiering.
|
|
485
|
+
|
|
486
|
+
3. **Zero Payload Re-Encoding:**
|
|
487
|
+
Preserves arbitrary opaque payloads (`data: payload_i`) as byte slices
|
|
488
|
+
without traversal or re-serialization during recursive list
|
|
489
|
+
processing (`search`, `poly_rev`).
|
|
490
|
+
|
|
491
|
+
4. **1:1 Machine Code Lowering:**
|
|
492
|
+
Specialized PKIR instructions map directly to WebAssembly (`i64.load
|
|
493
|
+
offset=C`, `i32.eq`) and LLVM machine instructions without dynamic
|
|
494
|
+
runtime fallbacks (`@k_product_get_n`).
|
|
495
|
+
|
|
496
|
+
### How to Generate
|
|
497
|
+
|
|
498
|
+
In JavaScript / Node.js API:
|
|
499
|
+
```javascript
|
|
500
|
+
import { compileRelationToPKIR } from "@fraczak/k/backend-api.mjs";
|
|
501
|
+
|
|
502
|
+
const pkir = compileRelationToPKIR(relDef, "extract_id");
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### How to Consume
|
|
506
|
+
|
|
507
|
+
- **Direct Execution with AccessTable:**
|
|
508
|
+
```javascript
|
|
509
|
+
import {
|
|
510
|
+
executePKIR,
|
|
511
|
+
buildAccessTable,
|
|
512
|
+
valueToKVal,
|
|
513
|
+
kvalToValue
|
|
514
|
+
} from "@fraczak/k/backend-api.mjs";
|
|
515
|
+
|
|
516
|
+
const table = buildAccessTable(schemaS, patternP);
|
|
517
|
+
const kval = valueToKVal(inputVal, table.rootState);
|
|
518
|
+
const resKval = executePKIR(pkir, kval, table);
|
|
519
|
+
const result = kvalToValue(resKval);
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
- **Monomorphic Specialization (`specializePKIR`):**
|
|
523
|
+
```javascript
|
|
524
|
+
import {
|
|
525
|
+
specializePKIR,
|
|
526
|
+
executePKIR
|
|
527
|
+
} from "@fraczak/k/backend-api.mjs";
|
|
528
|
+
|
|
529
|
+
// Inlines static byte offsets and prunes dead union branches:
|
|
530
|
+
const specialized = specializePKIR(pkir, table);
|
|
531
|
+
|
|
532
|
+
// Executes with zero table overhead:
|
|
533
|
+
const result = executePKIR(specialized, kval, null);
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
- **Lowering to WebAssembly (`compileWasmArtifactFromPKIR`):**
|
|
537
|
+
```javascript
|
|
538
|
+
import {
|
|
539
|
+
compileWasmArtifactFromPKIR
|
|
540
|
+
} from "@fraczak/k/backend-api.mjs";
|
|
541
|
+
|
|
542
|
+
const wasmBytes = await compileWasmArtifactFromPKIR(pkir);
|
|
543
|
+
```
|
|
544
|
+
CLI commands:
|
|
545
|
+
```bash
|
|
546
|
+
# Compile .pkir directly to WebAssembly binary:
|
|
547
|
+
node backends/wasm/bin/k-wasm-compile.mjs input.pkir -o prog.wasm
|
|
548
|
+
|
|
549
|
+
# Lower .k source via PKIR to WebAssembly:
|
|
550
|
+
node backends/wasm/bin/k-wasm-compile.mjs --pkir prog.k -o prog.wasm
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
- **Lowering to LLVM IR & Native Binaries:**
|
|
554
|
+
```javascript
|
|
555
|
+
import {
|
|
556
|
+
compileLLVMArtifactFromPKIR
|
|
557
|
+
} from "@fraczak/k/backend-api.mjs";
|
|
558
|
+
import {
|
|
559
|
+
compilePKIRToExecutable,
|
|
560
|
+
compilePKIRAndRun
|
|
561
|
+
} from "@fraczak/k/backends/llvm/src/executable.mjs";
|
|
562
|
+
|
|
563
|
+
// Compile PKIR directly to LLVM IR string:
|
|
564
|
+
const llvmIR = compileLLVMArtifactFromPKIR(pkir);
|
|
565
|
+
|
|
566
|
+
// Compile PKIR directly to a native executable:
|
|
567
|
+
compilePKIRToExecutable(pkir, "./prog.exe");
|
|
568
|
+
|
|
569
|
+
// Compile and execute in one step:
|
|
570
|
+
const res = compilePKIRAndRun(pkir, { input: inputVal });
|
|
571
|
+
```
|
|
572
|
+
CLI commands:
|
|
573
|
+
```bash
|
|
574
|
+
# Compile .pkir directly to LLVM IR:
|
|
575
|
+
node backends/llvm/bin/k-llvm-compile.mjs input.pkir -o prog.ll
|
|
576
|
+
|
|
577
|
+
# Lower .k source via PKIR to LLVM IR:
|
|
578
|
+
node backends/llvm/bin/k-llvm-compile.mjs --pkir prog.k -o prog.ll
|
|
579
|
+
|
|
580
|
+
# Compile .pkir directly to native executable:
|
|
581
|
+
node backends/llvm/bin/k-llvm-build.mjs input.pkir -o prog.exe
|
|
582
|
+
|
|
583
|
+
# Lower .k source via PKIR to native executable:
|
|
584
|
+
node backends/llvm/bin/k-llvm-build.mjs --pkir prog.k -o prog.exe
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
---
|
|
588
|
+
|
|
368
589
|
## Practical Rules & Common Gotchas
|
|
369
590
|
|
|
370
591
|
### 1. Library Aliases Require Explicit `--export`
|
|
@@ -398,9 +619,11 @@ In `k`, there are no primitive numerical types or built-in integer
|
|
|
398
619
|
literals. Identifiers such as `5` or `10` are not language keywords;
|
|
399
620
|
they are defined relations (aliases) in `Examples/arithmetics.k`:
|
|
400
621
|
- `5` and `10` are nullary relations (constants) of type `{} -> bits`,
|
|
401
|
-
defined as binary digit trees over
|
|
622
|
+
defined as binary digit trees over:
|
|
623
|
+
`bits? = ?< {} _, bits? 0, bits? 1 > = bits?;`.
|
|
402
624
|
- Arithmetic operations (`plus`, `minus`, `times`, `inc`) operate on
|
|
403
|
-
signed integers
|
|
625
|
+
signed integers:
|
|
626
|
+
`int? = ?< <bits 0, bits 1, {} _>=bits "+", bits "-" >`.
|
|
404
627
|
- Passing a bit-representation like `5` to an integer relation requires
|
|
405
628
|
applying the `int` constructor (`5 int`), producing a constant
|
|
406
629
|
relation of type `{} -> int`.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Polymorphic K Intermediate Representation (PKIR)
|
|
2
|
+
|
|
3
|
+
## 1. Overview
|
|
4
|
+
|
|
5
|
+
PKIR (Polymorphic K Intermediate Representation) is the target execution
|
|
6
|
+
contract for polymorphic `k` relations.
|
|
7
|
+
|
|
8
|
+
Unlike the high-level relational AST or traditional bytecode that
|
|
9
|
+
relies on runtime string lookups for field names and variant tags, PKIR
|
|
10
|
+
is a **state-indexed, slot-addressed intermediate representation**.
|
|
11
|
+
|
|
12
|
+
PKIR operates in two cooperating execution modes:
|
|
13
|
+
1. **Generic Polymorphic Mode**: Instructions execute against a
|
|
14
|
+
precomputed `AccessTable` (Layout Witness), accessing fields and
|
|
15
|
+
variants via static slot numbers and array lookups with zero string
|
|
16
|
+
comparisons.
|
|
17
|
+
2. **Specialized Monomorphic Mode**: Given an `AccessTable`, a fast linear
|
|
18
|
+
pass (`specializePKIR`) inlines offsets directly into immediate machine
|
|
19
|
+
instructions, pruning unreachable union branches for peak LLVM/Wasm
|
|
20
|
+
performance.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 2. Core Concepts
|
|
25
|
+
|
|
26
|
+
### 2.1 The Structural Access Profile
|
|
27
|
+
|
|
28
|
+
Every PKIR relation is accompanied by an **Access Profile** derived from
|
|
29
|
+
its pattern graph:
|
|
30
|
+
- For every product pattern node $u$: a list of accessed field labels
|
|
31
|
+
defining dense, zero-based **logical slots**:
|
|
32
|
+
$$\text{fields}(u) = [ f_0, f_1, \dots, f_{k-1} ]$$
|
|
33
|
+
where slot $i$ corresponds to field $f_i$.
|
|
34
|
+
- For every union pattern node $u$: a list of matched variant tags
|
|
35
|
+
defining dense **branch targets**:
|
|
36
|
+
$$\text{variants}(u) = [ v_0, v_1, \dots, v_{m-1} ]$$
|
|
37
|
+
where branch $j$ corresponds to variant $v_j$.
|
|
38
|
+
|
|
39
|
+
### 2.2 Dual-Form Values (`KVal`)
|
|
40
|
+
|
|
41
|
+
Values in PKIR conform to the hybrid representation:
|
|
42
|
+
- **Serialized (Wire Slice)**: A pointer into an immutable prefix-free
|
|
43
|
+
bitstream, carrying a bit offset and schema state.
|
|
44
|
+
- **Materialized (Arena Node)**: An allocated record in memory containing
|
|
45
|
+
word-aligned pointers to child values.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 3. Instruction Set
|
|
50
|
+
|
|
51
|
+
PKIR instructions operate over a register file (`%v0`, `%v1`, ...):
|
|
52
|
+
|
|
53
|
+
### 3.1 Field & Variant Operations
|
|
54
|
+
|
|
55
|
+
- **`project_slot dest, src, state, slot`**:
|
|
56
|
+
Projects field at logical `slot` of pattern `state` from `src`.
|
|
57
|
+
At runtime with `AccessTable`:
|
|
58
|
+
```c
|
|
59
|
+
dest.ptr = src.ptr + table[src.state].slotToByteOffset[slot];
|
|
60
|
+
dest.state = table[src.state].slotToChildState[slot];
|
|
61
|
+
```
|
|
62
|
+
- **`match_tag src, state, branches`**:
|
|
63
|
+
Evaluates variant discriminator of `src` against pattern `state`.
|
|
64
|
+
At runtime with `AccessTable`:
|
|
65
|
+
```c
|
|
66
|
+
branch_idx = table[src.state].branchMap[src.tag];
|
|
67
|
+
dest.state = table[src.state].childStateMap[src.tag];
|
|
68
|
+
jump branches[branch_idx];
|
|
69
|
+
```
|
|
70
|
+
- **`make_variant dest, src, tag_id`**:
|
|
71
|
+
Wraps `src` into a tagged union with discriminator `tag_id`.
|
|
72
|
+
- **`make_product dest, [src0, src1, ...]`**:
|
|
73
|
+
Allocates a product node whose fields are registers `[src0, src1, ...]`.
|
|
74
|
+
|
|
75
|
+
### 3.2 Memory & Control Operations
|
|
76
|
+
|
|
77
|
+
- **`promote_spine dest, src`**:
|
|
78
|
+
If `src` is in serialized wire form, materializes only its immediate
|
|
79
|
+
outer record in the arena; children remain serialized wire slices.
|
|
80
|
+
If `src` is already materialized, acts as identity.
|
|
81
|
+
- **`dup dest1, dest2, src`**:
|
|
82
|
+
Zero-copy duplication of a value handle.
|
|
83
|
+
- **`call_rel dest, rel_name, src`**:
|
|
84
|
+
Invokes relation `rel_name` with input `src`.
|
|
85
|
+
- **`id dest, src`**:
|
|
86
|
+
Identity move.
|
|
87
|
+
- **`fail`**:
|
|
88
|
+
Signals partial function failure (backtracking or branch exit).
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 4. Execution Pipeline
|
|
93
|
+
|
|
94
|
+
```text
|
|
95
|
+
[AOT Phase]
|
|
96
|
+
k source -> AST -> Type Pattern Graph -> PKIR Relation
|
|
97
|
+
|
|
98
|
+
[Runtime Invocation with (Schema S, Payload V)]
|
|
99
|
+
1. AccessTable = buildAccessTable(S, PKIR.patternGraph)
|
|
100
|
+
2. Choose execution tier:
|
|
101
|
+
- Tier 0 (Interpreter): executePKIR(PKIR, V, AccessTable)
|
|
102
|
+
- Tier 1 (Specialized AOT/JIT): specializePKIR(PKIR, AccessTable)
|
|
103
|
+
-> direct emission to LLVM / WebAssembly
|
|
104
|
+
```
|
package/DOCS/REPL.md
CHANGED
|
@@ -33,10 +33,11 @@ is complete.
|
|
|
33
33
|
| Command | Meaning |
|
|
34
34
|
| --- | --- |
|
|
35
35
|
| `:help` | Show command summary |
|
|
36
|
-
| `:engine [wasm
|
|
37
|
-
| `:wasm` / `:js` | Shortcut to switch engine |
|
|
36
|
+
| `:engine [wasm\|pkir\|js]` | Display or switch evaluation engine (`wasm`, `pkir`, or `js`) |
|
|
37
|
+
| `:wasm` / `:pkir` / `:js` | Shortcut to switch engine |
|
|
38
38
|
| `:rel name` | Show relation definition |
|
|
39
39
|
| `:rels` | List relation aliases |
|
|
40
|
+
| `:limit [num\|none]` | Set maximum characters for value output (default: 4096) |
|
|
40
41
|
| `:codec load file` | Load a codec from an ES module file (e.g. `:codec load codecs/int.mjs`) |
|
|
41
42
|
| `:codec unload name` | Unload a registered codec |
|
|
42
43
|
| `:codec list` | List loaded REPL codecs (alias: `:codecs`) |
|
|
@@ -231,11 +232,13 @@ The REPL supports two evaluation engines:
|
|
|
231
232
|
|
|
232
233
|
### CLI Options
|
|
233
234
|
|
|
234
|
-
When starting `k-repl`, choose the engine with:
|
|
235
|
+
When starting `k-repl`, choose the engine or output limit with:
|
|
235
236
|
|
|
236
237
|
```bash
|
|
237
238
|
k-repl --engine=js # or k-repl --js
|
|
239
|
+
k-repl --engine=pkir # or k-repl --pkir
|
|
238
240
|
k-repl --engine=wasm # or k-repl --wasm (default)
|
|
241
|
+
k-repl --limit=8192 # set max characters for rendered output
|
|
239
242
|
```
|
|
240
243
|
|
|
241
244
|
## Timing and Profiling
|
|
@@ -297,6 +300,11 @@ Evaluated values print in k syntax together with the inferred envelope:
|
|
|
297
300
|
{}|0|+1 ?<<{} 0, ...> +1, ...>
|
|
298
301
|
```
|
|
299
302
|
|
|
303
|
+
Large values are rendered iteratively and truncated at `maxChars`
|
|
304
|
+
(default: `4096` characters) so deeply nested or large values print
|
|
305
|
+
instantly without exhausting stack or terminal buffers. Use
|
|
306
|
+
`:limit <num>` or `:limit none` to adjust or disable the limit.
|
|
307
|
+
|
|
300
308
|
`undefined` prints as:
|
|
301
309
|
|
|
302
310
|
```text
|
|
@@ -113,7 +113,7 @@ The bundled VFS and UI examples must include only verified useful files:
|
|
|
113
113
|
#### 1. Curated Files Explorer
|
|
114
114
|
In the Web REPL "Files" (VFS) explorer, the visible files are strictly curated to verified examples and codecs:
|
|
115
115
|
- **k-codes**: `core.k`, `arithmetics.k`, `ieee.k`
|
|
116
|
-
- **codecs**: `json.mjs`, `utf8.mjs`, `int.mjs`, `unit.mjs`, `ieee.mjs`
|
|
116
|
+
- **codecs**: `json.mjs`, `djson.mjs`, `utf8.mjs`, `int.mjs`, `unit.mjs`, `ieee.mjs`
|
|
117
117
|
- User-created or uploaded files remain visible.
|
|
118
118
|
- Internal runtime artifacts (`backends/wasm/runtime.wat`) and redundant directory prefixes (`Examples/`, `codecs/`) are kept accessible internally but hidden from the default file listing.
|
|
119
119
|
- Clicking "Load" on a `.mjs` file automatically executes `:codec load <filename>`.
|