SchOS/docs/plan/finch.md
Nexoniarz afb2e084af docs: Finch's self-hosting gap, as it stands
Sized numbers, methods, defer, errors as values and maps are now in the
self-hosted compiler; C import is the one piece left.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015f73FesGZGYPkmDvUcj6QX
2026-10-25 18:55:31 +01:00

96 lines
5.1 KiB
Markdown

# Finch, for SchOS's own programs
**Two things, and only one of them is later.**
- *Bringing Finch into SchOS* (below) is **later** — behind [1.0.md](1.0.md)'s
freeze like everything else here that is not named there.
- *Finishing Finch itself*, and making it fully self-hosting, is work on the
Finch repository and does not touch this tree. It can proceed now; see
[the gap](#the-self-hosting-gap).
Finch is the author's own language: <https://pandor.pl/git/nexoniarz/Finch>
(GitHub mirror: `Nexoniarz/Finch`). The plan is to write SchOS's own
applications and tools in it, in place of C, and so leave behind what C does
badly: silent narrowing, signed/unsigned mixing, undefined behaviour on an
out-of-range index, a forgotten `free`.
## What it is today (version 2.4.0)
Measured from the repository, not from its README alone:
- **LLVM front end**, C-like syntax, no semicolons, no headers, no preprocessor.
It compiles through LLVM's `-O2` pipeline to native code; there is no
garbage collector.
- **Values, not references:** lists, text and structs copy on assignment and
are freed at the end of their block. Out-of-range indexes, division by zero
and null pointers stop with a runtime error rather than undefined behaviour.
- **Errors as values** (`int(s) or 0`, `try read_file(p)`), maps, methods,
modules.
- **C interop through libclang:** `import "foo.h"` plus `link "foo"` calls any C
library, structs by value and callbacks included. That is the way in to
everything SchOS already has — musl, the `/dev/*` interfaces, Alpine's
libraries.
- **Targets:** Linux, macOS, Windows, on x86-64 and ARM64 (`src/target.cpp`;
the System V, AAPCS64 and Microsoft x64 ABIs are in `src/abi.cpp`).
- **Tooling:** a language server (`finch lsp`), VS Code and Kate support, 74
tests.
- **Self-hosting:** `boot/` is a Finch compiler written in Finch (about 3,100
lines, against about 5,900 for the C++ one in `src/`, language server included) that builds itself to a
byte-identical result — `tests/boot.sh`.
## What SchOS would need to do
1. **A `schos` target.** `finch` picks a triple, a C compiler and a linker per
target. SchOS runs unmodified Alpine binaries and Alpine's musl
(see [alpine.md](alpine.md)), so the first target is **the existing
`x86_64-unknown-linux-musl`**, and a Finch program built on the host should
run on SchOS before anything in Finch is made SchOS-specific. Test that
before writing a line of target code.
2. **The compiler on SchOS.** Needs LLVM 21 and libclang, both of which Alpine
packages. That is a question of apk and memory, not of SchOS.
3. **`boot/` as the SchOS-hosted compiler.** The C++ compiler needs LLVM's C++
libraries; the one in `boot/` is the candidate for being the compiler that
ships in the image, once it emits through LLVM's C API or a smaller
back end.
4. **Bindings** for SchOS's own interfaces (`/dev/pci`, `/dev/netdev`,
schinit's job protocol, the framebuffer) — generated by the C importer from
the headers in `include/uapi/`, so they are not hand-written and cannot
drift from the kernel.
## The self-hosting gap
"Rewrite it in Finch itself" was mostly done before this was written: `boot/`
compiled itself. What it lacked is stated by its own test, `tests/boot.sh`,
which skips every test using a feature `boot/` does not have. Measured against
that test, on the branch `finish-finch` of the Finch repository (kept in the
author's checkout, `Projects/Finch`, as a branch on top of `embed`):
| Feature | `boot/` | Notes |
|---|---|---|
| sized numbers (`i8`..`u64`, `f32`), conversions | **done** | `int` and `float` stay the i64 and f64 defaults |
| methods (`fn T.m`), mutation analysis | **done** | |
| `defer` | **done** | |
| errors as values (`-> T!`, `error`, `try`, `or`) | **done** | including `fn main() -> !` |
| maps, `for k, v in`, `for i, x in` | **done** | |
| `str(x)` of any value | **done** | |
| **C import** (`import "x.h"`, `link`, C structs by value) | **missing** | the one that matters for SchOS: libclang through Finch's own C import, then the System V struct ABI |
| target and ABI layer (AArch64, macOS, Windows) | missing | after C import |
| language server | missing | `lsp.cpp`, 580 lines |
The self-hosted compiler passes 17 of 22 tests and compiles itself to
byte-identical output; the five it skips all import C. **C import is the next
piece, and the last one before the C++ compiler is only a seed.** It is a few
thousand lines of Finch (`cimport.cpp` and `abi.cpp` are 740 in C++), done in two
steps so each can be tested: functions, constants, globals and pointers first
(`cimport`, `c_pointers`), struct layout and the calling convention second
(`c_structs`).
The scratch files `note.txt` and `notatka.txt` in the repository are not
Finch's and can go.
## Rules
- Inference, not an instruction: the kernel stays in C. Finch is for
applications and tools; the user said "our apps or stuff like that".
- No new capability starts until [the register of unfinished work](1.0.md#the-freeze-and-the-register-of-unfinished-work)
is empty; the SchOS half of this document is a plan, not an exception to that.