@fraczak/k 6.3.3 → 6.5.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.
Files changed (157) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/DOCS/CODECS.md +258 -0
  3. package/DOCS/DICTIONARY.md +1172 -0
  4. package/DOCS/KIR_SPECIALIZATION_DESIGN.md +51 -46
  5. package/DOCS/KIR_V1.md +221 -0
  6. package/DOCS/KVM_EXECUTION_MODEL.md +56 -19
  7. package/DOCS/OBJECT_FILE_AND_PATTERN.md +2 -1
  8. package/DOCS/PROFILING_AND_TRACING.md +196 -0
  9. package/DOCS/REPL.md +61 -4
  10. package/DOCS/WEB_REPL_REQUIREMENTS.md +135 -0
  11. package/DOCS/dependency-graph.md +144 -0
  12. package/Examples/arithmetics.k +108 -82
  13. package/Examples/bnat.k +1 -1
  14. package/Examples/buda.k +44 -0
  15. package/Examples/ieee.k +300 -8671
  16. package/Examples/poly.k +67 -0
  17. package/README.md +68 -19
  18. package/Value.mjs +8 -2
  19. package/augmentation.mjs +9 -7
  20. package/backend-api.mjs +11 -2
  21. package/backends/arm64/README.md +104 -0
  22. package/backends/arm64/bin/k-arm64-compile.mjs +101 -0
  23. package/backends/arm64/bin/k-arm64-run.mjs +58 -0
  24. package/backends/arm64/bin/k-arm64.mjs +88 -0
  25. package/backends/arm64/scripts/run-tests.mjs +41 -0
  26. package/backends/arm64/src/arm64.mjs +229 -0
  27. package/backends/arm64/src/cli.mjs +155 -0
  28. package/backends/arm64/src/kvm2arm64.mjs +906 -0
  29. package/backends/arm64/src/runtime.c +728 -0
  30. package/backends/arm64/tests/integration.sh +112 -0
  31. package/backends/arm64/tests/test-arm64.mjs +240 -0
  32. package/backends/llvm/README.md +135 -0
  33. package/backends/llvm/bin/k-llvm-build.mjs +71 -0
  34. package/backends/llvm/bin/k-llvm-compile.mjs +68 -0
  35. package/backends/llvm/bin/k-llvm-jit.mjs +160 -0
  36. package/backends/llvm/bin/k-llvm-run.mjs +90 -0
  37. package/backends/llvm/runtime/krt.c +1508 -0
  38. package/backends/llvm/runtime/krt.h +109 -0
  39. package/backends/llvm/scripts/conformance.mjs +76 -0
  40. package/backends/llvm/scripts/run-tests.mjs +28 -0
  41. package/backends/llvm/src/executable.mjs +562 -0
  42. package/backends/llvm/src/kvm2llvm.mjs +998 -0
  43. package/backends/llvm/src/llvm.mjs +1092 -0
  44. package/backends/llvm/tests/composition-driver.c +22 -0
  45. package/backends/llvm/tests/identity-driver.c +27 -0
  46. package/backends/llvm/tests/integration.sh +153 -0
  47. package/backends/llvm/tests/perf-support.mjs +735 -0
  48. package/backends/llvm/tests/product-driver.c +23 -0
  49. package/backends/llvm/tests/projection-driver.c +19 -0
  50. package/backends/llvm/tests/relation-driver.c +29 -0
  51. package/backends/llvm/tests/test-llvm.mjs +240 -0
  52. package/backends/llvm/tests/union-driver.c +31 -0
  53. package/backends/llvm/tests/variant-driver.c +19 -0
  54. package/backends/llvm/tests/variant-projection-driver.c +21 -0
  55. package/backends/wasm/DOCS/USE-WEB-ASSEMBLY.md +233 -0
  56. package/backends/wasm/README.md +97 -0
  57. package/backends/wasm/TECHNICAL-DEBT.md +58 -0
  58. package/backends/wasm/bin/k-wasm-compile.mjs +50 -0
  59. package/backends/wasm/bin/k-wasm-run.mjs +140 -0
  60. package/backends/wasm/bin/k-wasm.mjs +49 -0
  61. package/backends/wasm/demo_ieee.mjs +319 -0
  62. package/backends/wasm/runtime.wat +475 -0
  63. package/backends/wasm/scripts/run-tests.mjs +41 -0
  64. package/backends/wasm/src/cli.mjs +133 -0
  65. package/backends/wasm/src/kvm2wasm.mjs +697 -0
  66. package/backends/wasm/src/wasm.mjs +1054 -0
  67. package/backends/wasm/tests/integration.sh +182 -0
  68. package/backends/wasm/tests/perf-support.mjs +336 -0
  69. package/backends/wasm/tests/test-wasm.mjs +625 -0
  70. package/browser/repl-browser.mjs +1584 -0
  71. package/browser/shims/assert.mjs +19 -0
  72. package/browser/shims/buffer.mjs +224 -0
  73. package/browser/shims/crypto.mjs +103 -0
  74. package/browser/shims/fs.mjs +159 -0
  75. package/browser/shims/os.mjs +17 -0
  76. package/browser/shims/path.mjs +54 -0
  77. package/browser/shims/process.mjs +44 -0
  78. package/browser/shims/readline.mjs +11 -0
  79. package/browser/shims/url.mjs +12 -0
  80. package/browser/vfs-data.mjs +19 -0
  81. package/codecs/README.md +3 -0
  82. package/codecs/runtime/show-value.mjs +12 -3
  83. package/conformance/helper-reuse/case.json +8 -0
  84. package/conformance/helper-reuse/expected.kv +1 -0
  85. package/conformance/helper-reuse/input.kv +1 -0
  86. package/conformance/helper-reuse/program.k +2 -0
  87. package/conformance/identity/case.json +8 -0
  88. package/conformance/identity/expected.kv +1 -0
  89. package/conformance/identity/input.kv +1 -0
  90. package/conformance/identity/program.k +1 -0
  91. package/conformance/product-projection/case.json +8 -0
  92. package/conformance/product-projection/expected.kv +1 -0
  93. package/conformance/product-projection/input.kv +1 -0
  94. package/conformance/product-projection/program.k +1 -0
  95. package/conformance/run.mjs +149 -0
  96. package/conformance/variant-construction/case.json +8 -0
  97. package/conformance/variant-construction/expected.kv +1 -0
  98. package/conformance/variant-construction/input.kv +1 -0
  99. package/conformance/variant-construction/program.k +1 -0
  100. package/harness/adapters/arm64.mjs +105 -0
  101. package/harness/adapters/kvm.mjs +144 -0
  102. package/harness/adapters/llvm.mjs +118 -0
  103. package/harness/adapters/native.mjs +77 -0
  104. package/harness/adapters/wasm.mjs +169 -0
  105. package/harness/backend.mjs +95 -0
  106. package/harness/cli.mjs +130 -0
  107. package/harness/format.mjs +95 -0
  108. package/harness/index.mjs +25 -0
  109. package/harness/persistent.mjs +121 -0
  110. package/harness/registry.mjs +44 -0
  111. package/harness/suite.mjs +257 -0
  112. package/harness/suites/poly.mjs +156 -0
  113. package/harness/trace.mjs +50 -0
  114. package/harness/util.mjs +92 -0
  115. package/intrinsics.mjs +41 -0
  116. package/kir.mjs +399 -0
  117. package/kvm.mjs +585 -81
  118. package/objects/README.md +37 -3
  119. package/objects/compile.mjs +15 -22
  120. package/objects/inspect.mjs +96 -0
  121. package/objects/validate.mjs +415 -0
  122. package/package.json +51 -19
  123. package/repl-codecs.mjs +105 -6
  124. package/repl.mjs +335 -49
  125. package/run.mjs +2 -7
  126. package/scripts/benchmark.mjs +406 -22
  127. package/scripts/build-repl-html.mjs +1784 -0
  128. package/scripts/perf-ieee.mjs +586 -0
  129. package/scripts/perf-int.mjs +531 -0
  130. package/scripts/perf-poly.mjs +945 -0
  131. package/scripts/render-benchmark.mjs +12 -8
  132. package/scripts/run-tests.mjs +6 -0
  133. package/tests/integration.sh +19 -2
  134. package/tests/test-arithmetics.mjs +54 -0
  135. package/tests/test-ieee-arithmetic.mjs +4 -0
  136. package/tests/test-kir.mjs +85 -0
  137. package/tests/test-kvm-polymorphic.mjs +278 -0
  138. package/tests/test-kvm.mjs +25 -6
  139. package/tests/test-poly.mjs +129 -0
  140. package/tests/test-repl-html.mjs +303 -0
  141. package/tests/test-repl.mjs +144 -1
  142. package/tests/test-validate-object.mjs +40 -0
  143. package/a.klib +0 -1
  144. package/a.kvm +0 -142676
  145. package/a.wasm +0 -0
  146. package/benchmark-results.html +0 -532
  147. package/benchmark-results.json +0 -480
  148. package/k-vscode/.vscode/launch.json +0 -14
  149. package/k-vscode/README.md +0 -75
  150. package/k-vscode/extension.js +0 -273
  151. package/k-vscode/language-configuration.json +0 -42
  152. package/k-vscode/package.json +0 -79
  153. package/k-vscode/snippets/k.json +0 -92
  154. package/k-vscode/syntaxes/k.tmLanguage.json +0 -599
  155. package/k-vscode/test/background-ranges.test.js +0 -50
  156. package/k-vscode/themes/k-contrast-color-theme.json +0 -104
  157. package/scripts/git-hooks/pre-commit +0 -10
@@ -0,0 +1,196 @@
1
+ # Profiling and Execution Tracing in k
2
+
3
+ This document describes the performance benchmarking, macro-phase execution tracing,
4
+ and function-level call profiling infrastructure for `k` backends.
5
+
6
+ The profiling framework allows fine-grained performance analysis of polymorphic `k`
7
+ programs across multiple execution targets:
8
+ - **Linux ARM64** (native standalone ELF executable via direct kVM assembly emission)
9
+ - **WebAssembly** (in-process Wasm module via single-pass kVM lowering)
10
+ - **LLVM** (native specialized executable via KIR-P lowering)
11
+ - **kVM Interpreter** (in-process TypeScript/JavaScript kVM evaluator)
12
+ - **Native JS Baselines** (envelope-aware and envelope-free reference runs)
13
+
14
+ ---
15
+
16
+ ## 1. Motivation: Apples-to-Apples Backend Comparison
17
+
18
+ When measuring end-to-end request latency across backends, wall-clock time can be
19
+ dominated by factors outside the core relation algorithm:
20
+ - **Process IPC**: Out-of-process native executables (ARM64, LLVM) communicate via stdin/stdout pipes, incurring OS context switches and pipe buffer copies.
21
+ - **Wire Codec**: Decoding and validating the binary wire format (`pattern + value`) and encoding the response.
22
+ - **In-Memory Representation**: WebAssembly converts incoming values into a flat linear memory arena layout.
23
+ - **Pure Evaluation**: The actual relational instruction loop performing the algorithm.
24
+
25
+ Without detailed accounting, native ARM64 or LLVM binaries communicating over pipes can
26
+ appear slower than in-process WebAssembly or the interpreter simply because of IPC overhead.
27
+ The tracing infrastructure breaks request latency down into nanosecond-level phases so that
28
+ pure execution time can be measured and compared directly.
29
+
30
+ In addition, **per-function invocation profiling** verifies that every backend performs the
31
+ exact same number of relational evaluations and loop iterations for a given input.
32
+
33
+ ---
34
+
35
+ ## 2. Test Workload: Polymorphic List Operations (`Examples/poly.k`)
36
+
37
+ The primary benchmark for polymorphic kVM execution is [`Examples/poly.k`](../Examples/poly.k),
38
+ which defines canonical polymorphic operations over recursive lists:
39
+ - `reverse`: Linear reverse using an accumulator.
40
+ - `concat`: Polymorphic list concatenation.
41
+ - `split_by`: Splits a list at index $N$ into `{ first, second }`.
42
+ - `get_nth`: Retrieves the $N$-th element (0-indexed).
43
+ - `length`: Computes list length using arbitrary-precision Peano/bit integers.
44
+
45
+ ### Modular Compilation and Name Isolation
46
+
47
+ `Examples/poly.k` depends on integer and list operations defined in [`Examples/arithmetics.k`](../Examples/arithmetics.k).
48
+ Following `k`'s canonical content-addressed design:
49
+ - `arithmetics.k` is compiled as a separate library (`--lib`).
50
+ - Only required symbols (`0`, `int`, `inc`, `dec`, `nat`, `zero_int?`, `nil`, `cons`, `car`, `cdr`) are exported into `poly.k`'s scope.
51
+ - Bitstring `concat` in `arithmetics.k` remains strictly private and does not conflict with polymorphic list `concat` in `poly.k`. Each function receives its own unique canonical content hash.
52
+
53
+ ---
54
+
55
+ ## 3. Macro-Phase Execution Tracing (Level 1)
56
+
57
+ When tracing is enabled, each request is instrumented to measure 7 discrete phases with nanosecond precision:
58
+
59
+ | Phase | Description | Linux ARM64 | LLVM | WebAssembly | kVM Interp |
60
+ | :--- | :--- | :---: | :---: | :---: | :---: |
61
+ | **1. IPC Read (Pipe In)** | Waiting for and reading input payload from stdin | Yes | Yes | N/A (in-process) | N/A (in-process) |
62
+ | **2. Wire Decode & Validate** | Decoding wire buffer and validating against pattern | Yes | Yes | N/A (in-process) | N/A (in-process) |
63
+ | **3. Flat Input Prep (Arena)** | Flattening decoded structures into linear arena memory | Yes | N/A | Yes | N/A |
64
+ | **4. Pure Evaluation** | Core relational execution loop | **Yes** | **Yes** | **Yes** | **Yes** |
65
+ | **5. Flat Output Prep (Arena)** | Serializing/reading in-memory representations | Yes | N/A | Yes | N/A |
66
+ | **6. Wire Encode** | Encoding result to canonical wire format | Yes | Yes | N/A (in-process) | N/A (in-process) |
67
+ | **7. IPC Write (Pipe Out)** | Writing output wire bytes to stdout pipe | Yes | Yes | Yes (driver) | N/A |
68
+
69
+ ### Phase Timing Output Example
70
+
71
+ ```text
72
+ --- Operation: reverse (len 40) ---
73
+ Phase | Linux ARM64 | LLVM | WebAssembly | kVM Interp
74
+ -------------------------+---------------+---------------+---------------+---------------
75
+ 1. IPC Read (Pipe In) | 169.83 µs | 161.42 µs | - | -
76
+ 2. Wire Decode & Validate | 2.04 µs | 1.58 µs | - | -
77
+ 3. Flat Input Prep (Arena) | 3.08 µs | - | 80.88 µs | -
78
+ 4. Pure Evaluation | 0.46 µs | 0.54 µs | 1.71 µs | 26.04 µs
79
+ 5. Flat Output Prep (Arena) | 2.67 µs | - | 76.71 µs | -
80
+ 6. Wire Encode | 1.96 µs | 4.88 µs | - | -
81
+ 7. IPC Write (Pipe Out) | 11.29 µs | 11.08 µs | 0.62 µs | -
82
+ -------------------------+---------------+---------------+---------------+---------------
83
+ Total Request Time | 191.33 µs | 179.50 µs | 159.92 µs | 26.04 µs
84
+ ```
85
+
86
+ **Key Takeaways**:
87
+ - **Pure evaluation** in Linux ARM64 native code (`0.46 µs`) is ~3.7× faster than WebAssembly (`1.71 µs`) and ~56× faster than the interpreter (`26.04 µs`).
88
+ - **End-to-end request time** for native binaries is dominated by pipe IPC read (`~160–170 µs`).
89
+ - **WebAssembly overhead** is concentrated in flat arena conversion (`~80 µs` in, `~76 µs` out).
90
+
91
+ ---
92
+
93
+ ## 4. Per-Function Invocation Profiling (Level 2)
94
+
95
+ Per-function profiling increments dedicated counters at the entry point of every relation
96
+ body and tail-call loop. This proves semantic equivalence across targets by verifying that
97
+ every backend executes the exact same call path.
98
+
99
+ ### Function Profile Output Example
100
+
101
+ ```text
102
+ Function Call Profile: reverse
103
+ Function Name | Linux ARM64 Calls | WebAssembly Calls | kVM Interp Calls
104
+ -------------------------+-------------------+-------------------+------------------
105
+ reverse | - | 1 | 1
106
+ _reverse | - | 41 | 41
107
+ @dhiaXnh7AYZnewyvbXdh... | 1 | - | -
108
+ @EwQ2P3yZ8v4z2qA7kF... | 41 | - | -
109
+ car | 40 | 40 | 40
110
+ cdr | 40 | 40 | 40
111
+ cons | 40 | 40 | 40
112
+ nil | 1 | 1 | 1
113
+ -------------------------+-------------------+-------------------+------------------
114
+ Total Calls | 163 | 163 | 163
115
+ ```
116
+
117
+ *(Note: ARM64 displays canonical content hashes `@hash` for unaliased internal relations.
118
+ All three backends arrive at the exact same total call count: 163 calls for reversing a list of length 40).*
119
+
120
+ ---
121
+
122
+ ## 5. Usage & Commands
123
+
124
+ ### Running Benchmarks
125
+
126
+ ```bash
127
+ # Standard end-to-end benchmark across all 6 lanes
128
+ npm run perf:poly
129
+
130
+ # Benchmark with macro-phase breakdown tracing and function profiling
131
+ npm run perf:poly:trace
132
+
133
+ # Or run the script directly:
134
+ node scripts/perf-poly.mjs --trace
135
+ ```
136
+
137
+ ### Environment Variables
138
+
139
+ | Variable | Default | Description |
140
+ | :--- | :---: | :--- |
141
+ | `LIST_LENGTH` | `40` | Number of elements in test lists. |
142
+ | `ITERATIONS` | `3` | Number of iterations for the benchmark summary table. |
143
+ | `TRACE_SAMPLES` | `5` | Repetitions sampled and averaged for phase timings. |
144
+ | `TRACE` | `0` | Set to `1` (or pass `--trace`) to enable phase breakdown. |
145
+ | `PROFILE` | `1` (with trace) | Set to `0` to disable function call counters. |
146
+ | `ARM64_OPT` | `-O2` | Optimization level for the native ARM64 runtime (`-O0`, `-O1`, `-O2`, `-O3`). |
147
+ | `WASM_RESET` | `1` | Reset the WebAssembly linear memory arena between calls (`1` or `0`). |
148
+ | `ARM64_ONLY` | `0` | Run only the Linux ARM64 native target. |
149
+ | `WASM_ONLY` | `0` | Run only the WebAssembly target. |
150
+ | `LLVM_ONLY` | `0` | Run only the LLVM target. |
151
+ | `BACKENDS_ONLY` | `0` | Skip the native JS baseline lanes. |
152
+
153
+ ### Practical Examples
154
+
155
+ ```bash
156
+ # Fast smoke check with list length 10 and 1 iteration:
157
+ ITERATIONS=1 LIST_LENGTH=10 npm run perf:poly:trace
158
+
159
+ # Measure high-optimization ARM64 (-O3) vs WebAssembly on large lists (100 elements):
160
+ LIST_LENGTH=100 ARM64_OPT=-O3 npm run perf:poly:trace
161
+
162
+ # Isolate ARM64 native execution:
163
+ ARM64_ONLY=1 npm run perf:poly:trace
164
+ ```
165
+
166
+ ---
167
+
168
+ ## 6. Implementation Architecture
169
+
170
+ ### Linux ARM64 Backend
171
+ - **Code Emission** ([`backends/arm64/src/kvm2arm64.mjs`](../backends/arm64/src/kvm2arm64.mjs)): When `options.profile` is active, each function emits counter increment instructions in its entry sequence:
172
+ ```asm
173
+ adrp x9, k_prof_<func>
174
+ add x9, x9, :lo12:k_prof_<func>
175
+ ldr x10, [x9]
176
+ add x10, x10, #1
177
+ str x10, [x9]
178
+ ```
179
+ Counters are emitted into a dedicated `.data` section, and an exported metadata table `k_profile_entries[]` is generated.
180
+ - **Runtime Reporting** ([`backends/arm64/src/runtime.c`](../backends/arm64/src/runtime.c)):
181
+ - Nanosecond phase timestamps are sampled via `clock_gettime(CLOCK_MONOTONIC, ...)` and emitted over stderr formatted as:
182
+ ```text
183
+ K_TRACE_PHASES backend=arm64 ipc_read_ns=... decode_ns=... flat_in_ns=... eval_ns=... flat_out_ns=... encode_ns=... ipc_write_ns=... total_ns=...
184
+ ```
185
+ - `dump_profile_counts()` emits nonzero function call counts between `K_PROFILE_BEGIN` and `K_PROFILE_END` tags.
186
+
187
+ ### WebAssembly Backend
188
+ - **Code Emission** ([`backends/wasm/src/kvm2wasm.mjs`](../backends/wasm/src/kvm2wasm.mjs)): Emits mutable 64-bit Wasm globals:
189
+ ```wat
190
+ (global $prof_<name> (export "prof_<name>") (mut i64) (i64.const 0))
191
+ ```
192
+ Inside the function/tail-loop body, `(global.set $prof_<name> (i64.add (global.get $prof_<name>) (i64.const 1)))` increments the counter.
193
+ - **Harness Integration** ([`backends/wasm/tests/perf-support.mjs`](../backends/wasm/tests/perf-support.mjs)): `readWasmProfile` and `resetWasmProfile` read and zero the exported globals directly from the Wasm instance exports.
194
+
195
+ ### kVM Interpreter
196
+ - **Evaluation Loop** ([`kvm.mjs`](../kvm.mjs)): When `context.profile` is provided, `executeKVM` resolves the active function name or hash via `context.hashToName` and increments `context.profile[name]`.
package/DOCS/REPL.md CHANGED
@@ -40,13 +40,17 @@ complete.
40
40
  | `:def name = expr` | Alias for `:rel` |
41
41
  | `:run expr` | Evaluate `expr` on the current value |
42
42
  | `:eval expr` | Alias for `:run` |
43
+ | `:time expr` | Evaluate `expr` and report compilation and execution time |
44
+ | `:timing [on\|off]` | Toggle compilation and execution timing reporting for all evaluations |
43
45
  | `:t name` | Show relation input/output filters |
44
46
  | `:d name` | Show relation definition |
45
47
  | `:C name` | Show canonical code definition |
46
48
  | `:codes` | List type aliases |
47
49
  | `:rels` | List relation aliases |
48
- | `:codec load file` | Load an importable REPL codec module |
49
- | `:codec list` | List loaded REPL codecs |
50
+ | `:codec load name\|file` | Load a built-in codec (`int`, `utf8`, `json`, `ieee`, `unit`) or an ES module file |
51
+ | `:codec define n t b` | Define an inline custom codec: `name type { parse: ..., print: ... }` |
52
+ | `:codec unload name` | Unload a registered codec |
53
+ | `:codec list` | List loaded REPL codecs (alias: `:codecs`) |
50
54
  | `:input type [codec]` | Read the next line as codec input for a type |
51
55
  | `:load [--no-alias] file` | Load `.k` source or `.klib` into the current state |
52
56
  | `:klib file` | Export the active relation closure as a `.klib` library |
@@ -163,9 +167,19 @@ for codec dispatch. A codec may also export `universal = true` to make it
163
167
  available for any type selected by `:input`; the parsed value is still validated
164
168
  against the requested type before it enters the session.
165
169
 
166
- ### `:codec load file`
170
+ For a complete guide to writing a new codec module, see
171
+ [`CODECS.md`](./CODECS.md).
167
172
 
168
- Loads an importable ES module that exports a codec shape:
173
+ ### `:codec load name|file`
174
+
175
+ Loads either a built-in codec by name (`int`, `utf8`, `json`, `ieee`, `unit`) or an ES module file. Loading a built-in codec automatically loads its corresponding `.k` definition file if not already present:
176
+ - `int` auto-loads `Examples/arithmetics.k`
177
+ - `ieee` auto-loads `Examples/ieee.k`
178
+ - `utf8`, `json`, `unit` auto-load `Examples/core.k`
179
+
180
+ Loading a codec also creates code aliases matching the codec name (e.g. `$ int = @...`, `$ float64 = @...`, `$ utf8 = @...`).
181
+
182
+ An external codec module exports:
169
183
 
170
184
  ```js
171
185
  export const name = "utf8";
@@ -179,6 +193,19 @@ property-list pattern that can be canonicalized to a code hash, and that hash is
179
193
  recalculated by the REPL. A universal codec exports `universal = true` instead
180
194
  of `codes` or `patterns`.
181
195
 
196
+ ### `:codec define name type { parse: ..., print: ... }`
197
+
198
+ Registers a dynamic custom codec directly from the REPL:
199
+
200
+ ```k
201
+ > :type bool = <{} true, {} false>
202
+ > :codec define yn bool ({ parse: (t) => Value.variant(t.trim() === 'yes' ? 'true' : 'false', Value.product({})), print: (v) => v.tag === 'true' ? 'YES' : 'NO' })
203
+ ```
204
+
205
+ ### `:codec unload name`
206
+
207
+ Unloads a previously registered codec by name.
208
+
182
209
  ### `:input type [codec]`
183
210
 
184
211
  Resolves `type` to a canonical code hash, selects the registered codec, and
@@ -187,6 +214,36 @@ canonical code hash, or an inline type expression such as
187
214
  `<{} true, {} false>`. The parsed value is validated against that type before
188
215
  becoming the current value.
189
216
 
217
+ ## Timing and Profiling
218
+
219
+ ### `:time expr`
220
+
221
+ Evaluates `expr` and reports the elapsed time broken down into compilation
222
+ (type derivation + WebAssembly lowering/compilation) and runtime execution:
223
+
224
+ ```text
225
+ > :time {10 int x, 5 int y} plus
226
+ {}|_|1|1|1|1|+ ?<{} _, ...>
227
+ /* comp: 12.4ms, exec: 0.8ms */
228
+ ```
229
+
230
+ ### `:timing [on|off]`
231
+
232
+ Toggles automatic timing reporting for every snippet or expression evaluated in
233
+ the session.
234
+
235
+ ## Web REPL (Studio)
236
+
237
+ The repository provides a standalone, single-file browser REPL: `repl.html`.
238
+
239
+ - **Zero-install in-browser execution**: Powered by WebAssembly (`wasm-in-process`) and virtual filesystem (VFS).
240
+ - **Interactive UI**: Tab autocompletion, persistent text selection, execution timing badges (`comp: Xms | exec: Yms`), interactive Codecs management modal, and interactive `:input` popup modal.
241
+ - **Build**: Generate `repl.html` locally using:
242
+ ```bash
243
+ npm run build:repl-html
244
+ ```
245
+ - **Live Demo**: Automatically deployed to GitHub Pages via `.github/workflows/pages.yml`.
246
+
190
247
  ## Export
191
248
 
192
249
  ### `:klib file`
@@ -0,0 +1,135 @@
1
+ # Web REPL Requirements & Architecture Specification
2
+
3
+ **Branch**: `web-repl`
4
+ **Status**: Approved Specification
5
+ **Target Area**: Web REPL UI (`browser/repl-browser.mjs`), Build Pipeline (`scripts/build-repl-html.mjs`), and REPL Engine (`repl.mjs`, `repl-codecs.mjs`)
6
+
7
+ ---
8
+
9
+ ## 1. Context & Objectives
10
+
11
+ The goal of this initiative is to improve the user experience, robustness, and out-of-the-box readiness of the K Web REPL.
12
+
13
+ The scope encompasses four primary objectives:
14
+ 1. **Console Text Selection**: Ensure all output in the terminal console is smoothly selectable and copyable across all desktop and mobile browsers without focus-stealing interference.
15
+ 2. **Prioritize `core.k`**: Make `core.k` the default first choice for loading, examples, dropdowns, and quick exploration.
16
+ 3. **Curate VFS Files**: Restrict the bundled Virtual File System (VFS) to verified, useful `.k` files (`core.k`, `Examples/arithmetics.k`, `Examples/ieee.k`, `Examples/poly.k`), auditing and verifying types used by REPL codecs.
17
+ 4. **Automatic Dependency Loading & Type Aliasing for Codecs**:
18
+ - Automatically load the required `.k` source file whenever a codec is loaded, ensuring that necessary type aliases, canonical codes, and operational relations are present before the user attempts `:input` or evaluations.
19
+ - Establish bidirectional type alias naming so codec names are direct aliases to the underlying type hashes (e.g. `$ieee` and `$float64` both point to `@AR4s...`, `$utf8` and `$string` both point to `@Pt3Mw...`, and `$int` points to `@Nws3v...`).
20
+
21
+ ---
22
+
23
+ ## 2. Detailed Requirements & Architectural Decisions
24
+
25
+ ### Objective 1: Selectable Console Output
26
+
27
+ #### Current Problem
28
+ - When users highlight and copy output text from `#terminal-output`:
29
+ 1. A global click event listener on `document` listens for clicks to focus `#repl-input`:
30
+ ```js
31
+ document.addEventListener("click", (e) => {
32
+ if (!e.target.closest("button, select, input, textarea, .modal, .quick-link, .btn-copy-entry")) {
33
+ inputEl.focus();
34
+ }
35
+ });
36
+ ```
37
+ 2. Clicking or releasing a drag selection within `#terminal-output` does not match the excluded selector list.
38
+ 3. Consequently, `inputEl.focus()` is called immediately upon `mouseup`/`click`.
39
+ 4. In modern browsers (Chromium, Firefox, Safari), focusing a text input field collapses the window's text selection, destroying the active selection.
40
+ 5. In addition, double-clicking or triple-clicking a word or line in the terminal is aborted.
41
+
42
+ #### Requirements
43
+ 1. **Selection Preservation**: Users must be able to click, drag-select, double-click, and triple-click any text inside the terminal output without losing selection.
44
+ 2. **Clipboard Compatibility**: Standard copy shortcuts (`Ctrl+C`, `Cmd+C`) must copy the selected text, not the input buffer.
45
+ 3. **Styling & Presentation**:
46
+ - Terminal entries (`.terminal-entry`, `.entry-command`, `.entry-line`, `.line-output`, `.line-error`, `.line-warning`, `.system-msg`) must have explicit `user-select: text; -webkit-user-select: text;`.
47
+ - Prompt decorations (`.entry-prompt`, `.entry-meta`, `.prompt-label`) retain `user-select: none;` to avoid cluttering copied text with prompt symbols (`> `).
48
+ 4. **Smart Focus Restoration**:
49
+ - If `window.getSelection() && !window.getSelection().isCollapsed && window.getSelection().toString().trim().length > 0`, the click handler must **never** steal focus to `#repl-input`.
50
+ - Clicking directly inside `#terminal-output` on text content should allow text cursor placement and selection without snapping focus away.
51
+ - Only clicking on empty dead space or background when no text is selected should optionally focus the input.
52
+
53
+ ---
54
+
55
+ ### Objective 2: Prioritize `core.k` as the First Choice
56
+
57
+ #### Requirements
58
+ 1. **Dropdown Ordering**: In `#example-select`, `core.k` must be the top-most option under standard examples.
59
+ 2. **Onboarding Banner**: The welcome message and quick-start hints in `browser/repl-browser.mjs` must showcase `:load core.k` as the primary recommended action.
60
+ 3. **Quick Expressions**: Ensure the quick expressions section provides expressions compatible with `core.k` out-of-the-box (e.g. `1 succ`, `10`, `$bits`, `$string`).
61
+
62
+ ---
63
+
64
+ ### Objective 3: Verified Useful Files in VFS & Codec Type Audit
65
+
66
+ #### Curated File Set
67
+ The bundled VFS and UI examples must include only verified useful files:
68
+ - `core.k` — The foundational standard library (bits, arithmetic on bits, Unicode `$unicode`, `$string`, `$pattern`).
69
+ - `Examples/arithmetics.k` — Arbitrary-precision signed integers (`$int`), rationals (`$rat`), GCD/LCM, factorial, Fibonacci.
70
+ - `Examples/ieee.k` — IEEE-754 double-precision floating point type (`$float64`) and arithmetic operations.
71
+ - `Examples/poly.k` — Polymorphic list functions (`concat`, `reverse`, `length`, `get_nth`, `split_by`, `take`, `drop`, `zip`).
72
+
73
+ #### Dependency Management for `poly.k`
74
+ - `Examples/poly.k` depends on `dec`, `nat`, and `zero_int?` from `Examples/arithmetics.k`.
75
+ - Loading `Examples/poly.k` on a fresh session will automatically ensure `Examples/arithmetics.k` is loaded first if not already loaded in the session.
76
+
77
+ ---
78
+
79
+ ### Objective 4: Auto-Loading `.k` Files on Codec Load & Code Aliasing
80
+
81
+ #### Requirements
82
+ 1. **Codec-to-File Auto-Loading**:
83
+ When a codec is registered or loaded (via `:codec load <name>`, REPL initialization, or UI action):
84
+ - Check if the required `.k` file is already loaded in `state.loadedFiles`.
85
+ - If not loaded, automatically load and evaluate the corresponding `.k` file before completing codec registration:
86
+ - `int` -> auto-loads `Examples/arithmetics.k`
87
+ - `utf8` -> auto-loads `core.k`
88
+ - `json` -> auto-loads `core.k`
89
+ - `ieee` -> auto-loads `Examples/ieee.k`
90
+ - Print an informative message, e.g.: `(auto-loaded Examples/arithmetics.k for codec 'int')`.
91
+
92
+ 2. **Bidirectional Code Aliasing**:
93
+ Establish code aliasing so that codec names and their standard type names are both valid aliases pointing to the same canonical type hash:
94
+ - **IEEE / Float64**:
95
+ - Canonical Hash: `@AR4sFGMwXgjj5p7dhi8sJKDWNbrXxLefQUCBRNm5fP6t`
96
+ - Aliases: `$float64` and `$ieee`
97
+ - **UTF-8 / String**:
98
+ - Canonical Hash: `@Pt3MwQwzUPxQKu58zXR3qUBHWTzfycx5bSZGzcK6EZQK`
99
+ - Aliases: `$string` and `$utf8`
100
+ - **Int**:
101
+ - Canonical Hash: `@Nws3vysWqC9PznraTP4kWPp44Rd77NAqrx9dgbtHAjGA`
102
+ - Alias: `$int`
103
+ This guarantees that both `:input utf8` and `:input string`, as well as `:input ieee` and `:input float64`, work seamlessly.
104
+
105
+ 3. **Idempotence**:
106
+ - `state.loadedFiles = new Set()` tracks loaded file paths (normalized).
107
+ - Re-running `:codec load` or loading multiple codecs referencing the same file (`utf8` and `json` both referencing `core.k`) will not recompile or reload the file redundantly.
108
+
109
+ ---
110
+
111
+ ### Phase 2: Curated VFS, Browser Buffer & Selection Persistence
112
+
113
+ #### 1. Curated Files Explorer
114
+ In the Web REPL "Files" (VFS) explorer, the visible files are strictly curated to verified examples and codecs:
115
+ - **k-codes**: `core.k`, `arithmetics.k`, `ieee.k`
116
+ - **codecs**: `json.mjs`, `utf8.mjs`, `int.mjs`, `unit.mjs`, `ieee.mjs`
117
+ - User-created or uploaded files remain visible.
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
+ - Clicking "Load" on a `.mjs` file automatically executes `:codec load <filename>`.
120
+
121
+ #### 2. Browser Buffer 64-bit Float & Int Methods
122
+ `browser/shims/buffer.mjs` implements:
123
+ - `writeDoubleBE`, `readDoubleBE`, `writeDoubleLE`, `readDoubleLE`
124
+ - `writeFloatBE`, `readFloatBE`, `writeFloatLE`, `readFloatLE`
125
+ - `writeBigUInt64BE`, `readBigUInt64BE`, `writeBigUInt64LE`, `readBigUInt64LE`
126
+ - `writeBigInt64BE`, `readBigInt64BE`, `writeBigInt64LE`, `readBigInt64LE`
127
+ - Complete integer read/write methods (`UInt32`, `Int32`, `UInt16`, `Int16`, `UInt8`, `Int8`).
128
+ - `globalThis.Buffer = Buffer` set unconditionally in the browser environment.
129
+ This fixes `:input {string a, float64 n}` number parsing in JSON and IEEE codecs in browser runtime.
130
+
131
+ #### 3. Persistent Console Selection
132
+ - Replaced the global document click focus-stealer with:
133
+ - Click listener on `.terminal-input-bar` (clicking prompt line focuses input).
134
+ - Keydown typing handler on `window` (typing printable characters outside modals/inputs focuses input).
135
+ - Mouse selection in `.terminal-output` never collapses on click/mouseup.
@@ -0,0 +1,144 @@
1
+ # Project Dependency Graph
2
+
3
+ _Auto-generated by scripts/generate-dependency-graph.mjs._
4
+
5
+ ```mermaid
6
+ graph TD
7
+ classDef default fill:#fff,stroke:#333,stroke-width:2px,color:#000;
8
+
9
+ Graph_mjs["Graph.mjs (1.9 KB)<br/>██"]
10
+ TypeGraph_mjs["TypeGraph.mjs (1.1 KB)<br/>█"]
11
+ TypePatternGraph_mjs["TypePatternGraph.mjs (8.0 KB)<br/>████████"]
12
+ Value_mjs["Value.mjs (5.4 KB)<br/>█████"]
13
+ augmentation_mjs["augmentation.mjs (6.9 KB)<br/>███████"]
14
+ codecs_example_pipeline_mjs["codecs/example-pipeline.mjs (5.1 KB)<br/>█████"]
15
+ codecs_ieee_mjs["codecs/ieee.mjs (4.3 KB)<br/>████"]
16
+ codecs_int_mjs["codecs/int.mjs (3.5 KB)<br/>████"]
17
+ codecs_json_codec_mjs["codecs/json-codec.mjs (6.2 KB)<br/>██████"]
18
+ codecs_json_mjs["codecs/json.mjs (1.5 KB)<br/>██"]
19
+ codecs_k_parse_mjs["codecs/k-parse.mjs (3.0 KB)<br/>███"]
20
+ codecs_k_print_mjs["codecs/k-print.mjs (1.5 KB)<br/>██"]
21
+ codecs_runtime_codec_mjs["codecs/runtime/codec.mjs (25.7 KB)<br/>████████████████████"]
22
+ codecs_runtime_ieee_pattern_mjs["codecs/runtime/ieee-pattern.mjs (1.1 KB)<br/>█"]
23
+ codecs_runtime_pattern_json_mjs["codecs/runtime/pattern-json.mjs (3.5 KB)<br/>███"]
24
+ codecs_runtime_prefix_codec_mjs["codecs/runtime/prefix-codec.mjs (13.7 KB)<br/>██████████████"]
25
+ codecs_runtime_show_value_mjs["codecs/runtime/show-value.mjs (2.1 KB)<br/>██"]
26
+ codecs_runtime_test_codec_mjs["codecs/runtime/test-codec.mjs (3.0 KB)<br/>███"]
27
+ codecs_runtime_typeFromValue_mjs["codecs/runtime/typeFromValue.mjs (0.9 KB)<br/>█"]
28
+ codecs_runtime_unicode_string_mjs["codecs/runtime/unicode-string.mjs (7.5 KB)<br/>████████"]
29
+ codecs_show_mjs["codecs/show.mjs (1.5 KB)<br/>██"]
30
+ codecs_string_codec_mjs["codecs/string-codec.mjs (4.5 KB)<br/>█████"]
31
+ codecs_unit_mjs["codecs/unit.mjs (1.6 KB)<br/>██"]
32
+ codecs_utf16_mjs["codecs/utf16.mjs (2.2 KB)<br/>██"]
33
+ codecs_utf8_mjs["codecs/utf8.mjs (1.3 KB)<br/>█"]
34
+ codes_mjs["codes.mjs (9.9 KB)<br/>██████████"]
35
+ compiler_mjs["compiler.mjs (3.9 KB)<br/>████"]
36
+ convergence_mjs["convergence.mjs (6.5 KB)<br/>██████"]
37
+ export_mjs["export.mjs (5.2 KB)<br/>█████"]
38
+ hash_mjs["hash.mjs (1.1 KB)<br/>█"]
39
+ index_mjs["index.mjs (1.9 KB)<br/>██"]
40
+ k_mjs["k.mjs (2.7 KB)<br/>███"]
41
+ object_mjs["object.mjs (26.3 KB)<br/>████████████████████"]
42
+ pretty_mjs["pretty.mjs (5.6 KB)<br/>██████"]
43
+ repl_mjs["repl.mjs (29.3 KB)<br/>████████████████████"]
44
+ run_mjs["run.mjs (14.4 KB)<br/>██████████████"]
45
+ symbol_table_mjs["symbol-table.mjs (2.7 KB)<br/>███"]
46
+ typing_mjs["typing.mjs (4.9 KB)<br/>█████"]
47
+ unification_mjs["unification.mjs (5.4 KB)<br/>█████"]
48
+ valueIO_mjs["valueIO.mjs (1.8 KB)<br/>██"]
49
+
50
+ TypePatternGraph_mjs --> Graph_mjs
51
+ TypePatternGraph_mjs --> unification_mjs
52
+ TypePatternGraph_mjs --> TypeGraph_mjs
53
+ augmentation_mjs --> codes_mjs
54
+ codecs_example_pipeline_mjs --> codecs_runtime_codec_mjs
55
+ codecs_example_pipeline_mjs --> codecs_runtime_prefix_codec_mjs
56
+ codecs_example_pipeline_mjs --> codecs_runtime_pattern_json_mjs
57
+ codecs_example_pipeline_mjs --> Value_mjs
58
+ codecs_example_pipeline_mjs --> hash_mjs
59
+ codecs_ieee_mjs --> Value_mjs
60
+ codecs_ieee_mjs --> codecs_runtime_prefix_codec_mjs
61
+ codecs_ieee_mjs --> codecs_runtime_ieee_pattern_mjs
62
+ codecs_int_mjs --> Value_mjs
63
+ codecs_int_mjs --> codecs_runtime_prefix_codec_mjs
64
+ codecs_json_codec_mjs --> Value_mjs
65
+ codecs_json_codec_mjs --> codecs_string_codec_mjs
66
+ codecs_json_codec_mjs --> codecs_runtime_ieee_pattern_mjs
67
+ codecs_json_mjs --> codecs_runtime_prefix_codec_mjs
68
+ codecs_json_mjs --> codecs_json_codec_mjs
69
+ codecs_k_parse_mjs --> index_mjs
70
+ codecs_k_parse_mjs --> valueIO_mjs
71
+ codecs_k_parse_mjs --> codecs_runtime_codec_mjs
72
+ codecs_k_parse_mjs --> codecs_runtime_pattern_json_mjs
73
+ codecs_k_parse_mjs --> codecs_runtime_prefix_codec_mjs
74
+ codecs_k_print_mjs --> codecs_runtime_prefix_codec_mjs
75
+ codecs_runtime_codec_mjs --> Value_mjs
76
+ codecs_runtime_codec_mjs --> TypePatternGraph_mjs
77
+ codecs_runtime_codec_mjs --> typing_mjs
78
+ codecs_runtime_codec_mjs --> codes_mjs
79
+ codecs_runtime_codec_mjs --> codecs_runtime_pattern_json_mjs
80
+ codecs_runtime_ieee_pattern_mjs --> codes_mjs
81
+ codecs_runtime_ieee_pattern_mjs --> codecs_runtime_codec_mjs
82
+ codecs_runtime_ieee_pattern_mjs --> codecs_runtime_pattern_json_mjs
83
+ codecs_runtime_prefix_codec_mjs --> Value_mjs
84
+ codecs_runtime_prefix_codec_mjs --> codecs_runtime_codec_mjs
85
+ codecs_runtime_prefix_codec_mjs --> codecs_runtime_pattern_json_mjs
86
+ codecs_runtime_prefix_codec_mjs --> codecs_runtime_unicode_string_mjs
87
+ codecs_runtime_show_value_mjs --> Value_mjs
88
+ codecs_runtime_test_codec_mjs --> codecs_runtime_codec_mjs
89
+ codecs_runtime_test_codec_mjs --> codecs_runtime_prefix_codec_mjs
90
+ codecs_runtime_test_codec_mjs --> codecs_runtime_pattern_json_mjs
91
+ codecs_runtime_test_codec_mjs --> Value_mjs
92
+ codecs_runtime_test_codec_mjs --> hash_mjs
93
+ codecs_runtime_typeFromValue_mjs --> Value_mjs
94
+ codecs_runtime_unicode_string_mjs --> Value_mjs
95
+ codecs_show_mjs --> codecs_runtime_prefix_codec_mjs
96
+ codecs_show_mjs --> codecs_runtime_show_value_mjs
97
+ codecs_string_codec_mjs --> codecs_runtime_codec_mjs
98
+ codecs_string_codec_mjs --> codecs_runtime_prefix_codec_mjs
99
+ codecs_string_codec_mjs --> codecs_runtime_pattern_json_mjs
100
+ codecs_string_codec_mjs --> codecs_runtime_unicode_string_mjs
101
+ codecs_unit_mjs --> Value_mjs
102
+ codecs_unit_mjs --> codecs_runtime_prefix_codec_mjs
103
+ codecs_utf16_mjs --> codecs_string_codec_mjs
104
+ codecs_utf8_mjs --> codecs_string_codec_mjs
105
+ codes_mjs --> hash_mjs
106
+ compiler_mjs --> hash_mjs
107
+ compiler_mjs --> TypePatternGraph_mjs
108
+ compiler_mjs --> Graph_mjs
109
+ compiler_mjs --> codes_mjs
110
+ compiler_mjs --> augmentation_mjs
111
+ compiler_mjs --> export_mjs
112
+ compiler_mjs --> convergence_mjs
113
+ convergence_mjs --> pretty_mjs
114
+ convergence_mjs --> typing_mjs
115
+ export_mjs --> hash_mjs
116
+ export_mjs --> pretty_mjs
117
+ index_mjs --> Value_mjs
118
+ index_mjs --> valueIO_mjs
119
+ index_mjs --> compiler_mjs
120
+ index_mjs --> run_mjs
121
+ index_mjs --> codes_mjs
122
+ k_mjs --> index_mjs
123
+ k_mjs --> codecs_runtime_prefix_codec_mjs
124
+ k_mjs --> object_mjs
125
+ object_mjs --> index_mjs
126
+ object_mjs --> run_mjs
127
+ object_mjs --> codes_mjs
128
+ object_mjs --> TypePatternGraph_mjs
129
+ object_mjs --> pretty_mjs
130
+ pretty_mjs --> TypePatternGraph_mjs
131
+ repl_mjs --> index_mjs
132
+ repl_mjs --> run_mjs
133
+ repl_mjs --> codes_mjs
134
+ repl_mjs --> Value_mjs
135
+ repl_mjs --> pretty_mjs
136
+ repl_mjs --> object_mjs
137
+ repl_mjs --> codecs_runtime_show_value_mjs
138
+ run_mjs --> Value_mjs
139
+ run_mjs --> codecs_runtime_codec_mjs
140
+ run_mjs --> codecs_runtime_pattern_json_mjs
141
+ symbol_table_mjs --> hash_mjs
142
+ typing_mjs --> TypePatternGraph_mjs
143
+ valueIO_mjs --> Value_mjs
144
+ ```