Skip to content

jihoo

An easy language that goes all the way down. Everyday code compiles into a native program that frees its own memory and calls C; run it on a garbage-collected VM instead, or drop libc too and build a tiny static binary that talks to the kernel itself.
hello.jh — native by default: jihoo run hello.jh
fn greet(name: str) -> str {
return "Hello, " + name + "!"
}
fn main() {
print(greet("jihoo"))
}
args.jh — calling C
import libc
fn main(argc: i32, argv: **u8) -> i64 {
libc.printf("%s got %d arguments\n", argv[0], argc - 1)
return 0
}
tiny.jh — no libc, no GC: a 3 KB static binary
#![freestanding]
fn _start() -> i64 {
syscall(1, 1, "hi\n", 3) // write(1, "hi\n", 3) on x86_64 Linux
return 0 // exit(0)
}

Three profiles, one IR

Programs are native: no GC, compiled by LLVM and linked with libc. #![hosted] ones run on a VM with a garbage collector; #![freestanding] ones have no libc either. All share one typed IR, and the test suite checks that they agree.

Compile-time everything

const, comptime and array lengths run ordinary functions on the VM while compiling, even for freestanding programs, and bake the results in.

Macros are just functions

A macro is a function that runs at compile time and returns code: an expression, statements, or whole functions and types.

Generics and modules

comptime T: type parameters, generic structs like Vec(T), and modules with import and pub, including a small standard library.

Down to the metal

Raw pointers, arrays, inline asm and syscall for compiled code, C functions through extern fn for native code, and an arena allocator and Vec(T) written in jihoo itself.

Built with Nix

nix run github:jihoo12/jihoo gives you the whole toolchain: the VM, the LLVM backend, the linkers and the standard library.