01 / hello.zi

Hello, World!

The smallest complete program.

main :: () {
    print("Hello, World!\n");
}
build/bin/ziran bundle --root . --entry hello:main -o hello.zib site/examples/hello.zi
build/bin/ziran run hello.zib
# Hello, World!

Download hello.zi ↓

02 / greet.zi

Print values

Each % in a print format takes the next argument, and %% prints a percent sign.

main :: () {
    name := "Ziran";
    year: s32 = 2026;
    print("Hello, %! It is %.\n", name, year);
    print("% + % = %\n", 40, 2, 40 + 2);
    print("pi is about %, and 100%% sure\n", 3.14159);
}
build/bin/ziran bundle --root . --entry greet:main -o greet.zib site/examples/greet.zi
build/bin/ziran run greet.zib
# Hello, Ziran! It is 2026.
# 40 + 2 = 42
# pi is about 3.14159, and 100% sure

Download greet.zi ↓

03 / values.zi

Values

Integers, floats, booleans, and text.

main :: () {
    print("text: %\n", "ziran");
    print("1 + 1 = %\n", 1 + 1);
    print("7.0 / 3.0 = %\n", 7.0 / 3.0);
    print("true and false: %\n", true && false);
    print("true or false: %\n", true || false);
    print("not true: %\n", !true);
}
build/bin/ziran bundle --root . --entry values:main -o values.zib site/examples/values.zi
build/bin/ziran run values.zib
# text: ziran
# 1 + 1 = 2
# 7.0 / 3.0 = 2.3333333333333335
# true and false: false
# true or false: true
# not true: false

Download values.zi ↓

04 / variables.zi

Variables and constants

A declared type, an inferred type, a default zero value, and a compile-time constant.

LIMIT :: 100;

main :: () {
    greeting: string = "initial";
    print("%\n", greeting);

    first: s32 = 1;
    second: s32 = 2;
    print("% %\n", first, second);

    ready := true;
    print("%\n", ready);

    count: s32;
    print("% (a variable starts at zero)\n", count);

    fruit := "apple";
    print("% and the limit is %\n", fruit, LIMIT);
}
build/bin/ziran bundle --root . --entry variables:main -o variables.zib site/examples/variables.zi
build/bin/ziran run variables.zib
# initial
# 1 2
# true
# 0 (a variable starts at zero)
# apple and the limit is 100

Download variables.zi ↓

05 / functions.zi

Functions

Plain calls, default and named arguments, and recursion.

Add :: (a: s32, b: s32) -> s32 {
    return a + b;
}

Greet :: (name: string, greeting: string = "Hello") {
    print("%, %!\n", greeting, name);
}

Factorial :: (n: s64) -> s64 {
    if n <= 1 { return 1; }
    return n * Factorial(n - 1);
}

Fibonacci :: (n: s32) -> s32 {
    if n < 2 { return n; }
    return Fibonacci(n - 1) + Fibonacci(n - 2);
}

main :: () {
    print("1 + 2 = %\n", Add(1, 2));
    Greet("Ziran");
    Greet("world", greeting = "Goodbye");
    print("10! = %\n", Factorial(10));
    print("fibonacci(20) = %\n", Fibonacci(20));
}
build/bin/ziran bundle --root . --entry functions:main -o functions.zib site/examples/functions.zi
build/bin/ziran run functions.zib
# 1 + 2 = 3
# Hello, Ziran!
# Goodbye, world!
# 10! = 3628800
# fibonacci(20) = 6765

Download functions.zi ↓

06 / conditions.zi

Conditions

If and else chains, and an if-case that picks a branch by value.

Describe :: (number: s32) -> string {
    if number < 0 {
        return "negative";
    } else if number == 0 {
        return "zero";
    }
    return "positive";
}

DayKind :: (day: s32) -> string {
    if day == {
        case 6; return "weekend";
        case 7; return "weekend";
    }
    return "weekday";
}

main :: () {
    print("-4 is %\n", Describe(-4));
    print("0 is %\n", Describe(0));
    print("9 is %\n", Describe(9));

    if 7 % 2 == 0 {
        print("7 is even\n");
    } else {
        print("7 is odd\n");
    }

    print("day 3 is a %\n", DayKind(3));
    print("day 6 is a %\n", DayKind(6));
}
build/bin/ziran bundle --root . --entry conditions:main -o conditions.zib site/examples/conditions.zi
build/bin/ziran run conditions.zib
# -4 is negative
# 0 is zero
# 9 is positive
# 7 is odd
# day 3 is a weekday
# day 6 is a weekend

Download conditions.zi ↓

07 / loops.zi

Loops

While, ranges, collections, break, and continue.

main :: () {
    index: s32 = 1;
    while index <= 3 {
        print("while %\n", index);
        index += 1;
    }

    for step: 0..2 {
        print("range %\n", step);
    }

    fruits := string.["apple", "banana", "cherry"];
    for fruit, position: fruits {
        print("% is at %\n", fruit, position);
    }

    for number: 0..9 {
        if number % 2 == 0 { continue; }
        if number > 7 { break; }
        print("odd %\n", number);
    }
}
build/bin/ziran bundle --root . --entry loops:main -o loops.zib site/examples/loops.zi
build/bin/ziran run loops.zib
# while 1
# while 2
# while 3
# range 0
# range 1
# range 2
# apple is at 0
# banana is at 1
# cherry is at 2
# odd 1
# odd 3
# odd 5
# odd 7

Download loops.zi ↓

08 / arrays.zi

Arrays and slices

A fixed array, a view into part of it, and a sum.

Sum :: (numbers: []s32) -> s32 {
    total: s32 = 0;
    for numbers { total += it; }
    return total;
}

main :: () {
    empty: [5]s32;
    print("empty: % % % % %\n", empty[0], empty[1], empty[2], empty[3], empty[4]);

    numbers := s32.[1, 2, 3, 4, 5];
    numbers[4] = 100;
    print("set: %, count: %\n", numbers[4], numbers.count);

    middle := numbers[1:4];
    print("middle has % items starting with %\n", middle.count, middle[0]);

    print("sum of all: %\n", Sum(numbers[:]));
    print("sum of middle: %\n", Sum(middle));
}
build/bin/ziran bundle --root . --entry arrays:main -o arrays.zib site/examples/arrays.zi
build/bin/ziran run arrays.zib
# empty: 0 0 0 0 0
# set: 100, count: 5
# middle has 3 items starting with 2
# sum of all: 110
# sum of middle: 9

Download arrays.zi ↓

09 / structs.zi

Structs

Records with fields, passed and returned by value.

Point :: struct {
    x: s32;
    y: s32;
}

Rectangle :: struct {
    origin: Point;
    width: s32;
    height: s32;
}

Area :: (shape: Rectangle) -> s32 {
    return shape.width * shape.height;
}

Grow :: (shape: Rectangle, amount: s32) -> Rectangle {
    grown := shape;
    grown.width += amount;
    grown.height += amount;
    return grown;
}

main :: () {
    corner := Point.{x = 3, y = 4};
    print("point: (%, %)\n", corner.x, corner.y);

    box := Rectangle.{origin = corner, width = 10, height = 5};
    print("area: %\n", Area(box));

    box = Grow(box, 2);
    print("grown: %x% with area %\n", box.width, box.height, Area(box));

    copy := box;
    copy.width = 1;
    print("the copy is % wide, the original still %\n", copy.width, box.width);
}
build/bin/ziran bundle --root . --entry structs:main -o structs.zib site/examples/structs.zi
build/bin/ziran run structs.zib
# point: (3, 4)
# area: 50
# grown: 12x7 with area 84
# the copy is 1 wide, the original still 12

Download structs.zi ↓

10 / enums.zi

Enums

Named values and a switch over them.

Shape :: enum {
    CIRCLE;
    SQUARE;
    TRIANGLE;
}

Corners :: (shape: Shape) -> s32 {
    if shape == {
        case .CIRCLE; return 0;
        case .SQUARE; return 4;
        case .TRIANGLE; return 3;
    }
    return -1;
}

main :: () {
    print("a circle has % corners\n", Corners(.CIRCLE));
    print("a square has % corners\n", Corners(.SQUARE));
    print("a triangle has % corners\n", Corners(.TRIANGLE));
}
build/bin/ziran bundle --root . --entry enums:main -o enums.zib site/examples/enums.zi
build/bin/ziran run enums.zib
# a circle has 0 corners
# a square has 4 corners
# a triangle has 3 corners

Download enums.zi ↓

11 / text_basics.zi

Strings

Length, bytes, slices, and comparison.

CountByte :: (text: string, wanted: u8) -> s32 {
    found: s32 = 0;
    for byte: text {
        if byte == wanted { found += 1; }
    }
    return found;
}

main :: () {
    word := "banana";
    print("% has % bytes\n", word, word.count);
    print("the first byte is %\n", word[0]);
    print("it contains % a's\n", CountByte(word, #char "a"));
    print("its middle is %\n", word[1:5]);
    print("equal to \"banana\": %\n", word == "banana");
    print("equal to \"apple\": %\n", word == "apple");
}
build/bin/ziran bundle --root . --entry text_basics:main -o text_basics.zib site/examples/text_basics.zi
build/bin/ziran run text_basics.zib
# banana has 6 bytes
# the first byte is 98
# it contains 3 a's
# its middle is anan
# equal to "banana": true
# equal to "apple": false

Download text_basics.zi ↓

12 / defer.zi

Defer

A deferred statement runs when its scope ends, last deferred first.

Work :: (name: string) {
    print("open %\n", name);
    defer print("close %\n", name);
    print("use %\n", name);
}

main :: () {
    defer print("done\n");
    Work("file");
    {
        defer print("leave the block\n");
        print("inside the block\n");
    }
}
build/bin/ziran bundle --root . --entry defer:main -o defer.zib site/examples/defer.zi
build/bin/ziran run defer.zib
# open file
# use file
# close file
# inside the block
# leave the block
# done

Download defer.zi ↓

13 / fizzbuzz.zi

FizzBuzz

Multiples of 3 print Fizz, of 5 Buzz, and of both FizzBuzz.

main :: () {
    for number: 1..20 {
        if number % 15 == 0 {
            print("FizzBuzz\n");
        } else if number % 3 == 0 {
            print("Fizz\n");
        } else if number % 5 == 0 {
            print("Buzz\n");
        } else {
            print("%\n", number);
        }
    }
}
build/bin/ziran bundle --root . --entry fizzbuzz:main -o fizzbuzz.zib site/examples/fizzbuzz.zi
build/bin/ziran run fizzbuzz.zib
# 1
# 2
# Fizz
# 4
# Buzz
# Fizz
# 7
# 8
# Fizz
# Buzz
# 11
# Fizz
# 13
# 14
# FizzBuzz
# 16
# 17
# Fizz
# 19
# Buzz

Download fizzbuzz.zi ↓

14 / primes.zi

The Sieve of Eratosthenes

Cross out every multiple of each prime.

LIMIT :: 50;

main :: () {
    composite: [LIMIT + 1]bool;
    for number: 2..LIMIT {
        if composite[number] { continue; }
        print("% ", number);
        multiple := number * number;
        while multiple <= LIMIT {
            composite[multiple] = true;
            multiple += number;
        }
    }
    print("\n");
}
build/bin/ziran bundle --root . --entry primes:main -o primes.zib site/examples/primes.zi
build/bin/ziran run primes.zib
# 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 

Download primes.zi ↓

15 / score.zi

Model a score

Define a record, pass it to a procedure, and return the answer.

Score :: struct {
    value: s32;
    bonus: s32;
}

Total :: (score: Score) -> s32 {
    return score.value + score.bonus;
}

Answer :: () -> s32 {
    score: Score = Score.{value = 40, bonus = 2};
    return Total(score);
}
build/bin/ziran bundle --root . --entry score:Answer -o score.zib site/examples/score.zi
build/bin/ziran run score.zib
# 42

Download score.zi ↓

16 / text_demo.zi

Use a standard module

Import the text module and test a prefix with ASCII case folding.

#import "text"

Answer :: () -> s32 {
    if StartsWithFoldASCII("Ziran", "zi") {
        return 1;
    }
    return 0;
}
build/bin/ziran bundle --root . --module-path std --entry text_demo:Answer -o text_demo.zib site/examples/text_demo.zi
build/bin/ziran run text_demo.zib
# 1

Download text_demo.zi ↓

17 / Native output

Generate native code

Every program above prints the same output on the portable runner and as C, C++, Go, Rust, and Python; tests/examples.sh checks it. For Rust, Go, and Python, --exe with an entry writes a runnable program. Go, Cargo, or Python 3.10 is needed only to run that output.

build/bin/ziran build --target=rust --exe --entry fizzbuzz:main --root . -o out/rust site/examples/fizzbuzz.zi
cargo run --manifest-path out/rust/Cargo.toml

build/bin/ziran build --target=go --pkg main --exe --entry fizzbuzz:main --root . -o out/go site/examples/fizzbuzz.zi
(cd out/go && go run .)

build/bin/ziran build --target=py --exe --entry fizzbuzz:main --root . -o out/py site/examples/fizzbuzz.zi
python3 out/py

C and C++ output mirrors the source path, here out/c/site/examples/fizzbuzz.c and its header, which declares fizzbuzz_main; call it from your program, or put #program_export before main to make the output a complete program. --target=plan9-c writes experimental Plan 9 C.

build/bin/ziran build --target=c --root . -o out/c site/examples/fizzbuzz.zi
build/bin/ziran build --target=cpp --root . -o out/cpp site/examples/fizzbuzz.zi

Native and portable support can differ by feature. See the current status before choosing a target.