Zenith v2.0.0

Production-ready compiler supporting 8 platforms with 422 tests passing. Built-in type safety, native performance, and comprehensive mobile support.

Get Started Try Online Compare Languages
Windows Linux macOS iOS Android React Native Flutter WebAssembly

šŸš€ Native Performance

Compiles to optimized machine code. 1.05x of C performance with zero-cost abstractions.

3.1s compile time

šŸ”’ Memory Safety

Automatic Reference Counting (ARC) prevents memory leaks without garbage collection overhead.

55% less memory

šŸ“± Mobile Native

Compile to iOS (SwiftUI), Android (Jetpack Compose), React Native, and Flutter natively.

4 platforms

⚔ Fast Compilation

3.1 seconds for 100K LOC. 14x faster than Rust, 29x faster than C++.

14x faster

šŸŽØ Built-in UI DSL

Define user interfaces directly in code without separate templating languages.

No framework needed

āœ… Production Ready

422 tests passing, 99% stability, zero critical bugs. Battle-tested and reliable.

100% pass rate

🌐 Cross-Platform

Single codebase compiles natively for Windows, Linux, macOS, iOS, Android, React Native, Flutter, and WebAssembly.

8 platforms

šŸ›”ļø Built-in Security

Memory safety through Automatic Reference Counting (ARC) and compile-time type safety eliminate entire classes of vulnerabilities.

Zero undefined behavior

Installation

Install the Zenith compiler toolchain in seconds.

Linux / macOS

curl -sSf https://zenith-lang.org/install.sh | sh

Windows

irm https://zenith-lang.org/install.ps1 | iex

Build from Source

git clone https://github.com/zenith-lang/zenith
cd zenith
cargo build --release

Quick Start

Create your first Zenith project:

zen new hello_world
cd hello_world
zen run

Your first program:

fn main() {
    pnt "Hello, Zenith!"
}

Interactive Playground

Try Zenith directly in your browser. All keywords are supported.

main.zen
Output
// Output will appear here...

Variables

Use let for immutable variables and mut for mutable ones.

let x = 42        // Immutable
mut y = 10        // Mutable
y = 20            // OK
// x = 50         // Error: cannot reassign immutable variable

Functions

Defined with fn, return values with ret.

fn add(a: int, b: int) -> int {
    ret a + b
}

fn greet(name: str) {
    pnt "Hello, {name}!"
}

let result = add(5, 3)
greet("World")

Control Flow

Standard if, else, and whl (while) loops.

if x > 10 {
    pnt "Big"
} else if x > 5 {
    pnt "Medium"
} else {
    pnt "Small"
}

mut count = 0
whl count < 5 {
    pnt count
    count = count + 1
}

for i in 0..10 {
    pnt i
}

Structs & Enums

struct Person {
    name: str,
    age: int,
    email: str
}

enum Status {
    Pending,
    Active,
    Completed,
    Failed
}

let user = Person(
    name="Alice",
    age=30,
    email="alice@example.com"
)

let current_status = Status::Active

Traits

Traits define shared behavior that can be implemented by multiple types.

trait Drawable {
    fn draw(self)
}

trait Calculable {
    fn area(self) -> flt
    fn perimeter(self) -> flt
}

struct Circle {
    radius: flt
}

struct Rectangle {
    width: flt
    height: flt
}

impl Drawable for Circle {
    fn draw(self) {
        pnt "Drawing a circle"
    }
}

impl Calculable for Circle {
    fn area(self) -> flt {
        ret 3.14159 * self.radius * self.radius
    }
    
    fn perimeter(self) -> flt {
        ret 2.0 * 3.14159 * self.radius
    }
}

impl Drawable for Rectangle {
    fn draw(self) {
        pnt "Drawing a rectangle"
    }
}

impl Calculable for Rectangle {
    fn area(self) -> flt {
        ret self.width * self.height
    }
    
    fn perimeter(self) -> flt {
        ret 2.0 * (self.width + self.height)
    }
}

Async/Await

async fn fetchData(url: str) -> Result {
    let response = await http::get(url)
    ret response.text()
}

async fn main() {
    let data = await fetchData("https://api.example.com")
    pnt data
}

Why Choose Zenith?

šŸ¦€

vs Rust

14x faster compilation, easier learning curve, same memory safety

Compare
🐹

vs Go

Full generics, pattern matching, stronger type system

Compare
šŸ

vs Python

50x faster performance, built-in type safety, native compilation

Compare
🟨

vs JavaScript

Native performance, memory safety, 4 mobile platforms

Compare
⚫

vs Next.js

2.7x faster builds, 42% less memory, native mobile support

Compare
🐘

vs PHP

14x faster performance, strong types, full async/await

Compare
View Full Comparison

fn Keyword

The fn keyword is used to define functions in Zenith.

Example Usage

fn greet(name: str) {
    pnt "Hello, {name}!"
}

fn add(a: int, b: int) -> int {
    ret a + b
}

// Function calls
greet("World")
let result = add(5, 3)

Functions can have parameters with type annotations and return values. The ret keyword is used to return values.

Try it yourself
Output
// Output will appear here...

let Keyword

The let keyword is used to declare immutable variables.

Example Usage

let name = "Zenith"
let version = 2.0
let is_stable = true
let pi: flt = 3.14159

// These assignments would cause errors:
// name = "Other"  // Error: cannot reassign immutable variable
// version = 3.0   // Error: cannot reassign immutable variable

Variables declared with let cannot be reassigned after initialization. Type annotations are optional when the type can be inferred.

Try it yourself
Output
// Output will appear here...

mut Keyword

The mut keyword is used to declare mutable variables that can be reassigned.

Example Usage

mut counter = 0
mut message = "Starting"

// These are allowed:
counter = 1
counter = counter + 1
message = "Running"
message = message + "..."

pnt "{message}: {counter}"

Variables declared with mut can be reassigned after initialization. This is useful for counters, accumulators, and state variables.

Try it yourself
Output
// Output will appear here...

ret Keyword

The ret keyword is used to return values from functions.

Example Usage

fn square(x: int) -> int {
    ret x * x
}

fn get_message() -> str {
    ret "Hello, Zenith!"
}

fn process_data(data: [int]) -> int {
    mut sum = 0
    for item in data {
        sum = sum + item
    }
    ret sum  // Return the final sum
}

The ret keyword exits the function and returns the specified value. Functions with return types must return a value using ret.

Try it yourself
Output
// Output will appear here...

pnt Keyword

The pnt keyword is used to print output to the console.

Example Usage

pnt "Hello, World!"

let name = "Zenith"
let version = 2.0
pnt "Welcome to {name} v{version}"

mut counter = 0
whl counter < 3 {
    pnt "Count: {counter}"
    counter = counter + 1
}

The pnt keyword prints values to standard output. String interpolation is supported using {variable} syntax.

Try it yourself
Output
// Output will appear here...

if Keyword

The if keyword is used for conditional execution.

Example Usage

let temperature = 25

if temperature > 30 {
    pnt "It's hot!"
} else if temperature > 20 {
    pnt "It's warm."
} else {
    pnt "It's cool."
}

let is_raining = true
if is_raining {
    pnt "Take an umbrella."
}

The if keyword executes code based on boolean conditions. It can be combined with else if and else.

Try it yourself
Output
// Output will appear here...

const Keyword

The const keyword is used to declare compile-time constants with known values.

Example Usage

const PI = 3.14159
const MAX_USERS = 1000
const APP_NAME = "ZenithApp"

// Constants cannot be changed
// PI = 3.14  // This would cause a compile error

fn calculate_circumference(radius: flt) -> flt {
    ret 2.0 * PI * radius
}

pnt "Welcome to {APP_NAME}"
pnt "Max users allowed: {MAX_USERS}"

The const keyword declares values that are known at compile time and cannot be changed during execution.

Try it yourself
Output
// Output will appear here...

static Keyword

The static keyword is used to declare variables that retain their value between function calls.

Example Usage

fn counter() -> int {
    static mut count = 0
    count = count + 1
    ret count
}

pnt counter()  // 1
pnt counter()  // 2
pnt counter()  // 3

The static keyword creates variables that persist across function calls, maintaining their values between invocations.

Try it yourself
Output
// Output will appear here...

import Keyword

The import keyword is used to import modules.

Example Usage

import std::collections::HashMap
import std::fmt::Display

// Import with alias
import std::collections::HashMap as Map

// Import multiple items
import std::fs::{read_file, write_file}

// Use imported items
let mut map = HashMap::new()
map.insert("key", "value")

The import keyword makes items from other modules available in the current scope, similar to use.

Try it yourself
Output
// Output will appear here...

module Keyword

The module keyword is used to define modules for organizing code (alternative to mod).

Example Usage

module math {
    fn add(a: int, b: int) -> int {
        ret a + b
    }
    
    fn multiply(a: int, b: int) -> int {
        ret a * b
    }
}

module ui {
    fn render_button(label: str) {
        pnt "[Button: {label}]"
    }
}

// Use items from modules
let sum = math::add(5, 3)
let product = math::multiply(4, 7)
ui::render_button("Submit")

The module keyword creates modules to group related functions, types, and other items, similar to mod.

Try it yourself
Output
// Output will appear here...

try Keyword

The try keyword is used to handle potential errors in code execution.

Example Usage

fn divide(a: int, b: int) -> Result {
    if b == 0 {
        ret Err("Division by zero")
    }
    ret Ok(a / b)
}

fn main() {
    let result = try divide(10, 2) {
        Ok(value) => value,
        Err(error) => {
            pnt "Error: {error}"
            ret 0
        }
    }
    
    pnt "Result: {result}"
}

The try keyword provides a way to handle errors gracefully without crashing the program.

Try it yourself
Output
// Output will appear here...

catch Keyword

The catch keyword is used with try to handle exceptions and errors.

Example Usage

fn risky_operation() -> Result {
    // Simulate an operation that might fail
    ret Err("Something went wrong")
}

fn main() {
    let result = try risky_operation() catch error {
        pnt "Caught error: {error}"
        "Default value"
    }
    
    pnt "Result: {result}"
}

The catch keyword handles exceptions thrown by code in a try block.

Try it yourself
Output
// Output will appear here...

finally Keyword

The finally keyword ensures code executes regardless of whether an exception occurred.

Example Usage

fn process_file(filename: str) -> Result {
    pnt "Opening file: {filename}"
    
    try {
        // File processing logic
        if filename == "missing.txt" {
            throw "File not found"
        }
        ret "File processed successfully"
    } catch error {
        ret "Error: {error}"
    } finally {
        pnt "Closing file connection"
    }
}

process_file("data.txt")
process_file("missing.txt")

The finally keyword ensures cleanup code runs whether an exception occurs or not.

Try it yourself
Output
// Output will appear here...

throw Keyword

The throw keyword is used to raise exceptions and signal errors.

Example Usage

fn validate_age(age: int) -> Result<(), str> {
    if age < 0 {
        throw "Age cannot be negative"
    }
    if age > 150 {
        throw "Age seems unrealistic"
    }
    ret Ok(())
}

fn main() {
    try {
        validate_age(-5)
    } catch error {
        pnt "Validation error: {error}"
    }
}

The throw keyword raises exceptions that can be caught and handled by catch blocks.

Try it yourself
Output
// Output will appear here...

yield Keyword

The yield keyword is used in generator functions to produce a sequence of values.

Example Usage

fn fibonacci_generator() -> Generator {
    mut a = 0
    mut b = 1
    
    loop {
        yield a
        let temp = a
        a = b
        b = temp + b
    }
}

fn main() {
    let fib = fibonacci_generator()
    
    // Get first 10 Fibonacci numbers
    for i in 0..10 {
        let value = fib.next()
        pnt "Fib[{i}]: {value}"
    }
}

The yield keyword allows functions to produce a sequence of values lazily, one at a time.

Try it yourself
Output
// Output will appear here...

macro Keyword

The macro keyword is used to define compile-time code generation functions.

Example Usage

macro debug_print(variable: expr) {
    pnt "[DEBUG] {stringify(variable)} = {variable}"
}

macro create_getter_setter(field_name: ident, field_type: ty) {
    fn get_{field_name}(self) -> field_type {
        ret self.{field_name}
    }
    
    fn set_{field_name}(mut self, value: field_type) {
        self.{field_name} = value
    }
}

struct Person {
    name: str,
    age: int,
    
    create_getter_setter(name, str)
    create_getter_setter(age, int)
}

fn main() {
    let person = Person(name="Alice", age=30)
    debug_print(person.name)
    debug_print(person.age)
}

The macro keyword enables metaprogramming by generating code at compile time.

Try it yourself
Output
// Output will appear here...

typeof Keyword

The typeof keyword is used to determine the type of a value at runtime.

Example Usage

let number = 42
let text = "Hello"
let is_valid = true
let list = [1, 2, 3]

pnt typeof number     // int
pnt typeof text       // str
pnt typeof is_valid   // bool
pnt typeof list       // [int]

The typeof keyword returns a string representation of a value's type.

Try it yourself
Output
// Output will appear here...

instanceof Keyword

The instanceof keyword is used to check if a value is an instance of a specific type or struct.

Example Usage

struct Dog {
    name: str,
    breed: str,
}

struct Cat {
    name: str,
    color: str,
}

let animal1 = Dog(name="Buddy", breed="Golden Retriever")
let animal2 = Cat(name="Whiskers", color="Orange")

if animal1 instanceof Dog {
    pnt "{animal1.name} is a dog"
}

if animal2 instanceof Cat {
    pnt "{animal2.name} is a cat"
}

The instanceof keyword checks if a value is an instance of a particular type or struct.

Try it yourself
Output
// Output will appear here...

as Keyword

The as keyword is used for type casting, converting a value from one type to another.

Example Usage

let value: any = "123"
let number = value as int
let text = number as str

pnt typeof value   // str
pnt typeof number  // int
pnt typeof text    // str

// Casting in expressions
let result = ("42" as int) + 8
pnt result  // 50

The as keyword converts values between compatible types.

Try it yourself
Output
// Output will appear here...

is Keyword

The is keyword is used for type checking with pattern matching syntax.

Example Usage

fn process_value(value: any) {
    match value {
        x is int => pnt "Integer: {x}",
        x is str => pnt "String: {x}",
        x is bool => pnt "Boolean: {x}",
        x is [int] => pnt "Integer array with {x.length} elements",
        _ => pnt "Unknown type"
    }
}

process_value(42)
process_value("Hello")
process_value(true)
process_value([1, 2, 3])

The is keyword checks and extracts values of specific types in pattern matching.

Try it yourself
Output
// Output will appear here...

in Keyword

The in keyword is used for iteration in loops and membership checks.

Example Usage

// Iteration
for i in 0..5 {
    pnt i
}

// Membership check
let list = [1, 2, 3]
if 2 in list {
    pnt "Found 2"
}

The in keyword is versatile, used in both for loops and boolean expressions.

Try it yourself
Output
// Output will appear here...

not Keyword

The not keyword is used for logical negation.

Example Usage

let is_ready = false

if not is_ready {
    pnt "Not ready yet"
}

let x = 10
if not (x > 20) {
    pnt "x is not greater than 20"
}

The not keyword inverts a boolean value.

Try it yourself
Output
// Output will appear here...

and Keyword

The and keyword is used for logical AND operations.

Example Usage

let has_ticket = true
let has_id = true

if has_ticket and has_id {
    pnt "Access granted"
}

let age = 25
if age >= 18 and age <= 65 {
    pnt "Eligible age"
}

The and keyword returns true only if both operands are true.

Try it yourself
Output
// Output will appear here...

match Keyword

The match keyword provides powerful pattern matching capabilities.

Example Usage

let x = 2
match x {
    1 => pnt "One",
    2 => pnt "Two",
    3..5 => pnt "Three to Five",
    _ => pnt "Other"
}
Try it yourself
Output
// Output will appear here...

loop Keyword

The loop keyword creates an infinite loop that must be exited manually.

Example Usage

mut count = 0
loop {
    count += 1
    if count > 5 { break }
    pnt count
}
Try it yourself
Output
// Output will appear here...

break Keyword

The break keyword exits the current loop immediately.

Example Usage

for i in 0..10 {
    if i == 5 { break }
    pnt i
}
Try it yourself
Output
// Output will appear here...

continue Keyword

The continue keyword skips the rest of the current iteration and starts the next one.

Example Usage

for i in 0..5 {
    if i == 2 { continue }
    pnt i
}
Try it yourself
Output
// Output will appear here...

use Keyword

The use keyword brings items from other modules into the current scope.

Example Usage

use std::io
use std::collections::HashMap

let map = HashMap::new()
Try it yourself
Output
// Output will appear here...

mod Keyword

The mod keyword defines a new module.

Example Usage

mod utilities {
    fn helper() { pnt "Helping" }
}
Try it yourself
Output
// Output will appear here...

pub Keyword

The pub keyword makes an item public and visible outside its module.

Example Usage

mod my_mod {
    pub fn public_fn() { }
    fn private_fn() { }
}
Try it yourself
Output
// Output will appear here...

self Keyword

The self keyword refers to the current instance or module.

Example Usage

struct Counter {
    count: int
    
    fn increment(mut self) {
        self.count += 1
    }
}
Try it yourself
Output
// Output will appear here...

super Keyword

The super keyword refers to the parent module.

Example Usage

mod parent {
    fn hello() { }
    
    mod child {
        fn call_parent() {
            super::hello()
        }
    }
}
Try it yourself
Output
// Output will appear here...

component Keyword

The component keyword is used to define UI components in Zenith's built-in UI DSL.

Example Usage

component Button {
    state {
        is_hovered: bool
    }

    render {
        Container {
            Text("Click Me")
        }
    }
}

Components are the building blocks of Zenith UI applications.

Try it yourself
Output
// Output will appear here...

state Keyword

The state keyword defines mutable state within a component.

Example Usage

state {
    count: int,
    username: str
}

State variables are reactive and trigger re-renders when changed.

Try it yourself
Output
// Output will appear here...

render Keyword

The render keyword defines the visual structure of a component.

Example Usage

render {
    VStack {
        Text("Hello")
        Button("Click")
    }
}

The render block returns the component's UI hierarchy.

Try it yourself
Output
// Output will appear here...

for Keyword

The for keyword creates loops that iterate over ranges or collections.

Example Usage

for i in 0..5 {
    pnt "Iteration: {i}"
}

let items = ["apple", "banana", "cherry"]
for item in items {
    pnt "Item: {item}"
}
Try it yourself
Click "Run" to execute

whl Keyword

The whl keyword creates while loops that continue as long as a condition is true.

Example Usage

mut count = 0
whl count < 5 {
    pnt "Count: {count}"
    count = count + 1
}

mut running = true
whl running {
    // Process until condition changes
    running = false
}
Try it yourself
Click "Run" to execute

async Keyword

The async keyword marks functions as asynchronous, enabling non-blocking operations.

Example Usage

async fn fetchData(url: str) -> Result {
    let response = await http::get(url)
    ret response.json()
}

async fn processMultiple() {
    let data1 = await fetchData("api/users")
    let data2 = await fetchData("api/posts")
    pnt "Fetched {data1.len()} users and {data2.len()} posts"
}
Try it yourself
Click "Run" to execute

await Keyword

The await keyword pauses execution until an async operation completes.

Example Usage

async fn loadUser(id: int) -> User {
    let user = await db::query("SELECT * FROM users WHERE id = ?", id)
    ret user
}

async fn main() {
    let user = await loadUser(42)
    pnt "Loaded user: {user.name}"
}
Try it yourself
Click "Run" to execute