@amritk/nish 0.10.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.
@@ -0,0 +1,468 @@
1
+ # Installing nish
2
+
3
+ `nish` compiles a static subset of TypeScript to LLVM IR and, with
4
+ `--link`, to a native binary. The compiler is itself a native binary, written
5
+ in Nish (`self/`), and needs nothing to run; the `--link` step (and anything
6
+ else that turns `.ll` into machine code) needs an LLVM toolchain.
7
+
8
+ ## 1. Prerequisites
9
+
10
+ - **Node.js 22.18 or newer** (22 is what CI uses), for the npm route and for
11
+ building from a checkout — the launcher, the postinstall step and the test
12
+ harness are Node scripts. It is the version where Node strips TypeScript
13
+ types without a flag, which `docs/RUN_UNDER_NODE.md` relies on. The
14
+ `install.sh` route below needs no Node at all.
15
+ - **clang** (LLVM 18 recommended) and **lld**, for `--link`. Without them
16
+ `nish` still writes the `.ll` files and exits 3 with the install
17
+ command for your platform when you ask for `--link`.
18
+
19
+ ### Ubuntu / Debian
20
+
21
+ ```bash
22
+ sudo apt-get update
23
+ sudo apt-get install -y clang-18 lld-18 llvm-18
24
+ ```
25
+
26
+ Debian ships versioned binaries (`clang-18`, `ld.lld-18`, ...). Either point
27
+ `nish` at the versioned compiler with `CC=clang-18`, or expose the plain
28
+ names on `PATH`:
29
+
30
+ ```bash
31
+ mkdir -p ~/.local/llvm-bin
32
+ for t in clang clang++ llc llvm-as opt ld.lld wasm-ld; do
33
+ ln -sf "/usr/bin/$t-18" ~/.local/llvm-bin/$t
34
+ done
35
+ export PATH=~/.local/llvm-bin:$PATH # add to your shell profile
36
+ ```
37
+
38
+ (`sudo apt-get install -y clang lld llvm` also works if your release's default
39
+ LLVM is 15 or newer.)
40
+
41
+ ### Fedora
42
+
43
+ ```bash
44
+ sudo dnf install clang lld llvm
45
+ ```
46
+
47
+ ### macOS
48
+
49
+ ```bash
50
+ brew install llvm@18
51
+ export PATH="$(brew --prefix llvm@18)/bin:$PATH" # add to your shell profile
52
+ ```
53
+
54
+ Xcode's `clang` (`xcode-select --install`) also works for native binaries;
55
+ the Homebrew LLVM is needed for the `wasm` and `wasi` profiles (`wasm-ld`).
56
+
57
+ ### WASI (optional, for `--profile wasi`)
58
+
59
+ The `wasi` profile links the runtime against wasi-libc so that whole programs
60
+ (strings, `console.log`, files, `process.argv`) run under any WASI host. It
61
+ needs a WASI sysroot and compiler-rt's wasm32 builtins next to your clang:
62
+
63
+ ```bash
64
+ # Ubuntu / Debian: the packaged sysroot lands in /usr/lib/wasi-sysroot
65
+ sudo apt-get install -y wasi-libc libclang-rt-18-dev-wasm32
66
+
67
+ # Any platform: wasi-sdk's sysroot and builtins tarballs (versions that match your clang)
68
+ curl -L -o - https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-24/wasi-sysroot-24.0.tar.gz | tar -xz -C /opt
69
+ curl -L -o - https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-24/libclang_rt.builtins-wasm32-wasi-24.0.tar.gz | tar -xz -C /opt
70
+ export WASI_SYSROOT=/opt/wasi-sysroot-24.0 # add to your shell profile
71
+ ```
72
+
73
+ `scripts/build.sh` looks for the sysroot in `WASI_SYSROOT`,
74
+ `/usr/lib/wasi-sysroot`, `/opt/wasi-sdk/share/wasi-sysroot` and
75
+ `/usr/share/wasi-sysroot`, and for `libclang_rt.builtins-wasm32.a` in clang's
76
+ resource directory, next to the sysroot (as the tarball above unpacks it),
77
+ in `<sysroot>/lib/wasm32-wasi/`, or at `WASI_BUILTINS=<file>`. Then:
78
+
79
+ ```bash
80
+ nish examples/argv.ts --link build/argv.wasm --profile wasi
81
+ node examples/wasi-host.mjs build/argv.wasm 3 4 five # or: wasmtime build/argv.wasm 3 4 five
82
+ ```
83
+
84
+ Node's built-in `node:wasi` runs the module (argv, stdout, exit code and the
85
+ working directory behave as natively); `npm test` prints
86
+ `skipped: no WASI sysroot` and moves on when none is installed.
87
+
88
+ ### Windows
89
+
90
+ Windows is not supported natively yet: `scripts/build.sh` is a bash script
91
+ and the runtime is built with clang on a POSIX toolchain. Use
92
+ [WSL](https://learn.microsoft.com/windows/wsl/install) with Ubuntu and follow
93
+ the Ubuntu steps inside it.
94
+
95
+ ## 2. Install the compiler
96
+
97
+ **Two ways in, and they install the same compiler.** Neither compiles anything
98
+ on your machine: the binary was built, `--verify`d and smoke-tested on hardware
99
+ of its own architecture by the release workflow before the release existed, and
100
+ installing is a download and an unpack.
101
+
102
+ Through npm, which is also how an Nish *program* resolves its dependencies
103
+ ([wp21-packages.md](wp21-packages.md)), so this is the one to pick if you want
104
+ the compiler pinned per project in a `package.json`:
105
+
106
+ ```bash
107
+ npm install -g @amritk/nish
108
+ nish --version
109
+ ```
110
+
111
+ Or without npm and without node at all:
112
+
113
+ ```bash
114
+ curl -fsSL https://raw.githubusercontent.com/amritk/nish/main/install.sh | sh
115
+ ```
116
+
117
+ That unpacks into `~/.nish` and prints the one line to add to your shell
118
+ profile. On a platform it has no binary for it says so and names the four it
119
+ does build — the npm route covers exactly the same four and no more, because
120
+ since 0.6.0 there is no compiler inside that package to fall back to either.
121
+
122
+ **Upgrading is running it again.** There is no separate command: it installs
123
+ over an existing install, says `upgrading nish 0.3.0 to 0.4.0`, and says
124
+ `nothing to do` when the version already matches.
125
+
126
+ ```bash
127
+ curl -fsSL https://raw.githubusercontent.com/amritk/nish/main/install.sh | sh # latest
128
+ curl -fsSL https://raw.githubusercontent.com/amritk/nish/main/install.sh | sh -s 0.4.0 # a version
129
+ sh install.sh --dir /opt/nish # somewhere other than ~/.nish (or NISH_INSTALL)
130
+ sh install.sh --force # reinstall the version already there
131
+ sh install.sh --uninstall # remove it
132
+ sh install.sh --help # all of the above
133
+ ```
134
+
135
+ An upgrade cannot leave you without a compiler. The new one is unpacked beside
136
+ the old, checked that it runs *and* that it reports the version that was asked
137
+ for — which catches a truncated download, a tarball built for another
138
+ architecture, and an asset whose name does not match what is inside it — and
139
+ only then swapped in. If any of that fails the install you had is untouched.
140
+
141
+ The npm route installs the **native** compiler, and it is a download rather than a
142
+ build: nothing is compiled on your machine. The package declares one
143
+ `nish-<os>-<arch>` package per supported platform as an `optionalDependencies`
144
+ entry with `os` and `cpu` set, so npm fetches exactly the one that matches and
145
+ skips the rest. Each of those carries the self-hosted compiler — `self/`
146
+ compiled by itself — already built, `--verify`d and smoke-tested on a machine
147
+ of its own architecture by the release workflow.
148
+
149
+ A postinstall step then puts that binary on your PATH directly, so `nish` is
150
+ the compiler rather than a node script that starts it — 3.2 ms per invocation
151
+ instead of 94 ms, measured. If you install with `npm ci --ignore-scripts`, or
152
+ in a sandbox that disables scripts, the step does not run and `nish` is a small
153
+ node launcher that spawns the same binary: the same compiler and the same
154
+ answers, about 91 ms slower to start. Nothing else changes, and the install
155
+ never fails over it.
156
+
157
+ > [!IMPORTANT]
158
+ > **Unpacking a release tarball onto your `PATH` is not an install.** The
159
+ > compiler resolves `scripts/build.sh` and `runtime/` from `argv[0]`'s
160
+ > directory, and a bare `nish` found on `PATH` has no directory in it — so it
161
+ > looks in `./..` and every `--link` fails against whatever your working
162
+ > directory happens to be, while `--version` and `-o` keep working. Both
163
+ > installers above handle it by running the binary through a one-line `exec` of
164
+ > an absolute path. If you unpack a tarball by hand, invoke it by path
165
+ > (`nish-<version>-<asset>/bin/nish`) or write that wrapper yourself. The
166
+ > underlying defect is [wp19 §5a](wp19-stage0-retirement.md#5a-what-r6-is-waiting-on)
167
+ > item 4.
168
+
169
+ **Do not install `nish`.** That name on the public registry has belonged to
170
+ `stdarg`'s "A Node.js Interactive shell" since February 2014 — versions 0.0.0
171
+ and 0.0.1, both deprecated by their author, nothing published since. **This
172
+ compiler is `@amritk/nish`** (decided 2026-09-19,
173
+ [docs/wp12-release.md](wp12-release.md#the-npm-name)), and the command it
174
+ installs is still `nish` — the package name and the command are two different
175
+ strings, and that is the one thing the scope costs.
176
+
177
+ **On a platform this project attaches no binary for, `npm install` gets you a
178
+ command that refuses.** The table below is the whole list, so musl, FreeBSD and
179
+ 32-bit anything are outside it, and outside it `nish` prints what happened,
180
+ names the four platforms that do have a binary, and exits 3:
181
+
182
+ ```
183
+ $ nish --version
184
+ nish: no prebuilt compiler for freebsd/x64
185
+
186
+ This package installs a prebuilt native compiler. One is published for:
187
+ aarch64-darwin aarch64-linux x86_64-darwin x86_64-linux
188
+
189
+ There is no compiler inside the package to fall back to, and nothing is
190
+ compiled on your machine on any path.
191
+
192
+ To get a compiler for this machine, build one from a released `nish` in a
193
+ checkout of the repository:
194
+ NISH_BOOTSTRAP=<a released nish that runs here> scripts/bootstrap.sh
195
+ docs/INSTALL.md has the detail, including what to do when no released
196
+ binary runs on this platform at all.
197
+ ```
198
+
199
+ Until 0.6.0 it ran the TypeScript compiler that shipped in the same package
200
+ instead — the same compiler by every test here, about eight times slower, and
201
+ no C toolchain needed. That compiler was `src/`, which was deleted in R6
202
+ ([wp19](wp19-stage0-retirement.md)), so there is nothing left in the package to
203
+ fall back to. The cost is stated where the rest of that deletion's costs are,
204
+ in [wp19 §6](wp19-stage0-retirement.md#6-what-retirement-costs-stated-plainly),
205
+ and it is a real one: **musl, FreeBSD and 32-bit platforms have no `npm
206
+ install` route to a compiler any more.**
207
+
208
+ What is left for those platforms is the bootstrap, and it needs one thing this
209
+ page cannot hand you: a compiler that already runs on the machine. The seed does
210
+ not have to be *for* the machine — it has to run *on* it — so the practical
211
+ routes are
212
+
213
+ - a glibc container or host to build in, when the target is musl. Build
214
+ `build/nish` there with `NISH_BOOTSTRAP=<released nish> scripts/bootstrap.sh`,
215
+ and then **emit the IR in the container and link it on the musl host**:
216
+
217
+ ```bash
218
+ # in the glibc container, where build/nish runs
219
+ build/nish app.ts -o app.ll
220
+ # on the musl host, with its own clang and the runtime from this repository
221
+ clang app.ll runtime/runtime.c runtime/runtime_os.c -lm -o app
222
+ ```
223
+
224
+ `--link`ing inside the container is the mistake to avoid: it shells out to the
225
+ container's `clang` and hands you a glibc binary, which is the one thing the
226
+ musl host cannot run. The split works because the compiler's output is
227
+ target-neutral text — the C toolchain that compiles `runtime.c` and links is
228
+ what decides the libc, not the compiler that wrote the IR;
229
+ - `--profile wasi`, which compiles the compiler itself into a single WASI module
230
+ that runs anywhere Node does (`web/compile.mjs` drives one). This is not a
231
+ shipped artefact and there is no supported install path for it;
232
+ - a target this project does build, if one will do.
233
+
234
+ If you need one of these to be a first-class install, that is the conversation
235
+ to have on the issue tracker rather than a workaround to discover here.
236
+
237
+ **Nothing is published to the registry yet.** The installer is built and
238
+ tested, and what is left is a person publishing a release under it, which
239
+ [docs/wp12-release.md](wp12-release.md#release-procedure) step 4 is about.
240
+ Until that happens, install from a release.
241
+
242
+ From a release tarball on GitHub — the same package `npm publish` would upload,
243
+ carried by the release instead of the registry. The `Release` workflow attaches
244
+ the npm tarball to the release it builds for a `v*` tag. `npm pack` names it
245
+ after `package.json#name`, so it is `amritk-nish-<version>.tgz` from 0.4.0 on
246
+ and `nish-<version>.tgz` for the releases cut before the scope was taken — the
247
+ example below is one of those:
248
+
249
+ ```bash
250
+ curl -LO https://github.com/amritk/nish/releases/download/v0.2.0/nish-0.2.0.tgz
251
+ npm install -g ./nish-0.2.0.tgz
252
+ nish --version
253
+ ```
254
+
255
+ Installed on its own like that, the package finds no platform package next to
256
+ it and refuses — the same refusal as above, but for the other reason: the binary
257
+ was never fetched rather than none existing for your machine. The message says
258
+ which of the two it is, because the remedy differs. **So install the pair**: a
259
+ release from 0.4.0 on attaches the platform packages beside the npm tarball,
260
+ under the name `npm pack` gave them.
261
+
262
+ ```bash
263
+ base=https://github.com/amritk/nish/releases/download/v0.4.0
264
+ curl -LO $base/amritk-nish-0.4.0.tgz
265
+ curl -LO $base/amritk-nish-x86_64-linux-0.4.0.tgz # the row matching your machine
266
+ npm install -g ./amritk-nish-0.4.0.tgz ./amritk-nish-x86_64-linux-0.4.0.tgz
267
+ ```
268
+
269
+ As a native compiler, which needs no Node at all. A release also attaches the
270
+ self-hosted compiler — the binary `self/` produces by compiling itself — one
271
+ per supported platform, from the version named in the last column:
272
+
273
+ | Asset | For | Attached from |
274
+ | --- | --- | --- |
275
+ | `nish-<version>-x86_64-linux.tar.gz` | Linux on Intel or AMD | v0.1.1 |
276
+ | `nish-<version>-aarch64-linux.tar.gz` | Linux on ARM | v0.4.0 |
277
+ | `nish-<version>-x86_64-darwin.tar.gz` | macOS on Intel | v0.4.0 |
278
+ | `nish-<version>-aarch64-darwin.tar.gz` | macOS on Apple Silicon | v0.4.0 |
279
+
280
+ Each is built and smoke-tested on a machine of its own architecture rather than
281
+ cross-compiled, so the one you take has compiled and run two programs before it
282
+ reached you — a one-module one and a two-module one, from a directory unrelated
283
+ to the machine that built it.
284
+
285
+ The last column is there because a release is a past event and a workflow is
286
+ not. `release.yml` builds all four, but a release already published cannot grow
287
+ an asset: **v0.2.0, the current release, attaches `x86_64-linux` only**. Those
288
+ versions are not prose — they are `attachedSince` in
289
+ [`.github/seed-targets.json`](https://github.com/amritk/nish/blob/main/.github/seed-targets.json),
290
+ the same file the release workflow builds its matrix from, so this table and
291
+ the assets cannot drift apart without a test failing.
292
+
293
+ **The three new rows say v0.4.0 rather than v0.3.0 on purpose.** The workflow
294
+ builds all four now, but nothing in this repository has ever run on macOS or on
295
+ ARM Linux, and a row that has never run is not something to put in front of a
296
+ release: `release` needs the whole matrix, so one red row blocks the publish.
297
+ They wait for a release after the run that exercises them. The two macOS rows
298
+ wait on a second thing as well — the bootstrap's `stage3 == stage2` check does
299
+ not hold as a raw byte comparison under `ld64`, and which bytes actually differ
300
+ has not been measured on real hardware, so a darwin row may turn up work rather
301
+ than a green tick. `scripts/verify-binaries.sh`'s header is the long version.
302
+
303
+ Check [the releases page](https://github.com/amritk/nish/releases/latest) for
304
+ what a given version actually carries; on a platform whose row has not shipped
305
+ yet, take the npm package above, or build from source below.
306
+
307
+ ```bash
308
+ # pick the row above that matches `uname -s` and `uname -m`
309
+ curl -LO https://github.com/amritk/nish/releases/download/v0.2.0/nish-0.2.0-x86_64-linux.tar.gz
310
+ tar -xzf nish-0.2.0-x86_64-linux.tar.gz
311
+ nish-0.2.0-x86_64-linux/bin/nish --version
312
+ ```
313
+
314
+ Both URLs name the version rather than using GitHub's version-neutral
315
+ `/releases/latest/download/` form, because that form needs the asset's exact
316
+ file name and every asset name carries the version in it. **v0.2.0 is the
317
+ current release**; v0.1.1 before it was the first one with a binary attached.
318
+ The `v0.1.0` tag exists but has no release behind it and no assets, so every
319
+ `v0.1.0` download URL is a 404 — the tag was pushed by a workflow, and GitHub
320
+ raises no event for that, so nothing ever built it
321
+ ([docs/wp12-release.md](wp12-release.md#release-procedure) step 2). When a newer
322
+ release exists, take its version from
323
+ [the releases page](https://github.com/amritk/nish/releases/latest).
324
+
325
+ Unpack it and run `bin/nish` from wherever you like; put that on `PATH` if you
326
+ want it there. Keep the directory intact rather than moving the binary out of
327
+ it: `--link` runs `scripts/build.sh` and compiles the C runtime
328
+ (`runtime/runtime.c` and `runtime/runtime_os.c`, the system-call half), and the
329
+ compiler finds all of them relative to its own location — `bin/nish` alone in a
330
+ directory can still emit IR with `-o`, but `--link` will tell you it cannot
331
+ find `scripts/build.sh`.
332
+
333
+ It still needs `clang` and `lld` on `PATH` for `--link` (§1), because linking
334
+ is the C toolchain's job, not the compiler's; what it does not need is Node.
335
+ x86_64 Linux is the only platform built today — on anything else, take the
336
+ `.tgz` above or build from a checkout.
337
+
338
+ From a checkout:
339
+
340
+ ```bash
341
+ git clone https://github.com/amritk/nish.git
342
+ cd nish
343
+ npm ci
344
+ bash scripts/fetch-seed.sh # the last release, into build/seed/
345
+ npm run build # seed -> stage1 -> stage2 = build/nish
346
+ build/nish hello.ts --link hello
347
+ ```
348
+
349
+ The build is a bootstrap, the way Rust and Go build themselves: the compiler
350
+ is written in Nish, so something has to compile it first, and that is the
351
+ previous release's `nish` binary — the seed. `scripts/fetch-seed.sh` downloads
352
+ it into `build/seed/`; `NISH_BOOTSTRAP=<path>` names one you already have and
353
+ skips the download. §2a has what the build does with it.
354
+
355
+ The published package ships `bin/` (the `nish` command, which is a launcher),
356
+ `runtime/` (the C runtime — two translation units and their header),
357
+ `scripts/build.sh` (the link pipeline) and `std/` (the standard library). The
358
+ compiler itself is not in it: it arrives as one prebuilt
359
+ `@amritk/nish-<asset>` package per platform, and `bin/nish` hands over to
360
+ whichever one npm installed. `nish` locates the runtime, the script and `std/`
361
+ relative to its own install directory, so a global install works from any
362
+ working directory — and the binary runs from inside its own platform package
363
+ for exactly that reason.
364
+
365
+ Building the IR yourself rather than through `--link` means naming the runtime
366
+ on the `clang` line, and it is two files:
367
+
368
+ ```bash
369
+ clang app.ll runtime/runtime.c runtime/runtime_os.c -lm -o app
370
+ ```
371
+
372
+ `runtime.c` is the half every program touches — the arena, strings, arrays,
373
+ number formatting, the panics — and `runtime_os.c` is the half that wraps the
374
+ system calls: files, directories, subprocesses, `getenv`, the monotonic clock.
375
+ They are separate so that each carries its own measured size ceiling
376
+ ([docs/wp7-runtime.md](wp7-runtime.md)); nothing in the core calls into the
377
+ system-call half, so an older line that names `runtime.c` alone still links a
378
+ program that reads no files and spawns nothing. `scripts/build.sh` compiles
379
+ `runtime_os.c` beside any `runtime.c` it is handed, so a build that goes
380
+ through it — every `--link`, and every `--profile` recipe in these documents —
381
+ needs to name only the one.
382
+
383
+ ## 2a. What `npm run build` does
384
+
385
+ `self/` is the compiler, written in Nish, and it compiles itself
386
+ ([docs/wp14-selfhost.md](wp14-selfhost.md)). From a checkout, with clang on
387
+ `PATH`, `npm run build` runs `scripts/bootstrap.sh` with the seed from §2:
388
+
389
+ ```bash
390
+ npm run build # build/nish
391
+ NISH_BOOTSTRAP=~/.nish/bin/nish npm run build # the same, seeded by an installed nish
392
+ scripts/bootstrap.sh --verify # and assert the fixed point
393
+ ```
394
+
395
+ The seed builds stage1, stage1 builds stage2, and stage2 is installed as
396
+ `build/nish`. `--verify` also builds stage3 and asserts
397
+ `IR(stage1) == IR(stage2)` and `stage3 == stage2` byte for byte; the seed's
398
+ own IR is only reported beside them, because a codegen change since the
399
+ release is expected to move it. `--stages 1` stops one link sooner.
400
+
401
+ `build/nish` is then the compiler you run: it takes the same `-o`, `--link`
402
+ and `--profile` spellings as an installed `nish`, because it is the same
403
+ program, and makes every directory in the way of the IR, a sidecar or the
404
+ binary itself. It looks for `scripts/build.sh` and the two `runtime/*.c` files
405
+ one level up from wherever it was invoked, then in the working directory, so
406
+ it wants a checkout or an installed package around it the way `nish` does.
407
+
408
+ Because the seed is the last release, `self/` may only *use* in its own
409
+ source the constructs that release compiles. A new construct is implemented
410
+ in `self/` and becomes usable inside `self/` from the next release on; CI's
411
+ `bootstrap` job is what checks that the released seed still builds stage1.
412
+ Until R6 the seed was a TypeScript compiler in `src/`, run under Node; it was
413
+ deleted once the native one answered every flag it did
414
+ ([wp19](wp19-stage0-retirement.md)).
415
+
416
+ ## 3. Hello world
417
+
418
+ Create `hello.ts`:
419
+
420
+ ```ts
421
+ export const main = (): number => {
422
+ console.log("hello from Nish");
423
+ return 0;
424
+ };
425
+ ```
426
+
427
+ `export const main` is the process entry; its return value is the exit code
428
+ (`main(): void` exits 0). Compile and link it:
429
+
430
+ ```bash
431
+ nish hello.ts --link hello
432
+ # wrote hello.ll
433
+ # linked hello: 5104 bytes (speed)
434
+ ./hello
435
+ # hello from Nish
436
+ ```
437
+
438
+ `hello.ll` is the LLVM IR, kept next to the binary. To only get the IR:
439
+
440
+ ```bash
441
+ nish hello.ts -o hello.ll
442
+ ```
443
+
444
+ Other build profiles: `--profile size` (smallest binary), `--profile debug`
445
+ (no optimisation, symbols kept). Run `nish --help` for every flag, and
446
+ see the [README](../README.md) for the language subset.
447
+
448
+ ## 4. Exit codes
449
+
450
+ | Code | Meaning |
451
+ | ---: | --- |
452
+ | 0 | success |
453
+ | 1 | the program was rejected: compile error (`file:line:col: error: ...`), missing input file, or an `-o` layout that does not fit the module count |
454
+ | 2 | usage error: unknown flag, missing argument, no input files |
455
+ | 3 | toolchain error: `--link` found no `clang` (`CC` overrides), or `scripts/build.sh` failed (its output is shown; the `.ll` files are still written) — or the `nish` command found no prebuilt compiler for this platform, or one that would not start. Under `--json` all of these are one `NL0002` object |
456
+ | 70 | internal compiler error: an unexpected exception. Please report it at <https://github.com/amritk/nish/issues> with the input and command line; `NISH_DEBUG=1` prints the stack trace |
457
+
458
+ ## Troubleshooting
459
+
460
+ - `--link: no usable C compiler found` -- install clang as above, or set
461
+ `CC=/path/to/clang` (for example `CC=clang-18` on Debian).
462
+ - `warning: overriding the module target triple` from clang -- harmless: the
463
+ IR is target-neutral and clang fills in the host triple.
464
+ - `the wasm profile needs wasm-ld` -- install `lld` (`lld-18` on Debian,
465
+ bundled with Homebrew `llvm@18`).
466
+ - `the wasi profile needs a WASI sysroot` / `needs compiler-rt's wasm32
467
+ builtins` -- install them as in the WASI section above, or point
468
+ `WASI_SYSROOT` (a directory) and `WASI_BUILTINS` (the `.a` file) at them.
package/llms.txt ADDED
@@ -0,0 +1,49 @@
1
+ # Nish
2
+
3
+ > Nish is an ahead-of-time compiler from a strictly static subset of TypeScript
4
+ > to LLVM IR. Every Nish program is legal TypeScript syntax and type-checks
5
+ > under `tsc --strict`, but the subset is far smaller than TypeScript: no `any`,
6
+ > no `throw`, no callbacks or function values, no inheritance, no truthiness,
7
+ > and no implicit conversion of any kind. Generics are monomorphised: each
8
+ > instantiation is its own function or struct. Failure is a `Result<T, E>` the
9
+ > checker will not let you drop; absence is `T | null` you must narrow. There is
10
+ > no garbage collector — allocation is placed at compile time.
11
+
12
+ If you are **writing a Nish program**, read `docs/AI.md` first. It is the whole
13
+ language as rules, written for one pass, with the TypeScript reflexes that get
14
+ rejected listed before anything else. If you are **working on the compiler**,
15
+ read `AGENTS.md` and `.claude/orientation.md` instead.
16
+
17
+ Verify, never guess: `nish program.ts --json` prints one flat JSON object per
18
+ diagnostic on stdout and is the only authority on whether a program is legal.
19
+ Key on the stable `code` field (`NL2249`), never on the prose in `message`.
20
+ Exit codes: 0 ok, 1 the program was rejected, 2 usage, 3 the C toolchain or the
21
+ prebuilt compiler could not be run (one NL0002 object under --json), 70 a bug in
22
+ the compiler.
23
+
24
+ ## Writing Nish
25
+
26
+ - [Rules card](https://raw.githubusercontent.com/amritk/nish/main/docs/AI.md): the whole language as rules, sized for one read — the traps first, then types, `Result`, nullables, declarations, statements, the complete builtin inventory, and recipes for what is missing. Ships in the npm package as `docs/AI.md`.
27
+ - [Language reference](https://raw.githubusercontent.com/amritk/nish/main/docs/LANGUAGE.md): normative and exhaustive. Every rule cites the test that pins it and quotes the exact rejection message. Settles any disagreement with the rules card.
28
+ - [Ambient declarations](https://raw.githubusercontent.com/amritk/nish/main/runtime/nish.d.ts): reference this from `tsconfig.json` and `tsc --strict`, your editor and your language server accept `Result<T, E>`, `i32` and the rest. `nish` is still the authority — `tsc` cannot see the flow rules.
29
+ - [Standard library](https://raw.githubusercontent.com/amritk/nish/main/std/README.md): `std/testing`, a suite a program drives to check itself and answer an exit code; `std/text`, the `split` / `trim` / `replace` the language does not have; `std/json`, the value of one field of one flat JSON object — enough to read this compiler's own `--json` output. Source rather than a built library, imported by relative path, and shipped in the npm package under `std/`.
30
+ - [FAQ](https://raw.githubusercontent.com/amritk/nish/main/docs/FAQ.md): why no `any`, why `i32`, how to get JavaScript numbers, why no GC, overflow and `--wrapping`, what errors look like.
31
+ - [Install](https://raw.githubusercontent.com/amritk/nish/main/docs/INSTALL.md): prerequisites per OS, hello world, exit codes, troubleshooting.
32
+
33
+ ## How it compiles
34
+
35
+ - [IR cookbook](https://raw.githubusercontent.com/amritk/nish/main/docs/IR_COOKBOOK.md): for every construct, the smallest snippet and the exact LLVM IR it compiles to today.
36
+ - [Architecture](https://raw.githubusercontent.com/amritk/nish/main/docs/ARCHITECTURE.md): the pipeline, side tables, how to add a construct, the ABI contracts, attribute soundness rules, the test harness.
37
+ - [Benchmarks](https://raw.githubusercontent.com/amritk/nish/main/docs/BENCHMARKS.md): wall time, binary size and peak memory against C and Rust, with the exact build commands.
38
+
39
+ ## Working on the compiler
40
+
41
+ - [Agent guide](https://raw.githubusercontent.com/amritk/nish/main/AGENTS.md): the repository's rules for AI agents — the machine-readable surfaces, how to trust a test run, the house rules.
42
+ - [Orientation](https://raw.githubusercontent.com/amritk/nish/main/.claude/orientation.md): the two compilers, the code map, the commands, the seven things that are always true.
43
+ - [Documentation index](https://raw.githubusercontent.com/amritk/nish/main/docs/README.md): every reference and design note, one line each.
44
+
45
+ ## Optional
46
+
47
+ - [Master plan](https://raw.githubusercontent.com/amritk/nish/main/docs/MASTER_PLAN.md): vision, design rules, work packages, contributor conventions.
48
+ - [Self-hosting](https://raw.githubusercontent.com/amritk/nish/main/docs/wp14-selfhost.md): the compiler written in its own language, and the oracles that keep the two in step.
49
+ - [Changelog](https://raw.githubusercontent.com/amritk/nish/main/CHANGELOG.md): generated from the commits; what changed in each release.
package/package.json ADDED
@@ -0,0 +1,87 @@
1
+ {
2
+ "name": "@amritk/nish",
3
+ "version": "0.10.0",
4
+ "description": "Nish: an ahead-of-time compiler from a static subset of TypeScript to LLVM IR",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "exports": {
8
+ "./package.json": "./package.json",
9
+ "./runtime/*": "./runtime/*",
10
+ "./scripts/*": "./scripts/*",
11
+ "./*": "./std/*.ts"
12
+ },
13
+ "bin": {
14
+ "nish": "bin/nish"
15
+ },
16
+ "files": [
17
+ "bin",
18
+ "runtime",
19
+ "scripts",
20
+ "!scripts/arrow-verify.mjs",
21
+ "!scripts/arrowify.mjs",
22
+ "!scripts/fetch-seed.sh",
23
+ "!scripts/check-pr-body.mjs",
24
+ "!scripts/check-pr-body.test.mjs",
25
+ "!scripts/changelog-gen.test.mjs",
26
+ "std",
27
+ "README.md",
28
+ "LICENSE",
29
+ "llms.txt",
30
+ "docs/AI.md",
31
+ "docs/INSTALL.md"
32
+ ],
33
+ "scripts": {
34
+ "build": "bash scripts/bootstrap.sh",
35
+ "postinstall": "node scripts/postinstall.mjs",
36
+ "bootstrap": "bash scripts/bootstrap.sh",
37
+ "compile": "build/nish",
38
+ "example": "build/nish examples/add.ts -o build/add.ll && cat build/add.ll",
39
+ "test": "node tests/run.js",
40
+ "size-report": "build/nish examples/add.ts -o build/add.ll && bash scripts/size-report.sh build/add.ll examples/main.c",
41
+ "smoke": "bash scripts/smoke.sh",
42
+ "check": "tsc -p tsconfig.json",
43
+ "test:update": "UPDATE_GOLDENS=1 node tests/run.js",
44
+ "test:diff": "node tests/differential/run.js",
45
+ "test:nish": "build/nish tests/nish/run.ts -o build/nish-runner.ir/ --link build/nish-runner && build/nish-runner",
46
+ "test:cli": "build/nish tests/nish/cli.ts -o build/nish-cli.ir/ --link build/nish-cli && build/nish-cli",
47
+ "test:node": "node tests/differential/unmodified.js",
48
+ "lint": "biome check --formatter-enabled=false .",
49
+ "format": "biome format --write .",
50
+ "prepublishOnly": "npm run check && npm test",
51
+ "changelog": "node scripts/changelog-gen.mjs"
52
+ },
53
+ "engines": {
54
+ "node": ">=22.18.0"
55
+ },
56
+ "repository": {
57
+ "type": "git",
58
+ "url": "git+https://github.com/amritk/nish.git"
59
+ },
60
+ "bugs": {
61
+ "url": "https://github.com/amritk/nish/issues"
62
+ },
63
+ "homepage": "https://github.com/amritk/nish#readme",
64
+ "keywords": [
65
+ "typescript",
66
+ "compiler",
67
+ "llvm",
68
+ "llvm-ir",
69
+ "ahead-of-time",
70
+ "aot",
71
+ "native",
72
+ "wasm",
73
+ "webassembly",
74
+ "nish"
75
+ ],
76
+ "optionalDependencies": {
77
+ "@amritk/nish-x86_64-linux": "0.10.0",
78
+ "@amritk/nish-aarch64-linux": "0.10.0",
79
+ "@amritk/nish-aarch64-darwin": "0.10.0",
80
+ "@amritk/nish-x86_64-darwin": "0.10.0"
81
+ },
82
+ "devDependencies": {
83
+ "@biomejs/biome": "2.5.12",
84
+ "@types/node": "^22.0.0",
85
+ "typescript": "^5.6.0"
86
+ }
87
+ }