Show HN: Rux – A Programming Language Built Without LLVM

musicvano1 pts0 comments

Programming Language Without LLVM | Rux Programming Language

Skip to content

Appearance

MenuReturn to top

Programming Language Without LLVM ​<br>We've been building a compiled, systems-capable programming language called Rux and just cut the 0.2.2 release. We'd love to get feedback from developers, especially from people who've thought hard about language design and compiler architecture.<br>What is Rux? ​<br>Rux is a fast, compiled, strongly typed, multi-paradigm general-purpose language. The compiler is written from scratch in C++26, with no LLVM backend — it has its own pipeline from source all the way to native binaries via a custom object file format (RCU) and linker.<br>The full pipeline looks like this:<br>Source → Lexer → Parser → AST → Sema → HIR → LIR → ASM → RCU → Linker → Native Binary<br>Every stage is dumpable (--dump-tokens, --dump-ast, --dump-sema, --dump-hir, --dump-lir, --dump-asm, --dump-rcu) which has been invaluable for debugging and understanding what the compiler is actually doing at each step.<br>The Language ​<br>Rux sits somewhere between Rust and a hypothetical "what if C had a modern redesign". The syntax leans toward clarity and ergonomics without sacrificing control.<br>A minimal example:<br>ruximport Std::Io::PrintLine;

func Main() -> int {<br>let a = 10;<br>let b = 20;<br>PrintLine("{} + {} = {}", a, b, a + b);<br>return 0;<br>A more representative one:<br>ruxmodule Geom {<br>struct Vec2 {<br>x: float64;<br>y: float64;

extend Vec2 {<br>func *(self, other: Vec2) -> float64 {<br>return self.x * other.x + self.y * other.y;

interface Shape {<br>func Area(self) -> float64;<br>func Perimeter(self) -> float64;<br>Type system ​<br>Primitive integers: int8, int16, int32, int64, uint8 ... uint64<br>Floats: float32, float64<br>Booleans: bool8, bool16, bool32<br>Composite types: struct, enum (sum types), union, tuples (T, U, V)<br>Slices: T[] for variable-length, T[N] for fixed-size arrays<br>Pointers: *T<br>Type aliases: type Name = OtherType<br>Interfaces for structural contracts + vtable dispatch<br>extend blocks for adding methods to any type (including external ones)<br>Generics via type parameters<br>Control flow ​<br>The usual suspects — if/else, for/in, while, do-while, loop, break/continue with optional labels, match with pattern matching (wildcards, literals, ranges, enum destructuring, struct patterns, guarded arms).<br>Calling conventions ​<br>Functions can specify Win64 vs System V AMD64 ABI. The extern keyword handles FFI with DLL imports, variadic functions, and extern variables.<br>Attributes ​<br>Rux uses a @[...] syntax for annotations:<br>rux@[Target("Linux")]<br>func Path(x: int32) -> String {<br>// implementation

@[Import(lib: "kernel32.dll")]<br>extern func Beep(freq: uint32, duration: uint32) -> bool32;

@[Deprecated("Use NewFunc instead")]<br>func OldFunc() {<br>// implementation<br>PascalCase names, @ is not address-of (& is).<br>Inline Assembly ​<br>Designed for systems programming, Rux has first-class inline asm:<br>ruxasm func ReadCr3() -> uint64 {<br>mov rax, cr3<br>ret<br>Register names and mnemonics are lowercase (consistent with GAS/LLVM conventions, as opposed to older MASM uppercase style).<br>The Compiler Internals ​<br>A few things I'm particularly happy with:<br>Custom object format (RCU). Rather than emitting ELF/COFF directly, the compiler generates RCU (Rux Compilation Unit) files — a simple binary format that carries sections, symbols, relocations, source metadata, and a build hash. The linker then combines them into a native executable. This keeps the backend clean and gives full control over the object model.<br>HIR/LIR split. The HIR (High-level IR) is a typed tree that mirrors the source closely — it still has if, for, structs, interfaces, etc. The LIR (Low-level IR) flattens everything into basic blocks with explicit jumps and three-address instructions. This made implementing control flow and pattern matching much easier than trying to do both simultaneously.<br>No GC, no runtime. Rux compiles to bare metal. There's no garbage collector, no runtime library overhead. Memory management is manual (or will be — RAII/resource types are on the roadmap).<br>The assembly emitter targets x86-64 with NASM-compatible output (Intel syntax, System V AMD64 ABI). Register allocation is currently naive (everything spilled to the stack) — a proper allocator is next.<br>The Package Manager ​<br>Rux ships with a built-in package manager. Current commands:<br>shrux new name> [--bin | --lib] # scaffold a new project<br>rux build [--debug | --release] # compile<br>rux run # build + execute<br>rux install [package][@version] # add a dependency<br>rux uninstall [package] # remove a dependency<br>rux list [--global] # show installed packages<br>rux update [--global] # update to latest<br>rux add --path path> # add local dependency<br>Build stats are printed after every successful compile (files, lines, time per stage), which is surprisingly motivating.<br>Platform Support ​<br>As of current release:<br>FreeBSD x86-64<br>Linux x86-64<br>Windows x86-64<br>The compiler itself requires C++26 (Clang 19+, GCC 14+, MSVC 2022+) and CMake 4.2+.<br>What's Missing / Rough ​<br>Team will be...

language func dump programming compiler float64

Related Articles