@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,475 @@
1
+ (module
2
+ (memory (export "memory") 1)
3
+
4
+ ;; Start allocation at byte offset 1024 to leave a safety margin and avoid returning 0 (nullptr)
5
+ (global $arena_free (export "arena_free") (mut i32) (i32.const 1024))
6
+ ;; Maximum address of the currently allocated pages (1 page = 64KB)
7
+ (global $arena_max (export "arena_max") (mut i32) (i32.const 65536))
8
+ ;; Out-of-memory status flags
9
+ (global $oom_flag (export "oom_flag") (mut i32) (i32.const 0))
10
+ (global $oom_size (export "oom_size") (mut i32) (i32.const 0))
11
+
12
+ ;; Bump allocator function: aligns allocation size to 8 bytes, grows memory if needed, and returns the pointer
13
+ (func $alloc (export "alloc") (param $size i32) (result i32)
14
+ (local $old_free i32)
15
+ (local $new_free i32)
16
+ (local $pages_needed i32)
17
+ (local $grow_res i32)
18
+
19
+ ;; Check if size exceeds maximum allocatable size
20
+ local.get $size
21
+ i32.const -8
22
+ i32.gt_u
23
+ if
24
+ i32.const 1
25
+ global.set $oom_flag
26
+ local.get $size
27
+ global.set $oom_size
28
+ unreachable
29
+ end
30
+
31
+ ;; 1. Align size to 8 bytes: size = (size + 7) & ~8
32
+ local.get $size
33
+ i32.const 7
34
+ i32.add
35
+ i32.const -8
36
+ i32.and
37
+ local.set $size
38
+
39
+ ;; Get current free pointer
40
+ global.get $arena_free
41
+ local.set $old_free
42
+
43
+ ;; Calculate proposed new free pointer
44
+ local.get $old_free
45
+ local.get $size
46
+ i32.add
47
+ local.set $new_free
48
+
49
+ ;; Check for 32-bit unsigned overflow
50
+ local.get $new_free
51
+ local.get $old_free
52
+ i32.lt_u
53
+ if
54
+ i32.const 1
55
+ global.set $oom_flag
56
+ local.get $size
57
+ global.set $oom_size
58
+ unreachable
59
+ end
60
+
61
+ ;; 2. Check if we exceed current memory size
62
+ local.get $new_free
63
+ global.get $arena_max
64
+ i32.gt_u
65
+ if
66
+ ;; Calculate how many additional pages we need to grow
67
+ local.get $new_free
68
+ global.get $arena_max
69
+ i32.sub
70
+ i32.const 65535
71
+ i32.add
72
+ i32.const 65536
73
+ i32.div_u
74
+ local.set $pages_needed
75
+
76
+ ;; Try to grow memory by $pages_needed
77
+ local.get $pages_needed
78
+ memory.grow
79
+ local.set $grow_res
80
+
81
+ ;; If grow returns -1, we are out of memory
82
+ local.get $grow_res
83
+ i32.const -1
84
+ i32.eq
85
+ if
86
+ i32.const 1
87
+ global.set $oom_flag
88
+ local.get $size
89
+ global.set $oom_size
90
+ unreachable
91
+ end
92
+
93
+ ;; Update arena_max: arena_max = arena_max + pages_needed * 65536
94
+ global.get $arena_max
95
+ local.get $pages_needed
96
+ i32.const 65536
97
+ i32.mul
98
+ i32.add
99
+ global.set $arena_max
100
+ end
101
+
102
+ ;; 3. Perform the allocation
103
+ local.get $new_free
104
+ global.set $arena_free
105
+
106
+ local.get $old_free
107
+ )
108
+
109
+ ;; Return a checkpoint that can be restored after a temporary result is consumed.
110
+ (func $arena_mark (export "arena_mark") (result i32)
111
+ global.get $arena_free
112
+ )
113
+
114
+ ;; Bulk-free allocations made after a checkpoint. Memory pages remain available for reuse.
115
+ (func $arena_reset (export "arena_reset") (param $mark i32)
116
+ local.get $mark
117
+ i32.const 1024
118
+ i32.lt_u
119
+ if
120
+ unreachable
121
+ end
122
+
123
+ local.get $mark
124
+ global.get $arena_free
125
+ i32.gt_u
126
+ if
127
+ unreachable
128
+ end
129
+
130
+ local.get $mark
131
+ global.set $arena_free
132
+ )
133
+
134
+ ;; Compaction staging globals
135
+ (global $compact_buf_start (mut i32) (i32.const 0))
136
+ (global $compact_buf_free (mut i32) (i32.const 0))
137
+
138
+ ;; Ensure memory capacity in staging buffer
139
+ (func $ensure_buf_capacity (param $size i32)
140
+ (local $needed i32)
141
+ (local $pages i32)
142
+ (local $grow_res i32)
143
+
144
+ global.get $compact_buf_free
145
+ local.get $size
146
+ i32.add
147
+ local.set $needed
148
+
149
+ ;; Check for 32-bit overflow
150
+ local.get $needed
151
+ global.get $compact_buf_free
152
+ i32.lt_u
153
+ if
154
+ i32.const 1
155
+ global.set $oom_flag
156
+ local.get $size
157
+ global.set $oom_size
158
+ unreachable
159
+ end
160
+
161
+ local.get $needed
162
+ global.get $arena_max
163
+ i32.gt_u
164
+ if
165
+ local.get $needed
166
+ global.get $arena_max
167
+ i32.sub
168
+ i32.const 65535
169
+ i32.add
170
+ i32.const 65536
171
+ i32.div_u
172
+ local.set $pages
173
+
174
+ local.get $pages
175
+ memory.grow
176
+ local.set $grow_res
177
+
178
+ local.get $grow_res
179
+ i32.const -1
180
+ i32.eq
181
+ if
182
+ i32.const 1
183
+ global.set $oom_flag
184
+ local.get $size
185
+ global.set $oom_size
186
+ unreachable
187
+ end
188
+
189
+ global.get $arena_max
190
+ local.get $pages
191
+ i32.const 65536
192
+ i32.mul
193
+ i32.add
194
+ global.set $arena_max
195
+ end
196
+ )
197
+
198
+ ;; Initialize compaction staging buffer at current arena top
199
+ (func $compact_start (export "compact_start")
200
+ global.get $arena_free
201
+ global.set $compact_buf_start
202
+ global.get $arena_free
203
+ global.set $compact_buf_free
204
+ )
205
+
206
+ ;; Compact an object graph reachable from $root down toward $mark
207
+ (func $compact_obj (export "compact_obj") (param $root i32) (param $mark i32) (result i32)
208
+ (local $curr i32)
209
+ (local $first_final i32)
210
+ (local $prev_dest i32)
211
+ (local $dest i32)
212
+ (local $final_ptr i32)
213
+ (local $tag i32)
214
+ (local $payload i32)
215
+ (local $size i32)
216
+ (local $alignedSize i32)
217
+ (local $N i32)
218
+ (local $i i32)
219
+ (local $offsetVal i32)
220
+ (local $fieldPtr i32)
221
+ (local $child_final i32)
222
+
223
+ local.get $root
224
+ local.set $curr
225
+ i32.const 0
226
+ local.set $prev_dest
227
+
228
+ (block $break_chain
229
+ (loop $chain_loop
230
+ ;; 1. Check null / empty
231
+ local.get $curr
232
+ i32.eqz
233
+ if
234
+ local.get $prev_dest
235
+ if
236
+ local.get $prev_dest
237
+ i32.const 0
238
+ i32.store offset=8
239
+ end
240
+ br $break_chain
241
+ end
242
+
243
+ ;; 2. Check if < mark
244
+ local.get $curr
245
+ local.get $mark
246
+ i32.lt_u
247
+ if
248
+ local.get $prev_dest
249
+ if
250
+ local.get $prev_dest
251
+ local.get $curr
252
+ i32.store offset=8
253
+ end
254
+ local.get $first_final
255
+ i32.eqz
256
+ if
257
+ local.get $curr
258
+ local.set $first_final
259
+ end
260
+ br $break_chain
261
+ end
262
+
263
+ ;; 3. Check if forwarded
264
+ local.get $curr
265
+ i32.load offset=0
266
+ local.set $size
267
+
268
+ local.get $size
269
+ i32.const -1
270
+ i32.eq
271
+ if
272
+ local.get $curr
273
+ i32.load offset=4
274
+ local.set $final_ptr
275
+ local.get $prev_dest
276
+ if
277
+ local.get $prev_dest
278
+ local.get $final_ptr
279
+ i32.store offset=8
280
+ end
281
+ local.get $first_final
282
+ i32.eqz
283
+ if
284
+ local.get $final_ptr
285
+ local.set $first_final
286
+ end
287
+ br $break_chain
288
+ end
289
+
290
+ ;; 4. Compute final_ptr = mark + (compact_buf_free - compact_buf_start)
291
+ local.get $mark
292
+ global.get $compact_buf_free
293
+ global.get $compact_buf_start
294
+ i32.sub
295
+ i32.add
296
+ local.set $final_ptr
297
+
298
+ local.get $first_final
299
+ i32.eqz
300
+ if
301
+ local.get $final_ptr
302
+ local.set $first_final
303
+ end
304
+
305
+ ;; If prev_dest != 0, patch its payload to final_ptr
306
+ local.get $prev_dest
307
+ if
308
+ local.get $prev_dest
309
+ local.get $final_ptr
310
+ i32.store offset=8
311
+ end
312
+
313
+ ;; 5. Check if Variant (size == 12)
314
+ local.get $size
315
+ i32.const 12
316
+ i32.eq
317
+ if
318
+ i32.const 16
319
+ call $ensure_buf_capacity
320
+
321
+ local.get $curr
322
+ i32.load offset=4
323
+ local.set $tag
324
+ local.get $curr
325
+ i32.load offset=8
326
+ local.set $payload
327
+
328
+ local.get $curr
329
+ i32.const -1
330
+ i32.store offset=0
331
+ local.get $curr
332
+ local.get $final_ptr
333
+ i32.store offset=4
334
+
335
+ global.get $compact_buf_free
336
+ local.set $dest
337
+ global.get $compact_buf_free
338
+ i32.const 16
339
+ i32.add
340
+ global.set $compact_buf_free
341
+
342
+ local.get $dest
343
+ i32.const 12
344
+ i32.store offset=0
345
+ local.get $dest
346
+ local.get $tag
347
+ i32.store offset=4
348
+
349
+ local.get $dest
350
+ local.set $prev_dest
351
+ local.get $payload
352
+ local.set $curr
353
+ br $chain_loop
354
+ end
355
+
356
+ ;; 6. Product handling (size != 12)
357
+ local.get $size
358
+ i32.const 7
359
+ i32.add
360
+ i32.const -8
361
+ i32.and
362
+ local.set $alignedSize
363
+
364
+ local.get $alignedSize
365
+ call $ensure_buf_capacity
366
+
367
+ local.get $curr
368
+ i32.load offset=4
369
+ local.set $N
370
+
371
+ local.get $curr
372
+ i32.const -1
373
+ i32.store offset=0
374
+ local.get $curr
375
+ local.get $final_ptr
376
+ i32.store offset=4
377
+
378
+ global.get $compact_buf_free
379
+ local.set $dest
380
+ global.get $compact_buf_free
381
+ local.get $alignedSize
382
+ i32.add
383
+ global.set $compact_buf_free
384
+
385
+ local.get $dest
386
+ local.get $size
387
+ i32.store offset=0
388
+ local.get $dest
389
+ local.get $N
390
+ i32.store offset=4
391
+
392
+ i32.const 0
393
+ local.set $i
394
+ (block $break_prod
395
+ (loop $loop_prod
396
+ local.get $i
397
+ local.get $N
398
+ i32.ge_u
399
+ br_if $break_prod
400
+
401
+ local.get $curr
402
+ i32.const 8
403
+ local.get $i
404
+ i32.const 4
405
+ i32.mul
406
+ i32.add
407
+ i32.add
408
+ i32.load
409
+ local.set $offsetVal
410
+
411
+ local.get $dest
412
+ i32.const 8
413
+ local.get $i
414
+ i32.const 4
415
+ i32.mul
416
+ i32.add
417
+ i32.add
418
+ local.get $offsetVal
419
+ i32.store
420
+
421
+ local.get $curr
422
+ local.get $offsetVal
423
+ i32.add
424
+ i32.load
425
+ local.set $fieldPtr
426
+
427
+ local.get $fieldPtr
428
+ local.get $mark
429
+ call $compact_obj
430
+ local.set $child_final
431
+
432
+ local.get $dest
433
+ local.get $offsetVal
434
+ i32.add
435
+ local.get $child_final
436
+ i32.store
437
+
438
+ local.get $i
439
+ i32.const 1
440
+ i32.add
441
+ local.set $i
442
+ br $loop_prod
443
+ )
444
+ )
445
+ br $break_chain
446
+ )
447
+ )
448
+
449
+ local.get $first_final
450
+ )
451
+
452
+ ;; Finalize compaction by copying staging buffer into mark and resetting arena_free
453
+ (func $compact_finish (export "compact_finish") (param $mark i32)
454
+ (local $total_size i32)
455
+ global.get $compact_buf_free
456
+ global.get $compact_buf_start
457
+ i32.sub
458
+ local.set $total_size
459
+
460
+ local.get $total_size
461
+ i32.const 0
462
+ i32.gt_u
463
+ if
464
+ local.get $mark
465
+ global.get $compact_buf_start
466
+ local.get $total_size
467
+ memory.copy
468
+ end
469
+
470
+ local.get $mark
471
+ local.get $total_size
472
+ i32.add
473
+ global.set $arena_free
474
+ )
475
+ )
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+
3
+ import path from "node:path";
4
+ import { spawnSync } from "node:child_process";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
8
+ const node = process.execPath;
9
+ const tests = [
10
+ ["tests/test-wasm.mjs", node, ["tests/test-wasm.mjs"]],
11
+ ["tests/integration.sh", path.join(root, "tests/integration.sh"), []]
12
+ ];
13
+
14
+ function formatDuration(milliseconds) {
15
+ if (milliseconds < 1000) return `${milliseconds.toFixed(0)} ms`;
16
+ return `${(milliseconds / 1000).toFixed(2)} s`;
17
+ }
18
+
19
+ const suiteStarted = performance.now();
20
+ for (const [name, command, args] of tests) {
21
+ console.log(`\n==> ${name}`);
22
+ const started = performance.now();
23
+ const result = spawnSync(command, args, {
24
+ cwd: root,
25
+ stdio: "inherit"
26
+ });
27
+ const duration = formatDuration(performance.now() - started);
28
+
29
+ if (result.error) {
30
+ console.error(`<== ${name} FAILED (${duration})`);
31
+ console.error(result.error.message);
32
+ process.exit(1);
33
+ }
34
+ if (result.status !== 0) {
35
+ console.error(`<== ${name} FAILED (${duration})`);
36
+ process.exit(result.status ?? 1);
37
+ }
38
+ console.log(`<== ${name} passed (${duration})`);
39
+ }
40
+
41
+ console.log(`\nAll tests passed (${formatDuration(performance.now() - suiteStarted)})`);
@@ -0,0 +1,133 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ import { decodeObject, loadLibrary } from "@fraczak/k/backend-api.mjs";
5
+ import {
6
+ compileWasmArtifact,
7
+ compileWasmArtifactFromKVM,
8
+ compileWasmArtifactFromObject
9
+ } from "./wasm.mjs";
10
+
11
+ function readAll(stream) {
12
+ return new Promise((resolve, reject) => {
13
+ const chunks = [];
14
+ stream.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
15
+ stream.on("end", () => resolve(Buffer.concat(chunks)));
16
+ stream.on("error", reject);
17
+ });
18
+ }
19
+
20
+ function parseCompileOptions(args) {
21
+ const libraries = [];
22
+ const exportSpecs = [];
23
+ let loadedLibrary = false;
24
+
25
+ while (args.length > 0) {
26
+ if (args[0] === "--") {
27
+ args.shift();
28
+ break;
29
+ }
30
+ if (args[0] === "--lib") {
31
+ if (loadedLibrary) throw new Error("--lib may only be specified once");
32
+ args.shift();
33
+ const libPath = args.shift();
34
+ if (!libPath) throw new Error("--lib requires a file argument");
35
+ libraries.push(loadLibrary(decodeObject(fs.readFileSync(libPath))));
36
+ loadedLibrary = true;
37
+ } else if (args[0] === "--export") {
38
+ args.shift();
39
+ const spec = args.shift();
40
+ if (!spec) throw new Error("--export requires a spec argument (name or libname:localname)");
41
+ exportSpecs.push(spec);
42
+ } else if (args[0].startsWith("--")) {
43
+ throw new Error(`Unknown option: ${args[0]}`);
44
+ } else {
45
+ break;
46
+ }
47
+ }
48
+
49
+ return { libraries, exportSpecs };
50
+ }
51
+
52
+ function fileInputType(filePath) {
53
+ const ext = path.extname(filePath).toLowerCase();
54
+ if (ext === ".ko") return "ko";
55
+ if (ext === ".kvm") return "kvm";
56
+ if (ext === ".klib") return "klib";
57
+ return "source-file";
58
+ }
59
+
60
+ function resolveProgramInput(args, { allowStdinSource = false } = {}) {
61
+ const inputArg = args.shift() ?? null;
62
+ if (inputArg == null) {
63
+ if (!allowStdinSource) throw new Error("Missing script argument");
64
+ return { kind: "stdin-source", sourceName: "<stdin>" };
65
+ }
66
+
67
+ const ext = path.extname(inputArg).toLowerCase();
68
+ if (fs.existsSync(inputArg)) {
69
+ const kind = fileInputType(inputArg);
70
+ if (kind === "klib") {
71
+ throw new Error("Cannot compile a .klib library to WebAssembly without a main relation; load it with --lib.");
72
+ }
73
+ return { kind, path: inputArg, sourceName: inputArg };
74
+ }
75
+
76
+ if ([".k", ".ko", ".kvm", ".klib", ".wasm"].includes(ext)) {
77
+ throw new Error(`Input file not found: ${inputArg}`);
78
+ }
79
+
80
+ return { kind: "inline-source", source: inputArg, sourceName: "<inline>" };
81
+ }
82
+
83
+ async function compileProgramInput(
84
+ input,
85
+ { libraries = [], exportSpecs = [], stdin = null, inputEnvelopePattern = null } = {}
86
+ ) {
87
+ if (input.kind === "inline-source") {
88
+ return compileWasmArtifact(input.source, {
89
+ libraries,
90
+ exports: exportSpecs,
91
+ source: input.sourceName,
92
+ inputEnvelopePattern
93
+ });
94
+ }
95
+
96
+ if (input.kind === "stdin-source") {
97
+ if (!stdin) throw new Error("stdin source requested without a stdin stream");
98
+ return compileWasmArtifact((await readAll(stdin)).toString("utf8"), {
99
+ libraries,
100
+ exports: exportSpecs,
101
+ source: input.sourceName,
102
+ inputEnvelopePattern
103
+ });
104
+ }
105
+
106
+ if (input.kind === "source-file") {
107
+ return compileWasmArtifact(fs.readFileSync(input.path, "utf8"), {
108
+ libraries,
109
+ exports: exportSpecs,
110
+ source: input.sourceName,
111
+ inputEnvelopePattern
112
+ });
113
+ }
114
+
115
+ if (input.kind === "ko") {
116
+ return compileWasmArtifactFromObject(decodeObject(fs.readFileSync(input.path)), {
117
+ inputEnvelopePattern
118
+ });
119
+ }
120
+
121
+ if (input.kind === "kvm") {
122
+ return compileWasmArtifactFromKVM(JSON.parse(fs.readFileSync(input.path, "utf8")));
123
+ }
124
+
125
+ throw new Error(`Unsupported input kind: ${input.kind}`);
126
+ }
127
+
128
+ export {
129
+ compileProgramInput,
130
+ parseCompileOptions,
131
+ readAll,
132
+ resolveProgramInput
133
+ };