Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Getting started

From nothing to a checked, tested, formatted, natively compiled program and a small package, in about ten minutes. Every program on this page is real Nazm 1.0, and every command shown with its output is run by crates/nazm-cli/tests/release_examples.rs, which fails if this page stops being true.

1. Build the toolchain

You need the Rust toolchain pinned in rust-toolchain.toml (rustup installs it on first use) and clang, which nazm build uses to compile and link. On macOS, the Xcode command-line tools provide clang; on Linux, install your distribution’s clang package.

git clone https://github.com/mdferdousalam/nazm
cd nazm
cargo build --release -p nazm-cli
export PATH="$PWD/target/release:$PATH"
nazm --version

cargo install --path crates/nazm-cli --locked puts nazm in ~/.cargo/bin instead. The binary carries the standard library inside it, so it needs no installation directory.

2. A first program

Create hello.nz:

fn main(out: OutCap) -> Int {
    print("Hello, Nazm!\n");
    0
}

main is the entry point and returns an Int, which nazm run prints after the program’s own output. out: OutCap is the authority to write to the standard streams. Nothing in Nazm reaches the outside world without such a value, and the only place one comes from is main’s parameters.

$ nazm run hello.nz
Hello, Nazm!
0

3. Check it

nazm check type-checks without running anything. Remove the capability to see what it catches:

fn main() -> Int {
    print("Hello, Nazm!\n");
    0
}
$ nazm check hello.nz
ok
$ nazm check nocap.nz  # fails
error[N0369]: the built-in `print` requires `OutCap` authority, and `main` holds no `OutCap` here
  --> nocap.nz:2:5
  |
2 |     print("Hello, Nazm!\n");
  |     ^^^^^ `print` is authorised by an `OutCap`
  = help: authority is a value: give `main` an `OutCap` parameter and have each caller pass one. The only source of one is `main`'s parameters
nazm: 1 error

Every diagnostic has a stable code; nazm check --json prints the same thing as nazm.diagnostic/1 for tools.

4. Build a native executable

nazm build compiles the same program to a native executable — no interpreter and no nazm process at run time. It produces the same output:

$ nazm build hello.nz -o hello
hello
$ ./hello
Hello, Nazm!
0

There are two code generators, held to the same results. LLVM is the default; Cranelift generates code in process instead of through clang (performance.md has a dated build-time comparison):

$ nazm build hello.nz -o hello-fast --backend cranelift
hello-fast
$ ./hello-fast
Hello, Nazm!
0

5. Test it

nazm test DIR runs every NAME.nz that has a NAME.expected beside it, interpreted and compiled, and requires both to print exactly what the .expected file says.

fn double(n: Int) -> Int {
    n * 2
}

fn main() -> Int {
    double(21)
}
42
$ nazm test checks
ok    double
nazm: 1 of 1 passed

6. Format it

There is one layout. nazm fmt --check reports a file that differs from it; nazm fmt rewrites the file.

fn  add(a:Int,b:Int)->Int{a+b}
fn main()->Int{add(2,   3)}
$ nazm fmt --check messy.nz  # fails
messy.nz
nazm: 1 file would change; run `nazm fmt` without --check
$ nazm fmt messy.nz
messy.nz
nazm: 1 of 1 file rewritten
$ cat messy.nz
fn add(a: Int, b: Int) -> Int { a + b }
fn main() -> Int { add(2, 3) }

7. More than one file

A file is a module. use "FILE"; makes the definitions that file marks pub nameable here; everything else in it stays private.

#![allow(unused)]
fn main() {
pub struct Rect {
    w: Int,
    h: Int,
}

pub fn area(r: Rect) -> Int {
    r.w * r.h
}
}
use "geometry.nz";

fn main() -> Int {
    area(Rect(w: 6, h: 7))
}
$ nazm run main.nz
42

8. A package

A program that grows past a few files becomes a package: a nazm.toml beside src/. nazm init writes one from a template — cli, library, server, embedded, wasm or contract — with a module, a test and a README:

$ nazm init demo --template cli
nazm: created `demo` from the `cli` template (6 files); its README.md says what to run
$ nazm run demo
hello, world
0
$ nazm test demo/tests
ok    greet
nazm: 1 of 1 passed
$ nazm lock demo
nazm: wrote demo/nazm.lock (1 package)
$ nazm build demo -o demo/demo --locked
demo/demo
$ ./demo/demo
hello, world
0

nazm lock pins every package the program uses, by version and BLAKE3 digest, and --locked refuses to build against anything else. Dependencies are written use "NAME:path.nz"; and declared in nazm.toml; see docs/spec.md, Packages.

Where next

  • examples/tour/ — records and enums, Result and ?, generics, closures and function values, traits, and tasks with declared effects and a SpawnCap, each checked, run and built under both backends by the test suite; examples/worker-pool.nz for a larger concurrent program.
  • guide.md — the language, a page per idea.
  • spec.md — what each construct means, exactly.
  • support.md — targets and optional features, and what is verified on each.
  • limitations.md — what Nazm does not do.