Rail
Rail is a self-hosted ARM64 language with four backends (macOS ARM64, Linux ARM64, Linux x86_64, WebAssembly), an LLM training substrate, and a verifiable provenance layer. The compiler is about 9,700 lines of Rail and compiles itself byte-identically at gen2; the runtime is ARM64 assembly embedded in the compiler. The compiler binary links only libSystem. Programs it builds may link small optional C and ObjC helpers (the JIT trampoline, the Metal host) and system libraries such as SQLite when they use them; SHIMS.md lists every one.
Quickstart
git clone https://github.com/Ledatic-Empire/rail
cd rail
./rail_native run examples/hello.rail
Expected output:
Compiling examples/hello.rail (244 chars)...
as: OK
ld: OK
hello, rail
3628800
42
The seed binary (rail_native, ~1.0 MB ARM64) is checked into the repo and self-compiles to a byte-identical fixed point at gen2 (the first cycle may differ; gen2 == gen3 always). No build step before "hello, world".
For Apple Silicon you're done. Other targets need cross-toolchains; see backends.md.
What's here
- quickstart.md: ten steps from
git cloneto a verified release. Real commands, real outputs. - stdlib.md: auto-generated reference for every top-level function in
stdlib/*.rail. Regenerate with./rail_native run tools/docs/gen_stdlib_ref.rail. - backends.md: one-page-per-backend with the literal command line you'd type.
- jit.md: a self-hosted JIT in pure Rail. ARM64 emit +
mmap-executable, called via apthread_createtrampoline. About 7,400 lines across 32 files. - examples/: 19 runnable programs with source, command, and real captured output. Start with hello, pattern_matching, calculator.
- TODO.md: what's deferred for v0 and why.
Language at a glance
-- Comments start with --
add a b = a + b
factorial n = if n <= 1 then 1 else n * factorial (n - 1)
type Option = | Some x | None
unwrap opt d = match opt
| Some x -> x
| None -> d
main =
let _ = print (show (factorial 10)) -- 3628800
let _ = print (show (unwrap (Some 42) 0)) -- 42
0
Functions are name args = body. main is the entry point and returns an int. ADTs use type T = | Ctor args | .... Pattern matching uses match (no with). Tail calls are compiled to loops with no stack growth.
Six backends, one compiler
./rail_native run file.rail # macOS ARM64 (native execute)
./rail_native linux file.rail # Linux ARM64 (cross)
./rail_native x86 file.rail # Linux x86_64 (cross, emits .s)
./rail_native wasm file.rail # WebAssembly
The same source compiles to all of them. See backends.md for toolchain requirements.
Why it exists
The thesis is in CLAUDE.md: the compiler is the source of truth. The HTTPS client, the training loop, the documentation generator you're reading: all are compiled by the same binary you cloned. If it compiles, it runs.
The closer-term motivation for *this* documentation: open-source LLMs are bad at Rail because there's no Rail corpus to read. These pages, together with the auto-generated stdlib reference, are the substrate fix.