A statically-typed, compiled programming language that transpiles to portable C11.
Safe. Simple. Fast.
Quick Start • Features • Documentation • Examples • Roadmap
URUS is a statically-typed programming language that compiles to standard C11. It aims to provide the safety guarantees of modern languages while producing code that runs anywhere a C compiler runs.
The compiler is a single-pass transpiler written in C. It reads .urus source files, performs lexing, parsing, semantic analysis, and emits portable C11 code. The generated C is then compiled to a native binary using GCC, Clang, or any C11-compliant compiler.
| Goal | How |
|---|---|
| Safer than C | RAII memory management, bounds checking, immutable by default |
| Simpler than Rust | No borrow checker, no lifetimes — straightforward ownership model |
| Faster than Python | Compiles to native binary via C11 |
| Portable | Transpiles to standard C11 — runs anywhere GCC/Clang runs |
| Modern syntax | Enums, pattern matching, string interpolation, Result types, tuples, macros |
- CMake 3.10+
- C compiler: GCC 8+, Clang, or MSVC (for building the compiler)
- GCC 8+ or compatible C11 compiler (for compiling generated code)
git clone https://github.com/Urus-Foundation/Urus.git
cd Urus/compiler
cmake -S . -B build
cmake --build buildOn Termux:
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=$PREFIX
cmake --build build# Linux / macOS / Termux
sudo cmake --install build
# Windows (Run as Administrator)
cmake --install buildfn main(): void {
print("Hello, World!");
}urusc hello.urus -o hello
./hello
# Hello, World!Tip
Having trouble? Open an issue on the issue tracker.
| Type | Description | C Equivalent |
|---|---|---|
int |
64-bit signed integer | int64_t |
float |
64-bit floating point | double |
bool |
Boolean (true / false) |
bool |
str |
UTF-8 string (heap-allocated) | urus_str* |
void |
No value | void |
[T] |
Dynamic array of T | urus_array* |
(T1, T2) |
Tuple (stack-allocated) | struct { T1 f0; T2 f1; } |
Result<T, E> |
Ok or Err value | urus_result* |
let x: int = 10; // immutable
let mut count: int = 0; // mutable
count += 1;
// Type inference
let name = "hello"; // inferred as str
let pi = 3.14; // inferred as floatconst MAX_SIZE: int = 100;
const PI: float = 3.14159;
const APP_NAME: str = "MyApp";type ID = int;
type Name = str;
type Numbers = [int];
fn greet(id: ID, name: Name): void {
print(f"User {id}: {name}");
}fn add(a: int, b: int): int {
return a + b;
}
// Default parameter values
fn greet(name: str = "World"): void {
print(f"Hello {name}!");
}
// Mutable parameters
fn increment(mut x: int): int {
x += 1;
return x;
}let t: (int, str) = (42, "hello");
print(t.0); // 42
print(t.1); // hello
// Destructuring
let (x, y) = get_pair();
// In for-each loops
let pairs: [(int, str)] = [(1, "a"), (2, "b")];
for (k, v) in pairs {
print(f"{k}: {v}");
}rune square(x) { x * x }
rune max(a, b) { if a > b { a } else { b } }
fn main(): void {
print(square!(5)); // 25
print(max!(10, 20)); // 20
}let label = if x > 5 { "big" } else { "small" };
print(if x > 0 { "positive" } else { "negative" });// If / Else
if x > 10 {
print("big");
} else if x > 5 {
print("medium");
} else {
print("small");
}
// While
while x < 100 {
x += 1;
}
// Do-While
do {
x += 1;
} while x < 100;
// For (range, exclusive)
for i in 0..10 {
print(i);
}
// For (range, inclusive)
for i in 0..=10 {
print(i);
}
// For-each
let names: [str] = ["Alice", "Bob"];
for name in names {
print(name);
}struct Point {
x: float;
y: float;
}
fn distance(a: Point, b: Point): float {
let dx: float = a.x - b.x;
let dy: float = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}enum Shape {
Circle(r: float);
Rect(w: float, h: float);
Point;
}
fn area(s: Shape): float {
match s {
Shape.Circle(r) => {
return 3.14159 * r * r;
}
Shape.Rect(w, h) => {
return w * h;
}
Shape.Point => {
return 0.0;
}
}
return 0.0;
}Match also works with primitive types:
fn describe(n: int): void {
match n {
0 => { print("zero"); }
1 => { print("one"); }
_ => { print("other"); }
}
}
fn greet(lang: str): void {
match lang {
"en" => { print("Hello!"); }
"id" => { print("Halo!"); }
_ => { print("..."); }
}
}fn process(): void {
print("start");
defer { print("cleanup"); }
print("working");
// "cleanup" runs automatically at end of function
}Defer bodies execute in LIFO order and run before every return path.
let name: str = "World";
let count: int = 42;
print(f"Hello {name}! Answer: {count}");let nums: [int] = [1, 2, 3, 4, 5];
let first: int = nums[0];
let mut items: [int] = [];
push(items, 42);
print(f"Length: {len(items)}");
// Method-call syntax
items.push(10);
print(items.len());let s: str = " Hello World ";
print(s.trim()); // "Hello World"
print(s.upper()); // " HELLO WORLD "
print(s.lower()); // " hello world "
print(s.contains("World")); // true
print(s.len()); // 15// math_utils.urus
fn square(x: int): int {
return x * x;
}
// main.urus
import "math_utils.urus";
fn main(): void {
print(f"5^2 = {square(5)}");
}fn divide(a: int, b: int): Result<int, str> {
if b == 0 {
return Err("division by zero");
}
return Ok(a / b);
}
fn main(): void {
let r: Result<int, str> = divide(10, 0);
if is_err(r) {
print(f"Error: {unwrap_err(r)}");
} else {
print(f"Result: {unwrap(r)}");
}
}| Category | Operators |
|---|---|
| Arithmetic | +, -, *, /, % |
| Exponent | ** |
| Comparison | ==, !=, <, >, <=, >= |
| Logical | &&, ||, ! |
| Bitwise | &, |, ^, ~, <<, >>, &~ |
| Assignment | =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>= |
| Increment/Decrement | ++, -- |
| String concat | + |
| Floored remainder | %% |
| Function | Description |
|---|---|
print(value) |
Print to stdout with newline |
input() |
Read one line from stdin |
read_file(path) |
Read file contents as string |
write_file(path, s) |
Write string to file |
append_file(path, s) |
Append string to file |
| Function | Description |
|---|---|
len(array) |
Array length |
push(array, v) |
Append to array |
pop(array) |
Remove last element |
| Function | Description |
|---|---|
str_len(s) |
String length |
str_upper(s) / s.upper() |
Uppercase |
str_lower(s) / s.lower() |
Lowercase |
str_trim(s) / s.trim() |
Trim whitespace |
str_contains(s, sub) / s.contains(sub) |
Check substring |
str_find(s, sub) / s.find(sub) |
Find index of substring |
str_slice(s, a, b) / s.slice(a, b) |
Substring |
str_replace(s, old, new) / s.replace(old, new) |
Replace occurrences |
str_starts_with(s, p) / s.starts_with(p) |
Check prefix |
str_ends_with(s, p) / s.ends_with(p) |
Check suffix |
str_split(s, d) / s.split(d) |
Split into array |
char_at(s, i) / s.char_at(i) |
Character at index |
| Function | Description |
|---|---|
to_str(value) |
Convert to string |
to_int(value) |
Convert to int |
to_float(value) |
Convert to float |
| Function | Description |
|---|---|
abs(x) / fabs(x) |
Absolute value |
sqrt(x) |
Square root |
pow(x, y) |
Power |
min(a, b) / max(a, b) |
Min/max (int) |
fmin(a, b) / fmax(a, b) |
Min/max (float) |
| Function | Description |
|---|---|
is_ok(r) |
Check if Ok |
is_err(r) |
Check if Err |
unwrap(r) |
Extract Ok value (aborts on Err) |
unwrap_err(r) |
Extract Err message (aborts on Ok) |
| Function | Description |
|---|---|
http_get(url) |
HTTP GET request, returns response body |
http_post(url, body) |
HTTP POST request, returns response body |
Requires
curlto be available on the system.
| Function | Description |
|---|---|
exit(code) |
Exit program |
assert(cond, msg) |
Abort if condition is false |
URUS Compiler, version 0.3.0
Usage: urusc <file.urus> [options]
Options:
--help Show help message
--version Show compiler version
--tokens Display lexer tokens
--ast Display the AST
--emit-c Print generated C code to stdout
-o <file> Output executable name (default: a.exe / a.out)
Example:
urusc main.urus -o app
Source (.urus)
|
v
[ Lexer ] Tokenize source code
|
v
[ Preprocessor ] Expand imports and rune macros
|
v
[ Parser ] Build Abstract Syntax Tree
|
v
[ Sema ] Type checking and semantic analysis
|
v
[ Codegen ] Generate standard C11 code
|
v
[ GCC/Clang ] Compile to native binary
|
v
Executable
Urus/
├── compiler/
│ ├── src/ # Compiler implementation
│ │ ├── main.c # CLI entry point
│ │ ├── lexer.c # Tokenizer
│ │ ├── parser.c # Recursive descent parser
│ │ ├── codegen.c # C11 code generator
│ │ ├── ast.c # AST constructors and utilities
│ │ ├── preprocess.c # Import resolution and rune expansion
│ │ ├── error.c # Error/warning reporting
│ │ ├── util.c # File and string utilities
│ │ └── Sema/ # Semantic analysis
│ │ ├── sema.c # Type checking and validation
│ │ ├── builtins.c # Built-in function signatures
│ │ └── scope.c # Scope and symbol table
│ ├── include/ # Public headers
│ ├── runtime/ # Embedded runtime library
│ │ └── urus_runtime.h # Header-only runtime (strings, arrays, etc.)
│ ├── stdlib/ # Standard library modules (.urus)
│ └── CMakeLists.txt # Build configuration
├── examples/ # Sample programs
├── tests/ # Test suite
│ └── run/ # Integration tests (.urus + .expected)
├── documentation/ # Extended documentation
├── SPEC.md # Language specification
├── CONTRIBUTING.md # Contribution guide
├── SECURITY.md # Security policy
├── CODE_OF_CONDUCT.md # Community guidelines
├── CHANGELOG.md # Version history
├── Dockerfile # Containerized build
└── LICENSE # Apache 2.0
| Metric | Value |
|---|---|
| Version | 0.3.0 |
| Compiler LOC | ~7,100+ |
| Runtime LOC | ~540 |
| Test files | 33 |
| Output | C11 compliant |
| Platforms | Windows, Linux, macOS, Termux |
| Build system | CMake 3.10+ |
| Dependencies | C11 compiler only |
cd compiler/build # Make sure you're in the build directories
ctest # Run all testsEach test consists of a .urus source file and a .expected file. The test runner compiles and runs the program, then compares the output against the expected file.
| Feature | URUS | C | Rust | Go | Python |
|---|---|---|---|---|---|
| Static typing | Yes | Yes | Yes | Yes | No |
| Memory safety | RAII + bounds | Manual | Ownership | GC | GC |
| Pattern matching | Yes | No | Yes | No | Limited |
| String interpolation | Yes | No | No | No | Yes |
| Result type | Yes | No | Yes | No | No |
| Null safety | Yes | No | Yes | No | No |
| Compiles to native | Yes | Yes | Yes | Yes | No |
| Learning curve | Low | Medium | High | Low | Low |
- Tuple types and destructuring
- Runes (macro system)
- If-expressions
- Type inference
- HTTP built-ins
- Constants (
const) - Type aliases (
type) - String and array method-call syntax
- Do-while loops
- Defer statements
- Extended pattern matching (int, str, bool)
- Bitwise and exponent operators
- Mutable function parameters
- Raw emit blocks
- Optional type (
Option<T>) - Generics (
fn max<T>(a: T, b: T): T) - Portable RAII (explicit drop insertion)
- Methods (
impl Point { fn distance() }) - Traits / Interfaces
- Closures
- Bundled TCC as default C backend
- Standard library
- Package manager
- Full documentation
- Production-ready
- Async/await
- Concurrency primitives
- WebAssembly target
- Self-hosting compiler
- LSP server for IDE support
URUS draws inspiration from:
- Rust — enums, pattern matching, Result type, immutability by default
- Go — simplicity, fast compilation, clean syntax
- Zig — transpile-to-C philosophy, minimal runtime
- Python — f-string interpolation, readability
We welcome contributions of all kinds. See CONTRIBUTING.md for the full guide.
1. Fork the repository
2. Create a feature branch
3. Make your changes and add tests
4. Submit a pull request
Licensed under the Apache License, Version 2.0. See LICENSE for the full text.
Have questions? Found a bug? Want to contribute? Join Our Whatsapp
![]() Rasya Andrean Founder & Lead |
![]() John-fried Co-Lead |
![]() Mulyawan-ts Developer |
![]() kkkfasya |
![]() fmway |
![]() fepfitra |
![]() lordpaijo |
![]() XBotzLauncher |
![]() aimardcr |
![]() billalxcode |
![]() devirtz |











