@fraczak/k 6.6.0 → 6.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DOCS/REPL.md +23 -36
- package/TODO.md +112 -0
- package/backends/arm64/README.md +0 -1
- package/backends/arm64/bin/k-arm64-compile.mjs +0 -8
- package/backends/llvm/README.md +13 -11
- package/backends/llvm/bin/k-llvm-build.mjs +40 -38
- package/backends/llvm/bin/k-llvm-compile.mjs +42 -32
- package/backends/llvm/src/cli.mjs +153 -0
- package/backends/llvm/src/executable.mjs +1 -1
- package/backends/llvm/src/kvm2llvm.mjs +11 -1
- package/backends/llvm/tests/integration.sh +18 -22
- package/backends/wasm/bin/k-wasm-compile.mjs +19 -4
- package/browser/repl-browser.mjs +146 -94
- package/browser/vfs-data.mjs +2 -0
- package/package.json +1 -1
- package/repl-codecs.mjs +26 -5
- package/repl.mjs +214 -148
- package/scripts/build-repl-html.mjs +213 -72
- package/tests/test-repl-html.mjs +84 -6
- package/tests/test-repl.mjs +90 -40
package/DOCS/REPL.md
CHANGED
|
@@ -33,29 +33,23 @@ complete.
|
|
|
33
33
|
| Command | Meaning |
|
|
34
34
|
| --- | --- |
|
|
35
35
|
| `:help` | Show command summary |
|
|
36
|
-
| `:type name = <...>` | Define a type alias |
|
|
37
36
|
| `:type name` | Show the canonical definition of a type |
|
|
38
37
|
| `:code name` | Alias for `:C name` |
|
|
39
|
-
| `:rel name = expr` | Define a relation alias |
|
|
40
|
-
| `:def name = expr` | Alias for `:rel` |
|
|
41
38
|
| `:run expr` | Evaluate `expr` on the current value |
|
|
42
39
|
| `:eval expr` | Alias for `:run` |
|
|
43
40
|
| `:time expr` | Evaluate `expr` and report compilation and execution time |
|
|
44
|
-
| `:timing [on\|off]` | Toggle compilation and execution timing reporting for all evaluations |
|
|
45
41
|
| `:t name` | Show relation input/output filters |
|
|
46
42
|
| `:d name` | Show relation definition |
|
|
47
43
|
| `:C name` | Show canonical code definition |
|
|
48
44
|
| `:codes` | List type aliases |
|
|
49
45
|
| `:rels` | List relation aliases |
|
|
50
46
|
| `: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
47
|
| `:codec unload name` | Unload a registered codec |
|
|
53
48
|
| `:codec list` | List loaded REPL codecs (alias: `:codecs`) |
|
|
54
|
-
| `:input
|
|
49
|
+
| `:input [<filter=(...)> [codec]]` | Read next input line using specified codec (opens dialog in browser) |
|
|
55
50
|
| `:load [--no-alias] file` | Load `.k` source or `.klib` into the current state |
|
|
56
51
|
| `:klib file` | Export the active relation closure as a `.klib` library |
|
|
57
52
|
| `:ko file expr` | Export a `.ko` executable with `expr` as main |
|
|
58
|
-
| `:val` | Print current value and JSON form |
|
|
59
53
|
| `:reset` | Reset interpreter state |
|
|
60
54
|
| `:quit` / `:exit` | Exit |
|
|
61
55
|
|
|
@@ -143,8 +137,8 @@ Tab completion covers:
|
|
|
143
137
|
Type aliases also complete in `$name` position inside raw k input.
|
|
144
138
|
|
|
145
139
|
For codec commands, completion covers `:codec load`, `:codec list`, file paths
|
|
146
|
-
after `:codec load`, type names after `:input`, and loaded codec names
|
|
147
|
-
after the input type.
|
|
140
|
+
after `:codec load`, type names or codec names after `:input`, and loaded codec names
|
|
141
|
+
after the input pattern or type.
|
|
148
142
|
|
|
149
143
|
## Loading
|
|
150
144
|
|
|
@@ -193,44 +187,39 @@ property-list pattern that can be canonicalized to a code hash, and that hash is
|
|
|
193
187
|
recalculated by the REPL. A universal codec exports `universal = true` instead
|
|
194
188
|
of `codes` or `patterns`.
|
|
195
189
|
|
|
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
190
|
|
|
205
191
|
### `:codec unload name`
|
|
206
192
|
|
|
207
193
|
Unloads a previously registered codec by name.
|
|
208
194
|
|
|
209
|
-
### `:input
|
|
195
|
+
### `:input [<filter=(...)> [codec]]`
|
|
210
196
|
|
|
211
|
-
Resolves
|
|
212
|
-
consumes the next line verbatim as codec input. `type` may be a type alias, a
|
|
213
|
-
canonical code hash, or an inline type expression such as
|
|
214
|
-
`<{} true, {} false>`. The parsed value is validated against that type before
|
|
215
|
-
becoming the current value.
|
|
197
|
+
Resolves a pattern expression (e.g. `? {string a, float64 n}`, `? (...)`, `? <{} true, {} false>`), a type alias, or a canonical code hash, selects the registered codec, and consumes the next line verbatim as codec input.
|
|
216
198
|
|
|
217
|
-
|
|
199
|
+
If only a universal codec is specified (e.g. `:input json`), no pre-declared type or pattern is required; input is parsed directly and derives its pattern from the input payload.
|
|
218
200
|
|
|
219
|
-
|
|
201
|
+
When a pattern expression or type is provided, the parsed value is validated and constrained against that pattern before becoming the current value:
|
|
220
202
|
|
|
221
|
-
|
|
222
|
-
|
|
203
|
+
```text
|
|
204
|
+
> :input ? {string a, float64 n} json
|
|
205
|
+
input ? {string a, float64 n} using json: enter value text
|
|
206
|
+
json> {"a": "Woj", "n": 123}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Timing and Profiling
|
|
210
|
+
|
|
211
|
+
Timing reporting is enabled by default for all evaluations, reporting elapsed time
|
|
212
|
+
broken down into compilation (type derivation + WebAssembly lowering/compilation) and runtime execution:
|
|
223
213
|
|
|
224
214
|
```text
|
|
225
|
-
>
|
|
215
|
+
> {10 int x, 5 int y} plus
|
|
226
216
|
{}|_|1|1|1|1|+ ?<{} _, ...>
|
|
227
217
|
/* comp: 12.4ms, exec: 0.8ms */
|
|
228
218
|
```
|
|
229
219
|
|
|
230
|
-
### `:
|
|
220
|
+
### `:time expr`
|
|
231
221
|
|
|
232
|
-
|
|
233
|
-
the session.
|
|
222
|
+
Evaluates `expr` with explicit timing and records performance metrics in session state.
|
|
234
223
|
|
|
235
224
|
## Web REPL (Studio)
|
|
236
225
|
|
|
@@ -279,11 +268,9 @@ Evaluated values print in k syntax together with the inferred envelope:
|
|
|
279
268
|
## Example Session
|
|
280
269
|
|
|
281
270
|
```text
|
|
282
|
-
>
|
|
283
|
-
|
|
284
|
-
>
|
|
285
|
-
inc = @...
|
|
286
|
-
> {} |0
|
|
271
|
+
> $ nat = < {} 0, nat +1 >;
|
|
272
|
+
> inc = | +1;
|
|
273
|
+
> {} | 0
|
|
287
274
|
{}|0 ?<{} 0, ...>
|
|
288
275
|
> :t inc
|
|
289
276
|
inc : ?X0 --> ?<X0 +1, ...> (@...)
|
package/TODO.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Web REPL Improvements & Conceptual Cleanup Plan
|
|
2
|
+
|
|
3
|
+
This document details the issues, conceptual improvements, and completed enhancements for the `k` Web REPL (`browser/repl-browser.mjs`, `scripts/build-repl-html.mjs`, and `repl.html`).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. General Branding & Visual Cleanup
|
|
8
|
+
|
|
9
|
+
### Removal of `λ` (Lambda) Symbol
|
|
10
|
+
- [x] Remove `<span class="brand-lambda">λ</span>` from the navbar in `scripts/build-repl-html.mjs`.
|
|
11
|
+
- [x] Remove the `.brand-lambda` CSS class.
|
|
12
|
+
- [x] Update welcome banner in `browser/repl-browser.mjs` to `k interactive repl`.
|
|
13
|
+
- [x] Replace `λ` in string codec sample inputs with ASCII/Unicode text samples (e.g. `"abc"`).
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 2. Help Modal (`? Help` / `:help`) Overhaul
|
|
18
|
+
|
|
19
|
+
### Language Overview & Grammar Categorization
|
|
20
|
+
- [x] **Language Overview**: Short, positive, accessible description: `k` is a concise language of types and relations (functions) over tree-like (JSON-like) documents.
|
|
21
|
+
- [x] **Content-Addressed Identity**: Functions and types are identified by their canonical content hash (`@...`) derived directly from their structure; local names are just temporary aliases used for recursion and readability.
|
|
22
|
+
- [x] **Three Clean Grammar Categories**:
|
|
23
|
+
1. **Definitions (Local Aliases)**:
|
|
24
|
+
- `name = relExpr;` — Relation alias (e.g. `swap = { . y x, . x y };`).
|
|
25
|
+
- `$ name = typeExpr;` — Type alias (e.g. `$ bool = < {} true, {} false >;`).
|
|
26
|
+
2. **Type Expressions (`typeExpr`)**: Schemas describing tree-like documents:
|
|
27
|
+
- `{ Type_1 label_1, ..., Type_k label_k }` — Product type of arity $k$ (labeled records, e.g. `{float64 x, string n}`; special case: `{}` is the 0-ary product).
|
|
28
|
+
- `< Type_1 tag_1, ..., Type_k tag_k >` — Union type of arity $k$ (tagged sum of variants, e.g. `<int ok, string err>`).
|
|
29
|
+
- `name` / `@hash` — Type reference.
|
|
30
|
+
3. **Relation Expressions (`relExpr`)**: Functions transforming an input document to an output document:
|
|
31
|
+
- `{ rel_1 label_1, ..., rel_k label_k }` — Product of arity $k$ (evaluates relations into record fields; special case: `{}` evaluates 0 relations, producing empty record `{}`).
|
|
32
|
+
- `< rel_1, ..., rel_k >` — Union / ordered choice of arity $k$ (evaluates relations in order until one succeeds).
|
|
33
|
+
- `( rel_1 ... rel_k )` — Composition of arity $k$ (sequentially composes relations; special case: `()` is the 0-ary composition denoting identity; parentheses can be omitted when non-empty: `f g`).
|
|
34
|
+
- `. label` — Field projection (extracts field `label`).
|
|
35
|
+
- `/ tag` — Variant branch projection (extracts payload of variant `tag`).
|
|
36
|
+
- `| tag` — Variant constructor (wraps document into variant `tag`).
|
|
37
|
+
- `$ typeExpr` — Type constraint (asserts input matches schema; compile-time Type Error on mismatch).
|
|
38
|
+
- `name` / `@hash` — Relation reference.
|
|
39
|
+
- [x] **Simplified Intro**:
|
|
40
|
+
- Made arbitrary arity explicit across products `{...}`, unions `<...>`, and compositions `(...)`; explained `{}` and `()` as the natural 0-ary special cases; omitted the pattern/filter expressions table from the introductory reference.
|
|
41
|
+
- [x] **Replaced Misleading Expressions & Snippets**:
|
|
42
|
+
- Removed phantom concepts (`10` as literal, "bit-path", `{10 int x, 5 int y} plus` in default state).
|
|
43
|
+
- Added self-contained snippets (`{} | ok`, `not = < / true | false, / false | true >;`, `$ bool = < {} true, {} false >;`, `not = $ bool < / true | false, {} | true > $ bool;`, `swap = { . y x, . x y };`).
|
|
44
|
+
- [x] **Command Reference Table**:
|
|
45
|
+
- Added `:time <expr>`.
|
|
46
|
+
- Removed obsolete commands: `:rel <name> = expr`, `:val`, `:timing [on|off]`, `:codec define n t b`.
|
|
47
|
+
- Updated `:type <name>` to purely inspect and display type definitions (type definition is native via `$ name = typeExpr;`).
|
|
48
|
+
- Timing is now always enabled by default across all evaluations.
|
|
49
|
+
- Updated `:input` documentation to note the interactive browser dialog.
|
|
50
|
+
- Clarified `:codes` (type aliases/hashes) and `:rels` (relation aliases).
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 3. Codecs Modal Overhaul
|
|
55
|
+
|
|
56
|
+
### Concept Correction: External Format Adapters
|
|
57
|
+
- [x] Reframed codecs as format adapters translating external text to/from $k$ values defined as pairs `(filter, tree)`.
|
|
58
|
+
- [x] **Type-Specific Codecs**:
|
|
59
|
+
- `int`: Converts decimal integers to/from `$ int = < bits '+', bits '-' >`.
|
|
60
|
+
- `ieee`: Converts decimal floats to/from `$ float64` records (`sign`, `exponent`, `fraction`).
|
|
61
|
+
- `utf8`: Converts text to/from `$ string` (aliased to `$ utf8`), a list of Unicode scalar values (`$ unicode`) partitioned by Unicode planes.
|
|
62
|
+
- `unit`: Converts to/from `{}`.
|
|
63
|
+
- [x] **Parameterized Codecs**:
|
|
64
|
+
- `json`: JSON text is untyped; deserializing JSON requires a target $k$ type schema parameter (e.g. `:input {float64 x, string n} json`).
|
|
65
|
+
- [x] **Custom Codec Studio**:
|
|
66
|
+
- Updated explanation to emphasize pairs `(filter, tree)`.
|
|
67
|
+
- Fixed `yn` preset to provide self-contained type definition `$ bool = < {} true, {} false >;`.
|
|
68
|
+
- Fixed `blank` preset with proper Value payload formatting.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 4. 'Input' Modal Overhaul
|
|
73
|
+
|
|
74
|
+
- [x] **Parameterized Codec Support**:
|
|
75
|
+
- Converted "Target Type" control into an editable combobox / text input with datalist autocomplete for known aliases, while allowing arbitrary composite type expressions (`{float64 x, string n}`, `<int ok, string err>`).
|
|
76
|
+
- Integrated `resolveInputTypeHash(state, rawType)` into live validation and modal submit.
|
|
77
|
+
- Marked `json` as a Parameterized Codec requiring a target type schema.
|
|
78
|
+
- Added composite quick samples demonstrating type + JSON payload pairs (e.g. `{float64 x, string n}` with `{"x":12, "n":"Woj"}`).
|
|
79
|
+
- Preserved CLI-specified type expressions when opening via `:input <type> [codec]`.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 5. Welcome Banner
|
|
84
|
+
|
|
85
|
+
- [x] Shortened initial welcome message to just the title line: `k interactive repl`.
|
|
86
|
+
- [x] Removed secondary description and quick link lists to keep the terminal prompt clean and uncluttered.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 6. Curated VFS & Navbar Examples Dropdown
|
|
91
|
+
|
|
92
|
+
- [x] Added `poly.k` to `verifiedExamples` and `#example-select`.
|
|
93
|
+
- [x] Structured Navbar Examples dropdown into self-contained basic expressions vs. library-dependent workflows.
|
|
94
|
+
- [x] Removed `:val` from example dropdown list.
|
|
95
|
+
- [x] Fixed `() ()` option display text.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 7. Responsive Navbar & Obsolete Command Removal
|
|
100
|
+
|
|
101
|
+
- [x] **Responsive Navbar on Narrow Screens**:
|
|
102
|
+
- Changed `.navbar` from fixed `height: 48px;` to `min-height: 48px; height: auto; flex-wrap: wrap; padding: 6px 16px; gap: 8px 12px;`.
|
|
103
|
+
- Styled `.nav-right` with `flex-wrap: wrap; justify-content: flex-end; min-width: 0;` so controls wrap smoothly without overflowing or clipping buttons (such as `? Help`).
|
|
104
|
+
- Added comprehensive responsive media query for narrow screens ($\le 768\text{px}$) with full width wrapping and adaptable control inputs.
|
|
105
|
+
- Verified via headless Chromium CDP automated tests that `#btn-help` is completely visible and interactable at narrow viewport widths (e.g. 600px).
|
|
106
|
+
- [x] **Removed Obsolete Commands**:
|
|
107
|
+
- Removed `:rel <name> = expr` and `:def` (relations are defined using native syntax `name = expr;`).
|
|
108
|
+
- Removed `:type <name> = <...>` definition syntax from `:type` (types are defined using native syntax `$ name = typeExpr;`; `:type <name>` remains for inspecting type definitions).
|
|
109
|
+
- Removed `:val` completely.
|
|
110
|
+
- Removed `:timing [on|off]` (timing reporting is now permanently enabled by default for all evaluations; `:time <expr>` remains for explicit timing).
|
|
111
|
+
- Removed `:codec define n t b` (custom codecs are created using the browser Custom Codec Studio UI or loaded from modules via `:codec load`).
|
|
112
|
+
|
package/backends/arm64/README.md
CHANGED
|
@@ -78,7 +78,6 @@ All tools accept `--help`.
|
|
|
78
78
|
|
|
79
79
|
- `-S, --assembly`: Emit GNU ARM64 assembly text (`.s`) instead of an ELF binary.
|
|
80
80
|
- `-o, --output <file>`: Specify the output file path.
|
|
81
|
-
- `--entry <name>`: Specify the entry relation (defaults to `__main__`).
|
|
82
81
|
- `--lib <file>`: Load one `.klib` or `.k` library dependency.
|
|
83
82
|
- `--export <spec>`: Export library symbols into source scope (`name` or `libname:localname`).
|
|
84
83
|
- `--json`: Format output as JSON instead of binary wire format.
|
|
@@ -22,7 +22,6 @@ function usage(stream = console.error) {
|
|
|
22
22
|
stream("Options:");
|
|
23
23
|
stream(" -S, --assembly Emit GNU ARM64 assembly (.s) instead of an executable binary.");
|
|
24
24
|
stream(" -o, --output Specify output file path explicitly.");
|
|
25
|
-
stream(" --entry name Specify entry relation name.");
|
|
26
25
|
stream(" --lib file Load one .klib dependency before compiling.");
|
|
27
26
|
stream(" --export spec Export a library alias into source scope. May be repeated.");
|
|
28
27
|
stream(" spec is 'name' or 'libname:localname'.");
|
|
@@ -38,8 +37,6 @@ try {
|
|
|
38
37
|
|
|
39
38
|
let emitAssembly = false;
|
|
40
39
|
let explicitOutput = null;
|
|
41
|
-
let entry = null;
|
|
42
|
-
|
|
43
40
|
// Extract ARM64-specific flags
|
|
44
41
|
const remainingArgs = [];
|
|
45
42
|
while (args.length > 0) {
|
|
@@ -51,10 +48,6 @@ try {
|
|
|
51
48
|
args.shift();
|
|
52
49
|
explicitOutput = args.shift();
|
|
53
50
|
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
51
|
} else {
|
|
59
52
|
remainingArgs.push(args.shift());
|
|
60
53
|
}
|
|
@@ -71,7 +64,6 @@ try {
|
|
|
71
64
|
libraries,
|
|
72
65
|
exportSpecs,
|
|
73
66
|
stdin,
|
|
74
|
-
entry,
|
|
75
67
|
emit: emitAssembly ? "assembly" : null,
|
|
76
68
|
outputPath: (!emitAssembly && outputPath) ? outputPath : null
|
|
77
69
|
});
|
package/backends/llvm/README.md
CHANGED
|
@@ -23,7 +23,7 @@ backend from `backends/llvm`:
|
|
|
23
23
|
npm install
|
|
24
24
|
cd backends/llvm
|
|
25
25
|
node ../../objects/compile.mjs '()' /tmp/id.ko
|
|
26
|
-
node ./bin/k-llvm-compile.mjs
|
|
26
|
+
node ./bin/k-llvm-compile.mjs /tmp/id.ko /tmp/id.ll
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
The generated `.ll` embeds the envelope-specialized KIR-P contract as module
|
|
@@ -44,24 +44,26 @@ status in `k_result`. These operations can compose through KIR `comp`.
|
|
|
44
44
|
## CLI
|
|
45
45
|
|
|
46
46
|
```sh
|
|
47
|
-
k-llvm-build [options]
|
|
48
|
-
k-llvm-compile [options]
|
|
47
|
+
k-llvm-build [options] [source-snippet | input-file [output-exe]]
|
|
48
|
+
k-llvm-compile [options] [source-snippet | input-file [output.ll]]
|
|
49
49
|
k-llvm-jit [options] object.ko
|
|
50
50
|
k-llvm-run [options] object.ko [input.kv]
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
Options:
|
|
54
54
|
|
|
55
|
-
-
|
|
56
|
-
|
|
57
|
-
- `--
|
|
58
|
-
|
|
59
|
-
- `--
|
|
60
|
-
|
|
55
|
+
- `-o, --output path`: specify output file path explicitly.
|
|
56
|
+
- `--lib file`: load one `.klib` or `.k` dependency before compiling.
|
|
57
|
+
- `--export spec`: export a library alias into source scope (`name` or `libname:localname`). May be repeated.
|
|
58
|
+
- `--input-pattern json-or-file`: for `k-llvm-run`, KIR property-list input pattern.
|
|
59
|
+
- `--retype rel`: for `k-llvm-run`, relation to specialize (defaults to object main).
|
|
60
|
+
- `--expect value-or-file`: for `k-llvm-run`, compare the output value against expected value text.
|
|
61
61
|
- `-h`, `--help`: show usage.
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
The compile commands follow the unified k CLI input convention: pass inline
|
|
64
|
+
source, an existing `.k` source file, or a `.ko`/`.klib` object. Reads UTF-8
|
|
65
|
+
source from stdin when input is omitted. Output paths can be specified as a
|
|
66
|
+
positional argument or explicitly with `-o, --output`.
|
|
65
67
|
Without `--expect`, `k-llvm-run` prints the result value as compact JSON.
|
|
66
68
|
`k-llvm-build` emits a native executable that reads and writes the binary
|
|
67
69
|
k pattern+value envelope used by `codecs/k-parse.mjs` and `codecs/k-print.mjs`.
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
|
|
3
|
+
import { argv, exit, stdin } from "node:process";
|
|
4
|
+
import {
|
|
5
|
+
compileProgramInputToObject,
|
|
6
|
+
parseCompileOptions,
|
|
7
|
+
resolveProgramInput
|
|
8
|
+
} from "../src/cli.mjs";
|
|
6
9
|
import { compileObjectToExecutable } from "../src/executable.mjs";
|
|
7
10
|
|
|
8
11
|
function usage(stream = console.error) {
|
|
9
12
|
const prog = argv[1] || "k-llvm-build.mjs";
|
|
10
|
-
stream(`Usage: node ${prog} [options]
|
|
11
|
-
stream("Compile
|
|
13
|
+
stream(`Usage: node ${prog} [options] [source-snippet | input-file [output-exe]]`);
|
|
14
|
+
stream("Compile k source, .ko, or .klib input into a native executable.");
|
|
15
|
+
stream("");
|
|
16
|
+
stream("Arguments:");
|
|
17
|
+
stream(" source-snippet Inline k source, in the same style as k.mjs.");
|
|
18
|
+
stream(" input-file Source .k, .ko, or .klib file. Reads UTF-8 source from stdin when omitted.");
|
|
19
|
+
stream(" output-exe Output executable path.");
|
|
12
20
|
stream("");
|
|
13
21
|
stream("The executable reads a binary k pattern+value envelope from stdin and");
|
|
14
22
|
stream("writes a binary k pattern+value envelope to stdout.");
|
|
@@ -16,18 +24,11 @@ function usage(stream = console.error) {
|
|
|
16
24
|
stream("stdout is encoded with the compiled output pattern.");
|
|
17
25
|
stream("");
|
|
18
26
|
stream("Options:");
|
|
19
|
-
stream(" --
|
|
20
|
-
stream(" --
|
|
21
|
-
stream("
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
function readMaybeFile(textOrPath) {
|
|
25
|
-
return fs.existsSync(textOrPath) ? fs.readFileSync(textOrPath, "utf8") : textOrPath;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function readPattern(inputPattern) {
|
|
29
|
-
if (inputPattern == null) return null;
|
|
30
|
-
return JSON.parse(readMaybeFile(inputPattern));
|
|
27
|
+
stream(" -o, --output path Specify output file path explicitly.");
|
|
28
|
+
stream(" --lib file Load one .klib dependency before compiling.");
|
|
29
|
+
stream(" --export spec Export a library alias into source scope. May be repeated.");
|
|
30
|
+
stream(" spec is 'name' or 'libname:localname'.");
|
|
31
|
+
stream(" -h, --help Show this help.");
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
try {
|
|
@@ -37,33 +38,34 @@ try {
|
|
|
37
38
|
exit(0);
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
let
|
|
41
|
-
|
|
42
|
-
while (args.length > 0
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
inputPattern = args.shift();
|
|
49
|
-
if (!inputPattern) throw new Error("--input-pattern requires JSON or a file path");
|
|
41
|
+
let explicitOutput = null;
|
|
42
|
+
const remainingArgs = [];
|
|
43
|
+
while (args.length > 0) {
|
|
44
|
+
const arg = args[0];
|
|
45
|
+
if (arg === "-o" || arg === "--output") {
|
|
46
|
+
args.shift();
|
|
47
|
+
explicitOutput = args.shift();
|
|
48
|
+
if (!explicitOutput) throw new Error("-o/--output requires a file argument");
|
|
50
49
|
} else {
|
|
51
|
-
|
|
50
|
+
remainingArgs.push(args.shift());
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
53
|
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
const { libraries, exportSpecs } = parseCompileOptions(remainingArgs);
|
|
55
|
+
const input = resolveProgramInput(remainingArgs, { allowStdinSource: true });
|
|
56
|
+
const positionalOutput = remainingArgs.shift();
|
|
57
|
+
if (remainingArgs.length > 0) throw new Error("Too many arguments");
|
|
58
|
+
|
|
59
|
+
const outputPath = explicitOutput || positionalOutput || null;
|
|
60
|
+
if (outputPath == null) throw new Error("Output executable path is required (pass output-exe or -o/--output)");
|
|
61
61
|
|
|
62
|
-
const object =
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
const object = await compileProgramInputToObject(input, {
|
|
63
|
+
libraries,
|
|
64
|
+
exportSpecs,
|
|
65
|
+
stdin
|
|
66
66
|
});
|
|
67
|
+
|
|
68
|
+
compileObjectToExecutable(object, outputPath);
|
|
67
69
|
} catch (error) {
|
|
68
70
|
console.error(error.stack || error.message || String(error));
|
|
69
71
|
usage();
|
|
@@ -2,29 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import { argv, exit, stdin, stdout } from "node:process";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
compileProgramInputToObject,
|
|
7
|
+
parseCompileOptions,
|
|
8
|
+
resolveProgramInput
|
|
9
|
+
} from "../src/cli.mjs";
|
|
10
|
+
import { compileObjectToLLVM } from "../src/llvm.mjs";
|
|
11
|
+
import { inputPatternForObjectRelation } from "../src/executable.mjs";
|
|
6
12
|
|
|
7
13
|
function usage(stream = console.error) {
|
|
8
14
|
const prog = argv[1] || "k-llvm-compile.mjs";
|
|
9
|
-
stream(`Usage: node ${prog} [options]
|
|
15
|
+
stream(`Usage: node ${prog} [options] [source-snippet | input-file [output.ll]]`);
|
|
10
16
|
stream("Compile a k .ko/.klib object into prototype LLVM IR.");
|
|
11
17
|
stream("");
|
|
12
18
|
stream("Arguments:");
|
|
13
|
-
stream("
|
|
19
|
+
stream(" source-snippet Inline k source, in the same style as k.mjs.");
|
|
20
|
+
stream(" input-file Source .k, .ko, or .klib file. Reads UTF-8 source from stdin when omitted.");
|
|
14
21
|
stream(" output.ll Output LLVM IR path. Writes to stdout when omitted.");
|
|
15
22
|
stream("");
|
|
16
23
|
stream("Options:");
|
|
17
|
-
stream(" --
|
|
18
|
-
stream(" --
|
|
19
|
-
stream("
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
async function readStdinBytes() {
|
|
23
|
-
const chunks = [];
|
|
24
|
-
for await (const chunk of stdin) {
|
|
25
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
26
|
-
}
|
|
27
|
-
return Buffer.concat(chunks);
|
|
24
|
+
stream(" -o, --output path Specify output file path explicitly.");
|
|
25
|
+
stream(" --lib file Load one .klib dependency before compiling.");
|
|
26
|
+
stream(" --export spec Export a library alias into source scope. May be repeated.");
|
|
27
|
+
stream(" spec is 'name' or 'libname:localname'.");
|
|
28
|
+
stream(" -h, --help Show this help.");
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
try {
|
|
@@ -34,32 +35,41 @@ try {
|
|
|
34
35
|
exit(0);
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
let
|
|
38
|
-
|
|
39
|
-
while (args.length > 0
|
|
40
|
-
const
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
inputPattern = args.shift();
|
|
46
|
-
if (!inputPattern) throw new Error("--input-pattern requires JSON or a file path");
|
|
38
|
+
let explicitOutput = null;
|
|
39
|
+
const remainingArgs = [];
|
|
40
|
+
while (args.length > 0) {
|
|
41
|
+
const arg = args[0];
|
|
42
|
+
if (arg === "-o" || arg === "--output") {
|
|
43
|
+
args.shift();
|
|
44
|
+
explicitOutput = args.shift();
|
|
45
|
+
if (!explicitOutput) throw new Error("-o/--output requires a file argument");
|
|
47
46
|
} else {
|
|
48
|
-
|
|
47
|
+
remainingArgs.push(args.shift());
|
|
49
48
|
}
|
|
50
49
|
}
|
|
51
|
-
if (inputPattern == null) throw new Error("--input-pattern is required");
|
|
52
50
|
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
|
|
51
|
+
const { libraries, exportSpecs } = parseCompileOptions(remainingArgs);
|
|
52
|
+
const input = resolveProgramInput(remainingArgs, { allowStdinSource: true });
|
|
53
|
+
const positionalOutput = remainingArgs.shift();
|
|
54
|
+
if (remainingArgs.length > 0) throw new Error("Too many arguments");
|
|
55
|
+
|
|
56
|
+
const outputPath = explicitOutput || positionalOutput || null;
|
|
57
|
+
|
|
58
|
+
const object = await compileProgramInputToObject(input, {
|
|
59
|
+
libraries,
|
|
60
|
+
exportSpecs,
|
|
61
|
+
stdin
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const { llvm } = compileObjectToLLVM(object, {
|
|
65
|
+
relation: object.main,
|
|
66
|
+
inputPattern: inputPatternForObjectRelation(object, object.main)
|
|
67
|
+
});
|
|
56
68
|
|
|
57
|
-
const input = inputPath == null ? await readStdinBytes() : fs.readFileSync(inputPath);
|
|
58
|
-
const { llvm } = compileBufferToLLVM(input, { relation, inputPattern });
|
|
59
69
|
if (outputPath == null) {
|
|
60
70
|
stdout.write(llvm);
|
|
61
71
|
} else {
|
|
62
|
-
fs.writeFileSync(outputPath, llvm);
|
|
72
|
+
fs.writeFileSync(outputPath, llvm, "utf8");
|
|
63
73
|
}
|
|
64
74
|
} catch (error) {
|
|
65
75
|
console.error(error.stack || error.message || String(error));
|