Skip to content

XIOM Language Reference

Complete reference for every XIOM language construct. For tutorials and concepts, see Getting Started and Concepts.


Program Structure

A XIOM source file consists of top-level declarations: fn, type, enum, interface, module, const, use, extern.

use xiom.io;

fn main() -> Int {
  io.println("Hello, world!");
  return 0;
}

Scripts (via xiom run) may omit fn main() -- the compiler wraps top-level code automatically.


Variables and Constants

var -- Mutable variable

var x: Int = 0;        // type-annotated
var y = 42;            // type-inferred
var z: Float64 = 3.14;

let -- Immutable binding

let name: Str = "xiom";     // cannot be reassigned
let pi: Float64 = 3.14159;

const -- Compile-time constant

pub const MAX: Int = 1024;
pub const PI: Float64 = 3.1415926535;

Types

Primitives

Type Description Example
Int Signed 64-bit integer 42, -1
Int128 Signed 128-bit integer 170141183460469231731687303715884105727
UInt128 Unsigned 128-bit integer 340282366920938463463374607431768211455
Float64 64-bit IEEE 754 float 3.14, -0.5
Float128 128-bit IEEE 754 float 3.14 as Float128
Bool Boolean true, false
Str Immutable string "hello"
Char Single Unicode character 'a', '\n'
Unit Void / no value ()
UInt8 Unsigned 8-bit integer 255
Int32 Signed 32-bit integer -2147483648

Compound Types

Type Syntax
Struct type Point = { x: Float64; y: Float64; }
Enum enum Color { Red, Green, Blue }
Enum with data enum Option[T] { Some(T), None }
Interface interface Comparable { fn compare(self, other: &Self) -> Int; }
Tuple (Int, Str, Bool)
Array (fixed) [3]Int
Vec (dynamic) Vec[Int]
Slice &Slice[Int]
Map Map[Str, Int]
Set Set[Int]
Reference &T, &mut T
Raw pointer *T

Type Aliases

type UserId = Int;
type Point3D = { x: Float64; y: Float64; z: Float64; };

Functions

Basic function

fn add(a: Int, b: Int) -> Int {
  return a + b;
}

Method on a type (receiver)

pub fn Point.distance(self, other: &Point) -> Float64 {
  let dx = self.x - other.x;
  let dy = self.y - other.y;
  return math.sqrt(dx * dx + dy * dy);
}

Generic function

fn max[T: Comparable](a: T, b: T) -> T {
  if a > b { return a; }
  return b;
}

impl Trait return type (M9.6)

fn get_display() -> impl Display {
  return 42;
}

Control Flow

if / elif / else

if x > 0 {
  io.println("positive");
} elif x < 0 {
  io.println("negative");
} else {
  io.println("zero");
}

match -- Pattern matching

match value {
  Some(v) => io.println(v),
  None => io.println("nothing"),
}

Multi-line arms use braces:

match result {
  Ok(data) => {
    process(data);
    return data;
  }
  Err(e) => {
    io.println(e.message);
    return defaultValue;
  }
}

while let

while let Some(item) = iter.next() { process(item); }

if let is not implemented by the current compiler. Use match, or test a variant with if value is Variant when no binding is needed.

while loop

use xiom.convert.itos;

var i = 0;
while i < 10 {
  io.println(itos(i));
  i = i + 1;
}

for loop (range-based)

The current release fails at LLVM codegen for for over an array literal (invalid getelementptr indices, tracked upstream); prefer while or the xiom.iter functions until the fix ships.

for i in [0, 1, 2, 3] {
  io.println(itos(i));
}

loop -- infinite loop

loop {
  // ...
  if done { break; };
}

break / continue

while i < 100 {
  i = i + 1;
  if i % 2 == 0 { continue; };
  if i > 50 { break; };
  io.println(itos(i));
}

Loops can carry a label; break @label; and continue @label; target the labeled loop instead of the innermost one:

@outer: while i < 10 {
  var j = 0;
  while j < 10 {
    j = j + 1;
    if j > 5 { break @outer; }
  }
  i = i + 1;
}

Expressions

Arithmetic

a + b    a - b    a * b    a / b    a % b

Comparison

a == b   a != b   a < b    a <= b   a > b    a >= b

Logical

a && b   a || b   !a

Bitwise

a & b    a | b    a ^ b    a << b   a >> b   ~a

Assignment

x = value;           // simple
x += 1;              // compound: +=, -=, *=, /=, %=, &=, |=, ^=

Type cast

x as Float64;         // safe numeric cast
x as Int;             // truncating float->int

is -- Type check

result is Ok;         // true if result matches Ok pattern
value is Some;        // true if value is Some variant

? -- Error propagation

let file = io.read_file(path)?;
// Equivalent to:
//   match io.read_file(path) {
//     Ok(f) => f,
//     Err(e) => return Err(e.into()),
//   }

=> -- Implication (contracts only)

requires: x > 0 => result > 0

String interpolation via +

var msg = "Hello, " + name + "!";

Array/Vec indexing

arr[0]            // 0-indexed access
vec[i]            // bounds-checked at runtime

Field access

point.x             // struct field
enum_type.Variant   // enum variant
type.method()       // method call

Contracts

Contracts are compile-time verified safety annotations.

fn divide(a: Float64, b: Float64) -> Float64
  requires: b != 0.0
  ensures:  result * b == a
{
  return a / b;
}
type NonEmptyStack[T] = {
  items: Vec[T];
  invariant: items.len() > 0;
}
Clause Where Meaning
requires: fn Must be true when function is called
ensures: fn Must be true when function returns
invariant: type, enum Must hold for all instances of type

Error Handling

Result[T, E]

fn parse_int(s: Str) -> Result[Int, Str] {
  // ...
  return Ok(value);
  // or
  return Err("invalid integer");
}

Option[T]

fn find_user(id: Int) -> Option[User] {
  // ...
  return Some(user);
  // or
  return None;
}

Unwrapping

let val = result.unwrap();           // panics on Err
let val = result.unwrap_or(default); // safe fallback
let val = option.unwrap_or(42);     // safe fallback for Option

Modules and Visibility

module mylib.data;           // namespace declaration

pub fn public_api() { ... }; // visible outside module
fn private_impl() { ... };   // module-private

use xiom.io;                 // import module
use xiom.collections.Map;    // import specific type

Ownership and Borrowing

XIOM uses lexical-scope ownership. When a value leaves scope, it is freed.

fn take_ownership(v: Vec[Int]) { ... } // v is moved -- caller loses access
fn borrow_read(v: &Vec[Int]) { ... }   // v is borrowed -- caller keeps access
fn borrow_write(v: &mut Vec[Int]) { ... } // exclusive mutable borrow

See Memory Model for the complete ownership and borrowing rules.


Generics

fn identity[T](x: T) -> T { return x; }

type Pair[A, B] = { first: A; second: B; }

enum Option[T] { Some(T), None }

interface Add {
  fn add(self, other: &Self) -> Self;
}

// Bounded generic
fn sum[T: Add](a: T, b: T) -> T {
  return a.add(&b);
}

Unsafe and FFI

unsafe {
  let ptr = malloc(1024);
  free(ptr);
}

extern "C" {
  fn printf(format: *UInt8, ...) -> Int32;
  fn malloc(size: UInt) -> *UInt8;
}

Scripting Mode

Scripts -- files with top-level code and no fn main -- run through xiom run, which wraps the code in fn main(), compiles it and executes it. The Scripting page covers the workflow, arguments, stdin, files, environment access and exit codes.

xiom repl starts an interactive REPL; xiom --run program.xi compiles and runs a program that has fn main(). Shebang scripts are supported on Linux and macOS.


CLI Reference

Command Description
xiom file.xi -o out Compile to a native binary
xiom run file.xi Compile and run a script (top-level code allowed)
xiom --run file.xi Compile and run a program (requires fn main())
xiom build Build a project from xiom.toml
xiom --check file.xi Type-check only (no codegen)
xiom doctor Verify toolchain (clang, opt)
xiom pkg search <q> Search registry
xiom pkg install <pkg> Install package
xiom pkg publish Publish package to registry
xiom doc file.xi Generate markdown docs
xiom doc file.xi --html Generate HTML docs
xiom fmt file.xi Format source code
xiom repl Start interactive REPL
xiom clean --cache Clean build cache

See Also

Document Covers
Syntax Detailed grammar and expression syntax
Type System Full type hierarchy, inference rules
Contracts Deep dive on requires/ensures/invariant
Memory Model Ownership, borrowing, move semantics
Generics Comptime monomorphisation, bounds
Standard Library Complete API reference