@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,67 @@
1
+ -- Examples/poly.k: Polymorphic list functions in k
2
+ -- Uses list constructors/destructors from Examples/list.k
3
+ -- and arbitrary-precision integer representations from Examples/arithmetics.k.
4
+
5
+ -- Decrement an integer and normalize its representation (stripping leading zeros)
6
+ pred_int = dec /'+' nat | '+';
7
+
8
+ -- Concatenate two lists: {xs, ys} -> list
9
+ concat = {.xs reverse xs, .ys acc} _reverse;
10
+
11
+ -- Reverse a list: xs -> list
12
+ reverse = {() xs, nil acc} _reverse;
13
+ _reverse = <
14
+ {.xs cdr xs, {.xs car car, .acc cdr} cons acc} _reverse,
15
+ .acc
16
+ >;
17
+
18
+ -- Length of a list: xs -> int
19
+ length = {() xs, 0 int acc} _length;
20
+ _length = <
21
+ {.xs /nil if, .acc then} .then,
22
+ {.xs cdr xs, .acc inc acc} _length
23
+ >;
24
+
25
+ -- Get N-th element of a list (0-indexed): {n, xs} -> element
26
+ get_nth = <
27
+ {.n zero_int? if, .xs car then} .then,
28
+ {.n pred_int n, .xs cdr xs} get_nth
29
+ >;
30
+
31
+ -- Split list at index N: {n, xs} -> {first, second}
32
+ split_by = {.n n, .xs xs, nil acc} _split_by;
33
+ _split_by = <
34
+ {.n zero_int? if, {.acc reverse first, .xs second} then} .then,
35
+ {.xs /nil if, {.acc reverse first, nil second} then} .then,
36
+ {.n pred_int n, .xs cdr xs, {.xs car car, .acc cdr} cons acc} _split_by
37
+ >;
38
+
39
+ -- Take the first N elements of a list: {n, xs} -> list
40
+ take = split_by .first;
41
+
42
+ -- Drop the first N elements of a list: {n, xs} -> list
43
+ drop = <
44
+ {.n zero_int? if, .xs then} .then,
45
+ {.xs /nil if, nil then} .then,
46
+ {.n pred_int n, .xs cdr xs} drop
47
+ >;
48
+
49
+ -- Repeat element X, N times: {n, x} -> list
50
+ repeat = {.n n, .x x, nil acc} _repeat;
51
+ _repeat = <
52
+ {.n zero_int? if, .acc then} .then,
53
+ {.n pred_int n, .x x, {.x car, .acc cdr} cons acc} _repeat
54
+ >;
55
+
56
+ -- Append an element to the end of a list: {x, xs} -> list
57
+ append = {.xs xs, {.x car, nil cdr} cons ys} concat;
58
+
59
+ -- Zip two lists into a list of {x, y} pairs: {xs, ys} -> list
60
+ zip = <
61
+ {.xs /nil if, nil then} .then,
62
+ {.ys /nil if, nil then} .then,
63
+ {
64
+ {.xs car x, .ys car y} car,
65
+ {.xs cdr xs, .ys cdr ys} zip cdr
66
+ } cons
67
+ >;
package/README.md CHANGED
@@ -64,6 +64,15 @@ one successor. The REPL also prints the inferred value envelope.
64
64
 
65
65
  ## Try It
66
66
 
67
+ ### In the Browser (Zero Install)
68
+
69
+ Try k directly in your browser without installing anything:
70
+ **[https://fraczak.github.io/k/](https://fraczak.github.io/k/)**
71
+
72
+ The Web REPL is self-contained, powered by an in-process WebAssembly compiler and execution engine with built-in codecs, autocompletion, interactive input, and standard libraries.
73
+
74
+ ### From Source
75
+
67
76
  From a checkout:
68
77
 
69
78
  ```bash
@@ -91,6 +100,13 @@ Start the interactive interpreter:
91
100
  k-repl
92
101
  ```
93
102
 
103
+ Build the standalone single-file Web REPL locally:
104
+
105
+ ```bash
106
+ npm run build:repl-html
107
+ # generates repl.html (open in any web browser)
108
+ ```
109
+
94
110
  Every installed command supports `-h` and `--help`.
95
111
 
96
112
  ## What k Gives You
@@ -149,13 +165,13 @@ k-print # binary pattern+value stream -> textual value
149
165
 
150
166
  k programs can be compiled into:
151
167
 
152
- - `.klib`: plain JSON library objects
168
+ - `.klib`: library objects
153
169
  - `.ko`: executable binary object containers
154
- - `.kvm`: JSON kVM programs
170
+ - `.kvm`: specialized kVM backend artifacts
155
171
 
156
172
  Object and library files keep canonical code/relation definitions, aliases,
157
- metadata, and type-derivation status. The `.kvm` output is a lowered JSON
158
- program for backend inspection and execution experiments.
173
+ metadata, and type-derivation status. The `.kvm` output is a lowered backend
174
+ artifact for inspection and execution experiments.
159
175
 
160
176
  ## CLI Tour
161
177
 
@@ -191,17 +207,30 @@ program for backend inspection and execution experiments.
191
207
  | `k-compile` | Compile `.k` source to `.ko`, `.klib`, or `.kvm` output |
192
208
  | `k-decompile` | Decompile `.ko` or `.klib` back to k source |
193
209
  | `k-extract-aliases` | Recover metadata aliases as k source |
210
+ | `k-inspect-object` | Inspect object sections or print the KIR-P backend export |
211
+ | `k-validate-object` | Validate `.ko`, `.klib`, or exported KIR-P artifacts |
212
+ | `k-kir` | Export KIR-P from `.ko` or `.klib` |
213
+ | `k-vm` | Execute or inspect lowered kVM bytecode artifacts (`.kvm`) |
214
+ | `k-wasm` / `k-wasm-compile` / `k-wasm-run` | Compile and run via WebAssembly backend |
215
+ | `k-llvm-build` / `k-llvm-compile` / `k-llvm-run` | Compile and run via LLVM backend |
216
+ | `k-arm64` / `k-arm64-compile` / `k-arm64-run` | Compile and run via Linux ARM64 native backend |
194
217
 
195
218
  Installed binary names are `k-` plus the source basename without `.mjs`, except
196
219
  for `k.mjs` itself. Source names that already include `k-`, such as
197
220
  `codecs/k-parse.mjs`, keep that name.
198
221
 
199
- ## WebAssembly Backend
222
+ ## Backends
223
+
224
+ Backends live under [`backends/`](backends/) as npm workspaces:
225
+
226
+ - [`backends/wasm`](backends/wasm/) lowers typed k programs through kVM into
227
+ WebAssembly artifacts. Powers both the CLI REPL (`wasm-in-process`) and the standalone Web REPL.
228
+ - [`backends/llvm`](backends/llvm/) lowers polymorphic kVM programs into LLVM IR and
229
+ compiled native test executables.
230
+ - [`backends/arm64`](backends/arm64/) lowers polymorphic kVM programs directly into
231
+ standalone Linux ARM64 native executables without external compiler dependencies.
200
232
 
201
- The experimental WebAssembly backend lives in the separate
202
- [`fraczak/k-wasm`](https://github.com/fraczak/k-wasm) repository. Keeping the
203
- backend separate avoids adding its WABT dependency to the core runtime. External
204
- backends integrate with the compiler and binary codecs through
233
+ All backends integrate with the compiler and binary codecs through
205
234
  [`backend-api.mjs`](backend-api.mjs).
206
235
 
207
236
  ## Node.js API
@@ -265,28 +294,41 @@ serialization, or teaching tools, there is room to shape the project.
265
294
 
266
295
  ## Examples
267
296
 
268
- The [`Examples/`](Examples/) directory contains small language demonstrations:
297
+ The [`Examples/`](Examples/) directory contains language demonstrations and standard libraries:
269
298
 
270
299
  | File | Contents |
271
300
  | --- | --- |
301
+ | `core.k` | Standard library: booleans, units, strings, optionals, and fundamental helpers |
302
+ | `arithmetics.k` | Integer and rational arithmetic built from bit-level relations from scratch |
303
+ | `ieee.k` | IEEE 754 binary64 floating-point arithmetic (`add`, `sub`, `mul`, `div`) |
304
+ | `poly.k` | Polymorphic list operations (`concat`, `reverse`, `length`, `get_nth`, `split_by`, `zip`) |
272
305
  | `nat.k` | Peano natural numbers |
273
306
  | `byte.k` | Byte type |
274
- | `ieee.k` | IEEE 754 floating-point layout |
275
307
  | `bnat.k` | Binary natural numbers |
276
- | `arithmetics.k` | Integer and rational arithmetic built from scratch |
308
+ | `buda.k` | Compact relational data transformations |
277
309
 
278
310
  `list.k` is also useful as a focused demonstration of filters and patterns.
279
311
 
280
- `ieee.k` is the largest example. It builds an IEEE-754 binary64 model from
281
- bit-level types upward, including comparison and floating-point `add`, `sub`,
282
- `mul`, and `div` relations. Those public aliases return `{ result, flags }`;
283
- compose with `.result` when only the floating-point value is needed.
312
+ `ieee.k` is a complete IEEE-754 binary64 model built from bit-level types
313
+ upward with hierarchical significand adders, including comparison and
314
+ floating-point `add`, `sub`, `mul`, and `div` relations. Those public aliases
315
+ return `{ result, flags }`; compose with `.result` when only the floating-point
316
+ value is needed.
284
317
 
285
318
  ## Development
286
319
 
287
320
  ```bash
288
- npm run prepare # regenerate parsers from .jison grammars
289
- npm test # run the fail-fast full suite with per-test timings
321
+ npm run prepare # regenerate parsers from .jison grammars
322
+ npm test # run the fail-fast full suite with per-test timings
323
+ npm run test:wasm # run the WebAssembly backend tests
324
+ npm run test:llvm # run the LLVM backend tests
325
+ npm run test:arm64 # run the Linux ARM64 backend tests
326
+ npm run build:repl-html # build the standalone single-file Web REPL (repl.html)
327
+ npm run compare # run multi-backend benchmark and conformance harness
328
+ npm run perf:poly # run polymorphic benchmark across backends
329
+ npm run perf:poly:trace # run execution phase tracing & call profiling
330
+ npm run perf:int # run integer arithmetic benchmark across backends
331
+ npm run perf:ieee # run IEEE-754 arithmetic benchmark across backends
290
332
  ```
291
333
 
292
334
  The test runner prints each test before execution and reports its elapsed time
@@ -297,14 +339,21 @@ afterward. It stops immediately when a test fails. The suite covers:
297
339
  - hash/fingerprint stability
298
340
  - object file round-trips
299
341
  - REPL scripted interaction
342
+ - Web REPL headless browser verification
343
+ - polymorphic kVM and specialization
300
344
  - shell integration tests
301
345
 
302
346
  ## Further Reading
303
347
 
304
- - [DOCS/REPL.md](DOCS/REPL.md) - interactive interpreter details
348
+ - [DOCS/DICTIONARY.md](DOCS/DICTIONARY.md) - concept names and terminology
349
+ - [DOCS/REPL.md](DOCS/REPL.md) - interactive interpreter and codec details
350
+ - [DOCS/WEB_REPL_REQUIREMENTS.md](DOCS/WEB_REPL_REQUIREMENTS.md) - Web REPL architecture and requirements
351
+ - [DOCS/KVM_EXECUTION_MODEL.md](DOCS/KVM_EXECUTION_MODEL.md) - kVM execution model and bytecode design
305
352
  - [DOCS/TEXTUAL_VALUES.md](DOCS/TEXTUAL_VALUES.md) - textual boundary notation
306
353
  - [DOCS/PATTERNS.md](DOCS/PATTERNS.md) - pattern representation
307
354
  - [DOCS/OBJECT_FILE_AND_PATTERN.md](DOCS/OBJECT_FILE_AND_PATTERN.md) - object format
355
+ - [DOCS/PROFILING_AND_TRACING.md](DOCS/PROFILING_AND_TRACING.md) - execution phase tracing and function call profiling across backends
356
+ - [DOCS/CODECS.md](DOCS/CODECS.md) - writing external codecs
308
357
  - [codecs/README.md](codecs/README.md) - binary codec internals
309
358
  - [objects/README.md](objects/README.md) - object/library tools
310
359
  - [DOCS/book.md](DOCS/book.md) - longer language reference
package/Value.mjs CHANGED
@@ -176,8 +176,14 @@ class Value {
176
176
 
177
177
  toString() {
178
178
  if (isVariant(this)) {
179
- // return `{${JSON.stringify(this.tag)}:${this.value.toString()}}`;
180
- return `${this.value.toString()}|${pLabel(this.tag)}`;
179
+ const tags = [];
180
+ let curr = this;
181
+ while (isVariant(curr)) {
182
+ tags.push(pLabel(curr.tag));
183
+ curr = curr.value;
184
+ }
185
+ const base = curr ? curr.toString() : "";
186
+ return tags.length === 0 ? base : `${base}|${tags.reverse().join("|")}`;
181
187
  }
182
188
  if (isProduct(this)) {
183
189
  return `{${Object.entries(this.product).map(([k, v]) => `${JSON.stringify(k)}:${v.toString()}`).join(',')}}`;
package/augmentation.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import codes from "./codes.mjs";
2
+ import { getIntrinsic } from "./intrinsics.mjs";
2
3
 
3
4
  const unitCode = codes.unitCode;
4
5
 
@@ -187,12 +188,13 @@ function augmentRef(rel,rootDef,rels) {
187
188
  });
188
189
  return;
189
190
  }
190
- // it is built-in
191
- switch (rel.ref) {
192
- case "_log!":
193
- rel.patterns[0] = rel.patterns[1] = rootDef.typePatternGraph.addNewNode();
194
- break;
195
- default:
196
- throw new Error(`No definition found for '${rel.ref}'`);
191
+ const intrinsic = getIntrinsic(rel.ref);
192
+ if (intrinsic) {
193
+ if (intrinsic.type !== "identity") {
194
+ throw new Error(`No type rule found for intrinsic '${rel.ref}'`);
195
+ }
196
+ rel.patterns[0] = rel.patterns[1] = rootDef.typePatternGraph.addNewNode();
197
+ return;
197
198
  }
199
+ throw new Error(`No definition found for '${rel.ref}'`);
198
200
  }
package/backend-api.mjs CHANGED
@@ -1,12 +1,21 @@
1
1
  export { annotate } from "./index.mjs";
2
- export { lowerToKVM, executeKVM } from "./kvm.mjs";
2
+ export { KVM_FORMAT, KVM_VERSION, lowerKIRRelationToKVM, lowerKIRToKVM, lowerToKVM, executeKVM, objectToKVMArtifact, specializeKVM } from "./kvm.mjs";
3
3
  export { decodeWire, encodeToWire } from "./codecs/runtime/prefix-codec.mjs";
4
4
  export { exportPatternGraph, NODE_KIND } from "./codecs/runtime/codec.mjs";
5
5
  export { patternToPropertyList, propertyListToPattern } from "./codecs/runtime/pattern-json.mjs";
6
6
  export { Value, fromObject, isProduct, isVariant, isValue } from "./Value.mjs";
7
- export { decodeObject, loadLibrary } from "./object.mjs";
7
+ export { KIR_FORMAT, KIR_VERSION, objectToKIRP, retypeObjectRelation, retypeObjectRelationForBackend } from "./kir.mjs";
8
+ export { compileLibrary, decodeObject, loadLibrary } from "./object.mjs";
8
9
  export { createState, evaluateInput } from "./repl.mjs";
9
10
  export { parse as parseFloat64, print as printFloat64 } from "./codecs/ieee.mjs";
10
11
  export { valueForCode } from "./repl-codecs.mjs";
11
12
  export { default as codes } from "./codes.mjs";
12
13
  export { default as run, run_converged } from "./run.mjs";
14
+ export {
15
+ intrinsicDefinitions,
16
+ jsIntrinsicFunctions,
17
+ getIntrinsic,
18
+ isIntrinsic,
19
+ isIdentityIntrinsic,
20
+ unsupportedIntrinsic
21
+ } from "./intrinsics.mjs";
@@ -0,0 +1,104 @@
1
+ # k Linux ARM64 Backend
2
+
3
+ `@fraczak/k-arm64` is the native Linux AArch64 (ARM64) backend for
4
+ [`@fraczak/k`](https://github.com/fraczak/k). It lowers typed k programs directly from
5
+ the kVM representation into GNU AArch64 assembly text (`.s`), compiles native ELF
6
+ executables, and provides CLI tools and runners for binary `pattern + value` streams
7
+ and `--json` input/output.
8
+
9
+ ## Features
10
+
11
+ - **Direct kVM to ARM64 Lowering**: Generates pure GNU AArch64 assembly text without requiring LLVM or external code generators.
12
+ - **Calling Convention & Registers (AAPCS64)**:
13
+ - `x0`: Input value pointer on entry; Return status (`0` for success, non-zero for failure) on exit.
14
+ - `x1`: Output value pointer on exit.
15
+ - `x19`: Callee-saved Arena bump pointer preserved and updated across relation calls.
16
+ - Standard 16-byte stack frame alignment with FP (`x29`) and LR (`x30`) chaining.
17
+ - **Flat Arena Memory Representation**:
18
+ - Word 0 (bytes 0–1): Total block size in bytes (16-byte aligned).
19
+ - Word 1 (bytes 2–3): Value kind (`1` = Product, `2` = Variant).
20
+ - Word 2 (bytes 4–7): Product field count OR Variant 32-bit tag ID.
21
+ - Payloads (bytes 8+): 64-bit pointers to child values in the arena.
22
+ - **Self Tail-Call Optimization (TCO)**:
23
+ - Recursion where the tail call passes new product fields directly updates cached field slots and jumps back to `.Ltail_loop` with zero frame overhead, enabling deep recursion without stack overflow.
24
+ - **Union Backtracking & Memory Rollback**:
25
+ - Union branches save the arena bump pointer (`x19`) before evaluation. If a branch fails, `x19` is rewound to cleanly roll back all allocations made in the failed speculative branch before attempting subsequent branches.
26
+ - **Standalone Linux Binaries**:
27
+ - Links with a lightweight C driver (`backends/arm64/src/runtime.c`) and `backends/llvm/runtime/krt.c` to produce independent native ELF executables that execute directly on Linux without Node.js.
28
+ - Supports `--json` for direct text output, stdin/stdout piping, and binary envelope streams.
29
+
30
+ ## Quick Start
31
+
32
+ Compile an expression to a standalone native Linux ARM64 executable:
33
+
34
+ ```bash
35
+ node ./backends/arm64/bin/k-arm64-compile.mjs -o /tmp/ok '|ok'
36
+ ```
37
+
38
+ Execute it over unit input and decode output:
39
+
40
+ ```bash
41
+ node ./codecs/unit.mjs --parse | /tmp/ok --json
42
+ ```
43
+
44
+ Output:
45
+ ```json
46
+ "ok"
47
+ ```
48
+
49
+ Compile with library dependencies (`--lib` and `--export`):
50
+
51
+ ```bash
52
+ node ./backends/arm64/bin/k-arm64-compile.mjs \
53
+ --lib Examples/arithmetics.k \
54
+ --export plus:+ --export succ --export int \
55
+ '{succ int x,int y}+' \
56
+ -o /tmp/add-one
57
+
58
+ node ./codecs/k-parse.mjs <<< '{"x":{"succ":"zero"},"y":{"succ":{"succ":"zero"}}}' |
59
+ /tmp/add-one --json
60
+ ```
61
+
62
+ Output:
63
+ ```json
64
+ {"+":{"1":"_"}}
65
+ ```
66
+
67
+ ## CLI Commands
68
+
69
+ | Command | Purpose |
70
+ | --- | --- |
71
+ | `k-arm64` | Compile k source, `.ko`, or `.kvm` in memory and run immediately |
72
+ | `k-arm64-compile` | Compile k source, `.ko`, or `.kvm` to standalone ELF executable or assembly (`-S`) |
73
+ | `k-arm64-run` | Run a compiled ELF executable over binary wire streams |
74
+
75
+ ### Options
76
+
77
+ All tools accept `--help`.
78
+
79
+ - `-S, --assembly`: Emit GNU ARM64 assembly text (`.s`) instead of an ELF binary.
80
+ - `-o, --output <file>`: Specify the output file path.
81
+ - `--entry <name>`: Specify the entry relation (defaults to `__main__`).
82
+ - `--lib <file>`: Load one `.klib` or `.k` library dependency.
83
+ - `--export <spec>`: Export library symbols into source scope (`name` or `libname:localname`).
84
+ - `--json`: Format output as JSON instead of binary wire format.
85
+
86
+ ## Running Tests
87
+
88
+ Run unit tests:
89
+
90
+ ```bash
91
+ node ./backends/arm64/tests/test-arm64.mjs
92
+ ```
93
+
94
+ Run integration tests:
95
+
96
+ ```bash
97
+ ./backends/arm64/tests/integration.sh
98
+ ```
99
+
100
+ Run the complete ARM64 backend test suite:
101
+
102
+ ```bash
103
+ npm run test:arm64
104
+ ```
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import { argv, exit, stdin, stdout } from "node:process";
5
+
6
+ import {
7
+ compileProgramInput,
8
+ parseCompileOptions,
9
+ resolveProgramInput
10
+ } from "../src/cli.mjs";
11
+
12
+ function usage(stream = console.error) {
13
+ const prog = argv[1] || "k-arm64-compile.mjs";
14
+ stream(`Usage: node ${prog} [options] [source-snippet | input-file [output-file]]`);
15
+ stream("Compile k source, .ko, or .kvm input into a standalone Linux ARM64 executable or assembly.");
16
+ stream("");
17
+ stream("Arguments:");
18
+ stream(" source-snippet Inline k source, in the same style as k.mjs.");
19
+ stream(" input-file Source .k, .ko, or .kvm file. Reads UTF-8 source from stdin when omitted.");
20
+ stream(" output-file Output file path. Writes to stdout when omitted and --assembly is set.");
21
+ stream("");
22
+ stream("Options:");
23
+ stream(" -S, --assembly Emit GNU ARM64 assembly (.s) instead of an executable binary.");
24
+ stream(" -o, --output Specify output file path explicitly.");
25
+ stream(" --entry name Specify entry relation name.");
26
+ stream(" --lib file Load one .klib dependency before compiling.");
27
+ stream(" --export spec Export a library alias into source scope. May be repeated.");
28
+ stream(" spec is 'name' or 'libname:localname'.");
29
+ stream(" -h, --help Show this help.");
30
+ }
31
+
32
+ try {
33
+ const args = argv.slice(2);
34
+ if (args.includes("-h") || args.includes("--help")) {
35
+ usage(console.log);
36
+ exit(0);
37
+ }
38
+
39
+ let emitAssembly = false;
40
+ let explicitOutput = null;
41
+ let entry = null;
42
+
43
+ // Extract ARM64-specific flags
44
+ const remainingArgs = [];
45
+ while (args.length > 0) {
46
+ const arg = args[0];
47
+ if (arg === "-S" || arg === "--assembly") {
48
+ emitAssembly = true;
49
+ args.shift();
50
+ } else if (arg === "-o" || arg === "--output") {
51
+ args.shift();
52
+ explicitOutput = args.shift();
53
+ if (!explicitOutput) throw new Error("-o/--output requires a file argument");
54
+ } else if (arg === "--entry") {
55
+ args.shift();
56
+ entry = args.shift();
57
+ if (!entry) throw new Error("--entry requires a name argument");
58
+ } else {
59
+ remainingArgs.push(args.shift());
60
+ }
61
+ }
62
+
63
+ const { libraries, exportSpecs } = parseCompileOptions(remainingArgs);
64
+ const input = resolveProgramInput(remainingArgs, { allowStdinSource: true });
65
+ const positionalOutput = remainingArgs.shift();
66
+ if (remainingArgs.length > 0) throw new Error("Too many arguments");
67
+
68
+ const outputPath = explicitOutput || positionalOutput || null;
69
+
70
+ const result = await compileProgramInput(input, {
71
+ libraries,
72
+ exportSpecs,
73
+ stdin,
74
+ entry,
75
+ emit: emitAssembly ? "assembly" : null,
76
+ outputPath: (!emitAssembly && outputPath) ? outputPath : null
77
+ });
78
+
79
+ if (emitAssembly) {
80
+ const asmText = typeof result === "string" ? result : result.assembly;
81
+ if (outputPath == null) {
82
+ stdout.write(asmText);
83
+ } else {
84
+ fs.writeFileSync(outputPath, asmText, "utf8");
85
+ }
86
+ } else {
87
+ if (outputPath == null) {
88
+ if (Buffer.isBuffer(result)) {
89
+ stdout.write(result);
90
+ } else if (typeof result === "string") {
91
+ stdout.write(fs.readFileSync(result));
92
+ }
93
+ } else if (Buffer.isBuffer(result)) {
94
+ fs.writeFileSync(outputPath, result, { mode: 0o755 });
95
+ }
96
+ }
97
+ } catch (error) {
98
+ console.error(error.stack || error.message || String(error));
99
+ usage();
100
+ exit(1);
101
+ }
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import { argv, exit, stdin, stdout } from "node:process";
5
+
6
+ import { readAll } from "../src/cli.mjs";
7
+ import { runARM64Artifact } from "../src/arm64.mjs";
8
+
9
+ function usage(stream = console.error) {
10
+ const prog = argv[1] || "k-arm64-run.mjs";
11
+ stream(`Usage: node ${prog} [options] executable-file [input-file]`);
12
+ stream("Run a standalone k Linux ARM64 executable over a binary wire stream.");
13
+ stream("");
14
+ stream("Arguments:");
15
+ stream(" executable-file Input compiled ELF binary produced by k-arm64-compile.");
16
+ stream(" input-file Optional binary input wire file. Reads stdin when omitted.");
17
+ stream("");
18
+ stream("Options:");
19
+ stream(" --json Format output as JSON instead of binary wire format.");
20
+ stream(" -h, --help Show this help.");
21
+ }
22
+
23
+ async function main() {
24
+ const args = argv.slice(2);
25
+ if (args.includes("-h") || args.includes("--help")) {
26
+ usage(console.log);
27
+ return;
28
+ }
29
+
30
+ let json = false;
31
+ const filteredArgs = [];
32
+ for (const arg of args) {
33
+ if (arg === "--json") {
34
+ json = true;
35
+ } else {
36
+ filteredArgs.push(arg);
37
+ }
38
+ }
39
+
40
+ const execPath = filteredArgs.shift();
41
+ if (!execPath) throw new Error("Missing executable artifact path");
42
+ const inputPath = filteredArgs.shift();
43
+ if (filteredArgs.length > 0) throw new Error("Too many arguments");
44
+
45
+ const input = await readAll(inputPath == null ? stdin : fs.createReadStream(inputPath));
46
+ const result = runARM64Artifact(execPath, input, { json });
47
+ if (json) {
48
+ stdout.write(result);
49
+ } else {
50
+ stdout.write(result);
51
+ }
52
+ }
53
+
54
+ main().catch((error) => {
55
+ console.error(error.stack || error.message || String(error));
56
+ usage();
57
+ exit(1);
58
+ });
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import { argv, exit, stdin, stdout } from "node:process";
5
+ import { decodeWire } from "../../../backend-api.mjs";
6
+
7
+ import {
8
+ compileProgramInput,
9
+ parseCompileOptions,
10
+ readAll,
11
+ resolveProgramInput
12
+ } from "../src/cli.mjs";
13
+ import { runARM64Artifact } from "../src/arm64.mjs";
14
+
15
+ function usage(stream = console.error) {
16
+ const prog = argv[1] || "k-arm64.mjs";
17
+ stream(`Usage: node ${prog} [options] ( source-snippet | input-file ) [ input-file ]`);
18
+ stream("Compile k source, .ko, or .kvm input to ARM64 in memory and run it over a binary pattern+value stream.");
19
+ stream("");
20
+ stream("Options:");
21
+ stream(" --json Format output as JSON instead of binary wire format.");
22
+ stream(" --entry name Specify entry relation name.");
23
+ stream(" --lib file Load one .klib dependency before compiling.");
24
+ stream(" --export spec Export a library alias into source scope. May be repeated.");
25
+ stream(" spec is 'name' or 'libname:localname'.");
26
+ stream(" -h, --help Show this help.");
27
+ }
28
+
29
+ async function main() {
30
+ const args = argv.slice(2);
31
+ if (args.includes("-h") || args.includes("--help")) {
32
+ usage(console.log);
33
+ return;
34
+ }
35
+
36
+ let json = false;
37
+ let entry = null;
38
+ const remainingArgs = [];
39
+ while (args.length > 0) {
40
+ const arg = args[0];
41
+ if (arg === "--json") {
42
+ json = true;
43
+ args.shift();
44
+ } else if (arg === "--entry") {
45
+ args.shift();
46
+ entry = args.shift();
47
+ if (!entry) throw new Error("--entry requires a name argument");
48
+ } else {
49
+ remainingArgs.push(args.shift());
50
+ }
51
+ }
52
+
53
+ const { libraries, exportSpecs } = parseCompileOptions(remainingArgs);
54
+ const programInput = resolveProgramInput(remainingArgs);
55
+ const inputPath = remainingArgs.shift();
56
+ if (remainingArgs.length > 0) throw new Error("Too many arguments");
57
+
58
+ const inputBuffer = await readAll(inputPath == null ? stdin : fs.createReadStream(inputPath));
59
+ let inputEnvelopePattern = null;
60
+ if (inputBuffer.length > 0) {
61
+ try {
62
+ const decoded = decodeWire(inputBuffer);
63
+ inputEnvelopePattern = decoded.pattern;
64
+ } catch {
65
+ // Not a valid wire buffer or empty
66
+ }
67
+ }
68
+
69
+ const artifact = await compileProgramInput(programInput, {
70
+ libraries,
71
+ exportSpecs,
72
+ inputEnvelopePattern,
73
+ entry
74
+ });
75
+
76
+ const output = runARM64Artifact(artifact, inputBuffer, { json });
77
+ if (json) {
78
+ stdout.write(output);
79
+ } else {
80
+ stdout.write(output);
81
+ }
82
+ }
83
+
84
+ main().catch((error) => {
85
+ console.error(error.stack || error.message || String(error));
86
+ usage();
87
+ exit(1);
88
+ });