A systems programming language that is as fast as C and memory-safe without lifetime annotations or a garbage collector.
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗A systems programming language that is as fast as C and memory-safe without lifetime annotations or a garbage collector.
x: T), borrow them to change them (inout x: T)
or take them (sink x: T). Borrows are scoped to a function body, so the
compiler sees all of them and needs no annotations..clone() copies them.comptime T: type parameters,
inferred at calls, with traits as bounds.Vec, String, Map, Box,
sorting, files, processes), with or without libc.Documentation: https://jihoolang.github.io/jihoo/, built from docs/ and examples/.
enum Expr {
Num(i64)
Add(Box(Expr), Box(Expr))
}
fn eval(e: Expr) -> i64 {
match e {
Num(n) => n
Add(a, b) => eval(a) + eval(b)
}
}
fn main() {
var counts = Map(String, i64).new()
for w in "a b a".split(" ") {
match counts.get_mut(w) {
Some(n) => n += 1
None => {
counts.insert(w.to_string(), 1)
}
}
}
println(counts["a"]) // 2
println(eval(Expr.Add(Box.new(Expr.Num(2)), Box.new(Expr.Num(3))))) // 5
}
fn main() {
var v = Vec(i64).new()
v.push(1)
for x in v {
v.push(x) // error: `v` is changed here while it is borrowed
}
}
nix run github:jihoolang/jihoo -- run hello.jh # try it
nix profile install github:jihoolang/jihoo # install `jihoo`
Without Nix, each release has the compiler for x86_64 and aarch64 Linux with its standard library; it needs glibc and LLVM 21 (libLLVM, clang, lld).
jihoo is written in jihoo. Everything comes from flake.nix (libLLVM,
clang and lld from LLVM 21, and the seed: the compiler of the latest
release). nix build bootstraps the compiler: the seed builds
compiler/, which builds itself again and is installed.
nix build # ./result/bin/jihoo
nix develop # `jihoo` is the seed
jihoo build -O2 compiler/main.jh -o out/jihoo
out/jihoo run examples/hello.jh
out/jihoo check examples/hello.jh # no code generation or linking
out/jihoo fmt examples/hello.jh # formatted source on stdout
out/jihoo emit-mir examples/hello.jh
jihoo run tests/runner.jh # the tests
| path | what |
|---|---|
compiler | the compiler, in jihoo: parser, type checker, MIR, borrow checker, LLVM IR writer |
lib/std | the standard library, in jihoo |
tests/run, tests/fail | programs and their expected output or error; tests/runner.jh runs them |
examples | example programs, which the website shows |
benchmarks | backend and iterator fusion benchmarks, with recorded measurements |
docs | the documentation, one Markdown file per page |
site | the website (site/README.md) |
Version 0.4: the 0.1 rewrite, which broke compatibility with everything before it (why), with a self-hosted compiler and checking, testing, diagnostic and formatting tools. Native (libc) and freestanding (no libc, static) programs for x86_64 and aarch64 Linux, and UEFI applications (PE32+ images) for both machines.
The compiler uses its own threads: it elaborates, infers borrow effects and
checks borrows one function per thread, the costliest first, and emits
large programs in parallel code generation units, with the same output as
one thread. On 8 CPUs, jihoo check of the compiler takes 0.53 s and a
full -O2 build 15.2 s, against 17.0 s and 36.8 s at 0.2.1
(phase timings,
roadmap).
Done: ownership with moves, destructors and drop flags; borrowing with
parameter conventions, projections and views, checked by a separate borrow
kernel; integers up to 128 bits; structs, enums, tuples, arrays, slices;
match with exhaustiveness, | patterns that bind names, let ... else,
and matches that are views of the borrowed parts they give; generics
with inference; traits with default
methods and generic impls; closures that borrow, comptime closures
that inline, and move fn closures that own their captures without
allocating, returned as -> impl Iterator or -> impl fn(A) -> R; Option, Result and ?; unsafe pointers, static
globals, C functions and callbacks (including structs by value, 128-bit
integers and variadic function pointers on both targets), dynamic libraries
(std.ffi), system calls, atomics and volatile accesses for device
registers; panic handlers for
library objects that another operating system links, and
kernel code generation
without the red zone or vector registers; the standard library,
including running other programs.
Compile-time evaluation runs ordinary functions
and blocks in a separate MIR interpreter for const values, comptime
expressions, array lengths and compile-time arguments. It supports loops,
recursion, aggregates and the heap: Vec, String, Map and destructors
work, and a String or Vec result becomes a static str or slice.
External calls remain unavailable during evaluation.
--comptime-report PATH
records evaluator steps, cumulative allocations and per-function costs;
failures report resource use and the originating compile-time obligation.
Proof checking at compile time (a Horn certificate kernel, general theorems by induction, and enum codecs bound to checked tables) is developed in the separate jihoo-proofs repository. General source-level contracts remain open.
Buffered UTF-8 input (std.io.BufRead, StrReader, BufReader) and
Unicode scalar decoding/iteration (std.utf8) support streaming parsers.
std.os reports
failures as an errno-based os.Error, which std.fs and std.process
also return, and reads and writes bytes with one system call each, so
partial operations, the end of input, interrupted calls and nonblocking
readiness are explicit, in both profiles.
std.fmt formats several
values with patterns such as "{:>8.2} {:#x}", checked while compiling
when they are literals (#[literal_check]),
and floats print the shortest text that reads back as the same value.
The borrow kernel infers argument escape effects for direct calls, including
recursive functions, so methods on views keep only the borrows they can
actually retain; unknown calls and raw memory effects remain conservative.
Reflection: inline for and inline if
unroll and select code at compile time, and builtins name a type's fields
and variants. #[derive(Clone, Eq, Ord, Hash, Show, Default)] is library code
written with them, in std/derive.jh, and keeps privacy.
Threads: std.thread.scope, join, each, map and
each_mut run work on several threads that borrows what the caller owns,
in native and freestanding programs; the _uneven forms hand out one item
at a time, for work of very different sizes.
Scopes start any number of workers, collect results with handle.join()
and join every remaining worker before the body's locals go away.
The borrow rules and a compile-time check of the closures rule out data
races. std.sync.Atomic, Mutex, Channel and Once are shared through
plain borrows.
Data by index: std.arena has typed ids
and arenas, generational handles and pools, and Soa(T), a
struct-of-arrays vector that reflection lays out from T's fields.
Dynamic dispatch: dyn Trait values own a value of
any type with the trait and call it through a table of functions;
dyn fn closures own what they capture, so they can be returned and
stored.
Iterator pipelines compose map, filter,
take, zip and fold without intermediate collections. Callback types
are inferred, and compile-time closures can be named, captured and forwarded.
Supported pipelines also run in the compile-time interpreter.
LLVM 21's C API optimizes and emits objects directly, with loop and SLP
vectorization at -O2/-O3. Native linking uses a C driver; freestanding
linking uses lld, and UEFI linking lld's COFF linker. JIHOO_BACKEND=clang selects the previous backend for
comparison. Backend benchmarks
compare compilation time and generated program speed.
Compilation baselines
measure checking and full compilation of the compiler and compile-time
generation workloads, with elapsed time and peak memory, and compare them
with a recorded report.
The compiler is written in jihoo, in compiler/, and
self-hosted: the compiler of the latest
release builds it, and it builds itself to the same LLVM IR. There is no
Rust left; the Rust compiler that first bootstrapped it is in the history
up to v0.1.1.
Errors come several per run, in source order, with notes on where a moved value went and where a conflicting borrow started.
jihoo check
checks types, moves, borrows and compile-time obligations without generating
code or requiring LLVM or a linker. --lib checks modules without main.
--error-format=json reports source errors with byte ranges and related
notes for editor integration, and every other failure (usage, files, the
backend and linker) in the same document; text remains the default.
jihoo fmt formats
source files while preserving comments, literals and meaningful line breaks.
Long argument, parameter and field lists wrap at a soft width of 100 byte
columns; --width N adjusts it. --check checks layout without printing
formatted source and --write rewrites files, including every .jh file in
the directories given. The output is reparsed and must retain the same syntax tree.
jihoo lsp is a language
server built on the same checking and diagnostics: errors in unsaved
documents, go to definition and formatting.
Next (roadmap): application-driven library work.