Architecture
jihoo aims to be an easy language that can still go all the way down to bare syscalls. One surface language is lowered to one IR, JIR; that IR is either run by a VM or compiled by LLVM.
┌─────────────── Rust ───────────────┐ ┌──── C++ ─────┐ source.jh ──► │ jihoo-syntax ─► jihoo-sema ──► JIR │ ──► │ jihoo-llc │ ──► .o ─┬─► cc + libc ──► program (native) │ (parse) (typecheck │ │ .jir │ (LLVM 21) │ └─► ld.lld ─────► static ELF (freestanding) │ + lower) ▼ │ └──────────────┘ │ jihoo-vm│ └────────────────────────────────────┘Components
Section titled “Components”| path | language | what |
|---|---|---|
crates/jihoo-syntax |
Rust | lexer, parser, AST, and the module loader |
crates/jihoo-sema |
Rust | type checking and lowering from the AST to JIR, compile-time evaluation, macros |
crates/jihoo-ir |
Rust | JIR data types, the text printer and reader, layouts, the verifier |
crates/jihoo-vm |
Rust | the register VM, its task scheduler and the GC heap |
crates/jihoo-cli |
Rust | the jihoo command |
backend-llvm |
C++ | jihoo-llc: JIR text → LLVM → object file |
lib |
jihoo | the standard library |
tests/diff |
jihoo | programs that must behave the same on the VM and natively |
site |
Astro | this website |
A program’s way through
Section titled “A program’s way through”- Load (
crates/jihoo-syntax/src/loader.rs). The root file and every file it imports, transitively, are parsed into one AST per module. Each file is loaded once; positions carry a file number, so errors name the right file. The target (x86_64 or aarch64 Linux) matters only here:import aprefersa.<target>.jhtoa.jh, so the rest of the compiler only ever sees the target’s files. The target is then recorded in the JIR for the backend. - Analyze (
crates/jihoo-sema). Item macros are expanded, then every function is type checked and lowered to typed JIR in one pass, generic ones once per instance. Constants,comptimeexpressions and macros run on the VM along the way. See Compiler. - Verify (
crates/jihoo-ir/src/verify.rs). The JIR module is checked on its own: register types, operand types, terminators, and that the profile allows every instruction. This catches frontend bugs before a backend sees them. - Run or compile. A native module (the default) or a freestanding one is
printed as text, compiled by
jihoo-llc(LLVM backend) and linked byjihoo build(whichjihoo runuses, then runs the result). A hosted module runs on the VM (VM and GC).
Why the IR is a text file
Section titled “Why the IR is a text file”The frontend (Rust) and the LLVM backend (C++) only talk through .jir files
(JIR). This keeps the IR an explicit, versioned contract
(Versions), lets the backend be developed and tested on
its own with hand-written .jir (Testing), and
keeps the Rust build free of LLVM. jihoo reads .jir files back too
(crates/jihoo-ir/src/parse.rs), so a module written once can be run on the VM
or built natively without its source.
Shared rules
Section titled “Shared rules”The typing rules of operators live once, in crates/jihoo-ir/src/types.rs, and
are used both by the type checker and by the IR verifier, so the two cannot
disagree. The C layout rules (crates/jihoo-ir/src/layout.rs) are recorded in
JIR and checked again by the backend against the real target.