Syntax Basics

A comprehensive guide to the core language features of Reox.

Variables: Immutable vs Mutable

Reox is designed with safety in mind. Variables are immutable by default, meaning once assigned, they cannot be changed. Use let mut to create mutable variables.

// ═══════════════════════════════════════
// IMMUTABLE VARIABLES (Default)
// ═══════════════════════════════════════

let x: int = 42;
let name: string = "Reox";
let pi: float = 3.14159;

// x = 10;  // ❌ ERROR: Cannot assign to immutable variable
// name = "New";  // ❌ ERROR: Variable is immutable

// ═══════════════════════════════════════
// MUTABLE VARIABLES (Explicit)
// ═══════════════════════════════════════

let mut counter: int = 0;
counter = 10;       // ✓ OK - counter is mutable
counter += 5;       // ✓ OK - compound assignment
counter++;          // ✓ OK - increment

// Mutable collections
let mut items = [1, 2, 3];
items = push(items, 4);  // [1, 2, 3, 4]

let mut config = map_new();
config = map_set(config, "debug", true);

Why immutable by default? Immutability prevents accidental changes, makes code easier to reason about, and enables safe concurrent programming. Only mark variables as mut when you need to modify them.

Shadowing vs Mutation

You can "shadow" an immutable variable by re-declaring it with the same name:

let value = 10;
let value = value * 2;  // Shadowing - creates new binding (20)
let value = to_string(value);  // Can even change type

// vs Mutation (requires mut)
let mut count = 10;
count = count * 2;  // Mutation - same binding, new value

Primitive Types

Reox has statically typed primitives with type inference.

let count: int = 42;           // Integer
let price: float = 19.99;       // Float
let name: string = "NeolyxOS";   // String
let active: bool = true;         // Boolean
let nothing = nil;               // Nil (null)

// Type inference
let inferred = 100;             // Inferred as int
let text = "Hello";            // Inferred as string

Compound Assignments & Operators

Shorthand operators for modifying mutable variables.

let mut x: int = 10;

// Arithmetic compound operators
x += 5;   // x = x + 5  → 15
x -= 3;   // x = x - 3  → 12
x *= 2;   // x = x * 2  → 24
x /= 4;   // x = x / 4  → 6
x %= 4;   // x = x % 4  → 2

// Increment and Decrement
x++;       // Post-increment: returns old value, then adds 1
++x;       // Pre-increment: adds 1, then returns new value
x--;       // Post-decrement
--x;       // Pre-decrement

// Practical example in loop
let mut i = 0;
while i < 10 {
    print(i++);  // Prints 0-9
}

Functions

Functions are declared with fn. Parameters have explicit types, and return types are specified after ->.

// ═══════════════════════════════════════
// BASIC FUNCTION
// ═══════════════════════════════════════
fn add(a: int, b: int) -> int {
    return a + b;
}

// Function without return (void)
fn greet(name: string) {
    print("Hello, " + name);
}

// ═══════════════════════════════════════
// CALLING FUNCTIONS
// ═══════════════════════════════════════
let result = add(10, 20);  // 30
greet("Reox");  // Prints: Hello, Reox

Inter-Function Calls & Composition

Functions can call other functions, enabling modular composition:

// Helper functions
fn square(n: int) -> int {
    return n * n;
}

fn double(n: int) -> int {
    return n * 2;
}

// Composed function using helpers
fn process(value: int) -> int {
    let squared = square(value);
    let doubled = double(squared);
    return doubled;
}

// Chain calls inline
let result = double(square(5));  // 50

// ═══════════════════════════════════════
// RECURSIVE FUNCTIONS
// ═══════════════════════════════════════
fn factorial(n: int) -> int {
    if n <= 1 {
        return 1;
    }
    return n * factorial(n - 1);
}

fn fibonacci(n: int) -> int {
    if n <= 1 { return n; }
    return fibonacci(n - 1) + fibonacci(n - 2);
}

Async Functions & Await

// Async function declaration
async fn fetch_data(url: string) -> string {
    let response = await http_get(url);
    return response;
}

// Multiple async calls
async fn load_user_data(id: int) {
    let user = await fetch_user(id);
    let posts = await fetch_posts(user.id);
    print("Loaded " + len(posts) + " posts");
}

Loops and Iteration

Reox supports while loops, for..in loops, range expressions, and loop control with break and continue.

While Loops

// Basic while loop
let mut count: int = 0;
while count < 5 {
    print(count);
    count++;
}  // Prints: 0, 1, 2, 3, 4

// Infinite loop with break
let mut running = true;
while running {
    let input = read_input();
    if input == "quit" {
        running = false;
    }
}

For Loops with Arrays

// Iterate over array elements
let fruits = ["apple", "banana", "cherry"];
for fruit in fruits {
    print(fruit);
}

// Process each item
let numbers = [1, 2, 3, 4, 5];
let mut sum: int = 0;
for num in numbers {
    sum += num;
}
print(sum);  // 15

Range Expressions

// Exclusive range: 0..5 means 0, 1, 2, 3, 4
for i in 0..5 {
    print(i);
}  // Prints: 0, 1, 2, 3, 4

// Inclusive range: 1..=10 means 1 to 10 inclusive
for i in 1..=10 {
    print(i);
}  // Prints: 1, 2, 3, ..., 10

// Counting backwards
let mut i = 10;
while i >= 0 {
    print(i);
    i--;
}  // Prints: 10, 9, 8, ..., 0

Loop Control: Break & Continue

// break: exit loop entirely
for i in 0..100 {
    if i == 5 {
        break;  // Stop the loop
    }
    print(i);
}  // Prints: 0, 1, 2, 3, 4

// continue: skip to next iteration
for i in 0..10 {
    if i % 2 == 0 {
        continue;  // Skip even numbers
    }
    print(i);
}  // Prints: 1, 3, 5, 7, 9

// Find first match and exit
let data = [10, 20, 30, 40];
let mut found = nil;
for item in data {
    if item > 25 {
        found = item;
        break;
    }
}
print(found);  // 30

Nested Loops

// Matrix iteration
for row in 0..3 {
    for col in 0..3 {
        print("[" + row + "," + col + "]");
    }
}

// Breaking out of nested loops
let mut done = false;
for i in 0..10 {
    for j in 0..10 {
        if i * j == 42 {
            done = true;
            break;
        }
    }
    if done { break; }
}

State Transitions

Managing state changes cleanly with mutable variables and pattern matching.

// State machine pattern
let mut state: string = "idle";

fn transition(current: string, event: string) -> string {
    match current {
        "idle" => match event {
            "start" => "running",
            _ => current
        },
        "running" => match event {
            "pause" => "paused",
            "stop" => "stopped",
            _ => current
        },
        "paused" => match event {
            "resume" => "running",
            "stop" => "stopped",
            _ => current
        },
        _ => current
    }
}

// Usage
state = transition(state, "start");   // "running"
state = transition(state, "pause");   // "paused"
state = transition(state, "resume");  // "running"

Arrays and Maps

Reox provides built-in collections for storing multiple values.

// Arrays
let numbers = [1, 2, 3, 4, 5];
let first = numbers[0];      // Access by index
let count = len(numbers);   // Get length: 5

// Modify array (requires mutable)
let mut items = ["a", "b"];
items = push(items, "c");   // ["a", "b", "c"]
let last = pop(items);       // "c"

// Maps (key-value pairs)
let mut user = map_new();
user = map_set(user, "name", "Alice");
user = map_set(user, "age", 25);
let name = map_get(user, "name");  // "Alice"

// Check if key exists
let hasEmail = map_has(user, "email");  // false

Structures

Define custom data types with struct.

struct User {
    id: int,
    name: string,
    email: string
}

let user = User {
    id: 1,
    name: "Swana",
    email: "[email protected]"
};

// Access fields
print(user.name);      // "Swana"

// Optional chaining (returns nil if nil)
let maybeUser = nil;
print(maybeUser?.name);  // nil (no crash)

Null Safety

Handle nil values safely with optional chaining and null coalescing.

// Null coalescing: use default if nil
let value = nil;
let result = value ?? "default";  // "default"

// Optional chaining: safe member access
let user = nil;
let name = user?.name ?? "Guest";  // "Guest"

// Chained optional access
let city = user?.address?.city ?? "Unknown";

Pattern Matching

Powerful match expressions simplify control flow.

match command {
    "save" => save_file(),
    "load" => load_file(),
    "exit" => return,
    _ => print("Unknown command")
}

Conditionals

Use if, else if, and else for conditional branching.

let score: int = 85;

if score >= 90 {
    print("Excellent!");
} else if score >= 70 {
    print("Good job!");
} else {
    print("Keep trying!");
}

// Logical operators
if score > 50 and score < 100 {
    print("Valid score");
}

if score < 0 or score > 100 {
    print("Invalid score");
}

if not is_valid {
    print("Not valid");
}

Error Handling

Reox provides robust error handling with guard, try/catch, and defer.

// Guard: early exit if condition fails
guard user != nil else {
    return;
}

// Defer: cleanup when leaving scope
defer {
    close_connection();
}

// Try/catch: handle exceptions
try {
    risky_operation();
} catch err {
    print("Error: " + err);
}

// Throw an error
throw "Something went wrong";