Foreword

Welcome to The Toka Programming Language Guide.

This book is a comprehensive guide to learning Toka — a modern systems programming language designed for safety, simplicity, and performance.

Toka is created by YiZhonghua. The official language repository is at github.com/tokalang/toka — visit it to explore the compiler, standard library, and more.

Who This Book Is For

  • Beginners who want to learn their first systems programming language
  • Experienced developers coming from C, Rust, Go, or other languages
  • Language enthusiasts curious about the Hat Principle and PAL Checker

What You'll Learn

  1. Getting started — Install Toka and write your first program
  2. Language basics — Variables, types, functions, control flow
  3. The Hat Principle — Toka's unique approach to memory safety
  4. Advanced features — Generics, error handling, concurrency
  5. Standard library tours — Strings, collections, IO, networking, and more
  6. Hands-on projects — Build CLI tools, HTTP servers, and regex engines

How to Use This Book

If you're new to Toka, start from the beginning and work your way through. Each chapter builds on the previous one.

If you're an experienced developer, feel free to jump to specific topics using the sidebar navigation.

Language Version Alignment

This book is kept up-to-date with the latest Toka compiler development. The current version of this documentation is aligned with:

  • Compiler Version: v0.9.8
  • Toka Commit: aadfd52 (Unify three-track string system, abolish while in favor of loop, refactor std with generational Slab allocator, and introduce forge parallel build engine)
  • Tag: v0.9.8-03

A Note From the Author

Toka is a young but ambitious language. This guide was written alongside the language's development to help early adopters get started. As Toka evolves, this book will evolve with it.

[!NOTE] Since Toka is still under active development and rapid iteration, some descriptions or features in this book may occasionally have slight discrepancies with the actual behavior of the latest compiler. For absolute accuracy, please always refer to the official compiler and standard library source code as the ultimate source of truth.

Happy coding!

— lumicore-dev

Getting Started

Welcome to Toka! Toka is a modern systems programming language designed for memory safety, high performance, and intuitive development. It implements the Hat Principle to achieve compile-time memory safety without a garbage collector or manual lifetime annotations.

To help you get up and running as quickly as possible, this chapter is divided into three logical steps. We recommend following them in order:

🧭 Your Path to Toka

  1. Installation Set up the Toka compiler and toolchain on your system. We provide a single-command quick installer for Linux, macOS, and Windows, as well as instructions for building from source.

  2. Hello, Toka! Write, compile, and run your very first Toka program. You'll learn how to invoke the compiler directly and understand the anatomy of a basic Toka executable.

  3. Project Structure Scale up from a single-file script to a structured multi-file package. Learn about Toka's built-in package manager, defining package metadata in package.tk, adding dependencies, and structuring library projects.


Let's begin by installing Toka on your machine!

Installation

Getting Toka on your system takes just a few seconds.

Quick Install

The easiest way to install Toka is via the official install script:

curl -fsSL https://tokalang.dev/install.sh | bash

This script will:

  1. Detect your operating system and CPU architecture
  2. Download the latest stable release
  3. Install to ~/.toka/bin/
  4. Configure environment variables

Setting Up Environment

After installation, add these to your ~/.bashrc or ~/.zshrc:

export PATH="$HOME/.toka/bin:$PATH"
export TOKA_LIB="$HOME/.toka/lib"

Reload your shell:

source ~/.bashrc

Verify Installation

tokac --version

You should see output similar to:

toka version 0.9.7 (Built: May 21 2026)

Building from Source

For the latest development version:

git clone https://github.com/tokalang/toka.git
cd toka
make -C build -j8

Supported Platforms

PlatformStatus
Linux (x86_64)✅ Primary
macOS (Apple Silicon)✅ Supported
macOS (Intel)✅ Supported
Windows (x86_64)✅ Supported
Linux (ARM64)⚠️ Experimental

Hello, Toka!

Let's write your first Toka program. Create a file called hello.tk:

import std/io::println

fn main() -> i32 {
    println("Hello, Toka!")
    return 0
}

Running the Program

Toka provides two ways to run your code:

Option 1: One-step run

toka run hello.tk

This compiles and executes your program in a single command.

Option 2: Build then run

tokac build hello.tk -o hello
./hello

This gives you a standalone binary that you can distribute.

Expected Output

Hello, Toka!

Understanding the Code

Let's break down what each part does:

  • import std/io::println — Brings the println function from the standard library's IO module into scope.
  • fn main() -> i32 — Declares the entry point of your program. Every Toka executable needs a main function. The -> i32 means it returns an integer (the exit code).
  • println("Hello, Toka!") — Prints the string to standard output.
  • return 0 — Returns exit code 0, indicating success.

Quick One-Liner

For a quick test without creating a file, you can also use:

echo 'import std/io::println fn main() -> i32 { println("Hello, Toka World!") return 0 }' > hello.tk
toka run hello.tk

What's Next?

In the next section, we'll explore the standard project structure and how to organize larger Toka projects.

Project Structure

Understanding Toka's project structure helps you organize your code effectively.

Single-File Programs

For quick prototyping or simple scripts, a single .tk file is perfectly sufficient. As we saw in the Hello, Toka! section, you can write all your code in one file (like hello.tk) and execute it instantly with:

toka run hello.tk

Multi-File Projects

For larger projects, initialize a project using toka init. This creates a package.tk file:

// package.tk
pub const PACKAGE = (
    name = "my_project",
    version = "0.1.0",
    dependencies = ()
)

Directory layout:

my-project/
├── package.tk      # Project configuration and dependencies
├── src/
│   ├── main.tk     # Entry point
│   ├── utils.tk    # Utility functions
│   └── models.tk   # Data models
└── lib/
    ├── config.tk   # Library config
    └── helpers.tk  # Helper functions

Adding Dependencies

You can easily add third-party packages to your project using the toka add command:

toka add toka_ink

This will automatically query the Toka Registry, resolve the package to its GitHub repository and version tag, and update your package.tk:

// package.tk
pub const PACKAGE = (
    name = "my_project",
    version = "0.1.0",
    dependencies = (
        toka_ink = "github.com/lumicore-dev/toka-ink:v0.2.1",
    )
)

During toka build, the compiler will automatically fetch these dependencies into your .toka/packages directory.

Library Projects

For reusable libraries, toka new my-lib --lib generates a library structure without a main.tk executable entry point. The configuration format remains the same in package.tk.

Import System

// Import from standard library
import std/io::println

// Import from project source
import src/utils::{helper_fn}

// Import from local library
import lib/config::{Config}

// Import with alias
import std/time as time_lib

Build Output

Running toka run or tokac build produces:

my-project/
└── target/
    ├── debug/
    │   └── my-project    # Debug binary
    └── release/
        └── my-project    # Release binary (with --release)

🛠️ Incremental Builds with the Forge Engine

Starting from Toka v0.9.8-03, the official compiler comes with a high-throughput, parallel, and persistent cache build engine named forge. It reads the project's dependency topology declared inside a build.tk script, coordinates workers to compile files in parallel, and persists the build provenance locally.

1. Declaring Build Configuration build.tk

Create a build.tk file in the root directory of your project, utilizing the standard build toolchain to declare your executable or library:

import build::{Executable, run_build}

fn main() -> i32 {
    // Instantiate a build project, Executable::make(binary_name, entry_source)
    // Since Executable::make is a high-level wrapper around low-level C-FFI, we pass raw FFI pointers.
    auto proj# = Executable::make("my-project".as_cstr().raw_ptr(), "src/main.tk".as_cstr().raw_ptr())
    return run_build(proj)
}

2. Running Forge for Parallel Incremental Builds

Execute forge in your terminal:

# Compile with concurrency, -j specifies worker thread count (defaults to 4)
forge -j 8

The forge engine will automatically:

  • Parse the entry point src/main.tk and map its static dependency DAG recursively.
  • Compare source file timestamps and maintain an index database inside .forge_cache.
  • Smart Incremental Skip: Instantly bypass compilation for unchanged files, shrinking multi-module project compilation times down to milliseconds!

Language Basics

Now that you have Toka installed and have written your first program, let's dive into the core concepts of the language.

Hello World Revisited

The simplest Toka program needs two things: an import for the standard library, and a main function:

import std/io::println

fn main() -> i32 {
    println("Hello, Toka!")
    return 0
}

Run it with:

toka run hello.tk

Key Principles

Toka is designed around a few core principles:

  1. Safety by default — Variables are immutable unless explicitly marked.
  2. No hidden runtime — What you write is what gets executed. No garbage collector, no VM.
  3. C-like performance — Built on LLVM 20, Toka generates optimized native code.
  4. Modern syntax — Clean, readable, with intuitive pattern matching and error handling.

Comment Syntax

Comments in Toka use the standard // syntax:

// This is a single-line comment

/* This is a
   multi-line comment */

Next Steps

In the following sections, we'll explore variables, types, functions, and control flow in detail.

Variables & Types

Toka is a statically-typed language with a rich type system. Let's explore how variables and types work.

Variable Declaration

Use the auto keyword to declare variables:

auto x = 10          // i32 (default integer type)
auto y = 3.14        // f64 (default float type)
auto name = "Toka"   // str (string slice)

Naming Rules & Hyphen (-) Resolution

Toka has a strict and elegant rule regarding the hyphen (-) character to achieve both modular naming convenience and unambiguous mathematical syntax:

Package Names & Namespaces

Package names and imported namespaces can use hyphens freely. This is common when importing nested folders or external libraries that follow a kebab-case directory structure. You can import them and call their functions using their hyphenated namespaces:

import std/io::println

// Package and namespace names can contain hyphens
import ./nested/toka-ink as toka_ink

fn main() -> i32 {
    toka_ink::render()
    return 0
}

Variables & Functions

Ordinary variable names, constant names, shape/struct names, and function definitions cannot contain hyphens. They must follow standard alphanumeric/underscore naming rules (such as camelCase or snake_case):

fn main() {
    auto max_size = 1024       // OK (snake_case)
    auto maxSize = 1024        // OK (camelCase)
    // auto max-size = 1024    // Error: Hyphens are not allowed in variable names
}

Unambiguous Subtraction

Because hyphens are strictly forbidden in variable and function names, the subtraction operator (-) is completely unambiguous. Ordinary subtraction expressions without spaces are always parsed correctly without ambiguity:

import std/io::println

fn main() -> i32 {
    auto sub1 = 10
    auto sub2 = 3
    
    // No spaces are needed! Always parsed as subtraction
    auto result = sub1-sub2    // OK: parsed as sub1 - sub2
    auto value = 10-3          // OK: parsed as 10 - 3
    println("Result: {}, Value: {}", result, value)
    return 0
}

Explicit Type Annotations

You can specify the type explicitly with a colon:

auto x: u64 = 10
auto y: f32 = 3.14:f32
auto flag: bool = true

Primitive Types

Toka's type system is defined in lib/core/types.tk and includes:

TypeDescriptionSize
i8, i16, i32, i64Signed integers1-8 bytes
u8, u16, u32, u64Unsigned integers1-8 bytes
f32, f64Floating point (IEEE 754)4-8 bytes
boolBoolean (true / false)1 byte
charC-style character (i8)1 byte
byteRaw byte (u8)1 byte

Platform-Dependent Types

pub alias usize = u64   // Pointer-sized unsigned integer
pub alias isize = i64   // Pointer-sized signed integer

On 64-bit systems, usize is u64; on 32-bit systems, it would be u32.

Type Aliases

Toka supports two kinds of type aliases:

Weak alias — Semantically identical, transparent to the compiler:

pub alias usize = u64

Strong type — Same memory layout, but requires explicit conversion:

pub type Addr = u64
pub type OAddr = u64

Constants

Use const for compile-time constant values:

pub const MAX_SIZE = 1024:u64
pub const NAME = "Toka"

Constants are inlined at compile time — no memory is allocated and their address cannot be taken.

Mutability

Variables are immutable by default. Use the # suffix to make them mutable. The # token is only needed in two places:

  1. At declaration — to mark the variable as mutable
  2. Before a mutable method call — to present the guard on the variable
import std/io::println

pub shape List(data: i32)
impl List {
    pub fn sort(self#) {}
    pub fn push(self#, val: i32) {}
}

fn main() -> i32 {
    auto y = List(data = 10)  // immutable
    auto x# = List(data = 10) // mutable — # at declaration

    // Reading and assignment don't need #
    x = List(data = 20)       // OK — plain assignment
    println("{}", x.data)     // OK — plain read

    // Calling a mutable method requires # on the variable
    x#.sort()                 // OK — # on variable before .method()
    x#.push(5)                // OK
    return 0
}

This is an example of Toka's Attribute Token System — the # suffix denotes soul mutability and is placed on the variable itself when declaring it or calling its mutable methods.

Functions

Functions in Toka are first-class citizens. They follow a clean, readable syntax.

Basic Function Syntax

fn add(x: i32, y: i32) -> i32 {
    return x + y
}
  • fn keyword declares a function
  • Parameters are typed with name: Type syntax
  • Return type follows ->
  • The function body is wrapped in { }

Entry Point: main

Every Toka executable needs a main function that returns an exit code:

import std/io::println

fn main() -> i32 {
    println("Hello, Toka!")
    return 0
}

Return 0 for success, non-zero for errors.

Multiple Parameters

Functions can take multiple parameters of different types:

fn greet(name: str, age: i32, formal: bool) -> str {
    if formal {
        return "Good day"
    }
    return "Hey"
}

Mutable Parameters

Parameters are immutable by default. Use the # token at declaration for mutable parameters. Inside the function body, you access the parameter without #:

fn increment(x#: i32) {
    x = x + 1       // Inside the body, no # needed
}

Functions with No Return

If a function doesn't return anything, omit ->:

import std/io::println

fn log_message(msg: str) {
    println("{}", msg)
}

Method Syntax

Functions can be attached to types using impl blocks:

pub shape Number(val: i32)

impl Number {
    pub fn double(self) -> i32 {
        return self.val * 2
    }
}

fn main() -> i32 {
    auto result = Number(val = 5).double()  // result = 10
    return 0
}

Control Flow

Toka provides modern control flow constructs for building clear, expressive programs.

If / Else

import std/io::println

fn check_temp(temp: i32) {
    if temp > 35 {
        println("It's hot!")
    } else if temp < 10 {
        println("It's cold!")
    } else {
        println("It's mild.")
    }
}

Loop Loops

Toka completely abolishes traditional while loops, unifying all loop semantics under the loop keyword. This significantly simplifies compiler control flow analysis and eliminates syntactic ambiguity.

Conditional loops use the loop condition {} syntax structure:

import std/io::println

auto count# = 0
loop count < 5 {
    println("Count: {}", count)
    count = count + 1
}

Iterating Over Arrays

Toka supports array-based iteration:

import std/io::println

for auto i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] {
    println("{}", i)
}

Currently, Toka does not support a native range operator (like ..). You can iterate over an array of elements or implement custom loops using loop.

Iterating Collections

import std/io::println

auto items = ["apple", "banana", "cherry"]
for auto item in items {
    println("{}", item)
}

With index:

import std/io::println

auto items2 = ["apple", "banana", "cherry"]
auto i# = 0
for auto item in items2 {
    println("{}: {}", i, item)
    i = i + 1
}

Break and Continue

Control loop flow with standard keywords:

import std/io::println

auto iter# = 0
loop iter < 100 {
    if iter == 50 {
        break        // Exit the loop completely
    }
    if iter % 2 == 0 {
        iter = iter + 1
        continue     // Skip to next iteration
    }
    println("{}", iter)  // Prints odd numbers: 1, 3, 5, ..., 49
    iter = iter + 1
}

Match (Pattern Matching)

Toka provides intuitive pattern matching with the match expression:

fn describe(value: i32) -> str {
    return match value {
        0 => pass "zero"
        1 => pass "one"
        auto v if v >= 2 && v <= 10 => pass "small"
        auto v if v >= 11 && v <= 100 => pass "medium"
        _ => pass "large"
    }
}

The _ wildcard matches any value, serving as the default case.

Strings

Toka 1.0 implements a highly rigorous, high-performance Three-Track Text & Byte-Stream System. It orthogonally decouples "textual observation" from "physical binary manipulation" in the type system. Simultaneously, it eliminates ambiguous implicit context inference, providing developers with maximum memory safety and speed.


🏛️ 1. String and View Types

Strings in Toka are split into owned heap-allocated containers and zero-copy borrowed views. Built into the Prelude's zero-import scope, you can directly use these types without any import:

TypePhysical Geometry / LLVM RepresentationMemory OwnershipDescription
strFat pointer { i8* head, i64 len }No Ownership (Borrowed)UTF-8 read-only text view. No \0 termination guarantee.
stringHeap container { *#buf, usize, usize }Exclusive Ownership (Owned)Heap-allocated mutable UTF-8 string, strictly terminated with \0.
bytesFat pointer { i8* head, i64 len }No Ownership (Borrowed)Read-only binary byte-stream view.
cstrSingle pointer i8* (Zero-cost Shape)FFI BorrowedC-style read-only single pointer, 100% statically guaranteed to be \0-terminated.

⚖️ 2. The Orthogonal Conversion Matrix

Toka strictly adheres to the "Honest Overhead Naming Code":

  • as_xxx family: Represents zero-overhead, zero-allocation view borrowing. The borrowed view's lifetime is strictly guarded at compile time, bound tightly to its host.
  • to_xxx family: Represents conversions involving physical copies or heap allocations, explicitly declaring the separation of ownership and physical memory operations.
Source $\rightarrow$ Targetstr (Safe Fat Slice)string (Heap Owned)cstr (\0 Borrowed)*char (FFI Raw Ptr)
"..." LiteralDefault ResolvedType (0-cost).to_string()
($O(N)$ heap alloc)
.as_cstr()
($O(1)$ zero-alloc)
FFI boundary decay
(0 friction)
str——.to_string()
($O(N)$ heap alloc)
.to_string().as_cstr()
($O(N)$ heap copy)
Implicit banned!
Use .to_string().c_str()
string.as_str()
($O(1)$ zero-alloc)
——.as_cstr()
($O(1)$ zero-alloc)
.c_str()
($O(1)$ address borrow)
cstr.as_str()
($O(1)$ zero-alloc)
.to_string()
($O(N)$ heap alloc)
——FFI boundary decay
(0 friction)

🚀 3. Core Operations & Examples

1. Default Zero-Copy Literals

In Toka, regular double-quoted "..." string literals are resolved as static, read-only str views by default:

import std/io::println

fn main() -> i32 {
    // Resolved as str by default, resident in .rodata, 100% statically safe
    auto greeting: str = "Hello, Toka!"
    println("Greeting: {}", greeting)
    return 0
}

2. Dynamic string & Concatenation

string is an exclusive heap container. You can mutate it dynamically using push_str.

import std/io::println

fn main() -> i32 {
    // zero-import prelude allows direct call to string::from
    auto full# = string::from("Hello, ")
    full#.push_str("World!")
    
    println("{}", full.as_str()) // Zero-overhead str view borrow
    return 0
}

3. Dual-Track Conversion between str and bytes

Use str for high-level text operations, and bytes for low-level binary data and byte-based indexing:

import std/io::println
import core/option::Option
import core/result::Result

fn main() -> i32 {
    auto s: str = "Toka 1.0"
    
    // 1. O(1) zero-cost downgrade to bytes view
    auto b = s.bytes()
    
    // 2. Bound-checked O(1) byte indexing
    auto b0 = b.at(0:usize)
    if b0.is_some() {
        println("Byte 0: {}", b0.unwrap() as i64) // 84 ('T')
    }
    
    // 3. Validate and upgrade back to str
    auto res = b.try_to_str()
    if res.is_ok() {
        auto s_back = res.unwrap()
        println("Recovered: {}", s_back)
    }
    return 0
}

🛡️ 4. FFI Physical Copy Isolation

Because dynamic str slices do not guarantee a \0 terminator, str is strictly prohibited from implicitly decaying to a cstr or raw pointer. If a dynamic str must cross the FFI boundary, you must explicitly call to_string() to create a \0-terminated copy on the heap:

// Declare FFI interface
pub fn puts(s: cstr)

fn main() -> i32 {
    auto my_str: str = "Hello C-FFI"
    
    // Explicitly declare physical copy and \0 sealing for absolute safety
    auto temp_c = my_str.to_string()
    unsafe {
        puts(temp_c.as_cstr())
    }
    return 0
}

The Hat Principle

The Hat Principle is the foundational design philosophy behind Toka's memory safety model. Rather than forcing developers to write complex lifetime annotations (as in Rust) or relying on a runtime Garbage Collector (as in Go or Java), Toka introduces visible syntactic tokens called "Hats" to track ownership, resource lifetimes, and access permissions at compile time.


What is a Hat?

In Toka, a Hat is a syntactic sigil (symbol) attached directly to an identifier. This explicit notation tells both the programmer and the compiler's safety analysis engine exactly how a resource is stored, owned, and accessed.

Toka defines four primitive Hat typologies:

Hat SigilTypologySemantic DescriptionAllocation Context
*Raw PointerUnsafe, low-level pointer with manual lifecycle managementHeap or Address-of
^Unique PointerSafe, exclusive ownership of a heap-allocated resource (Auto-free)Heap (new)
~Shared PointerSafe, reference-counted shared ownershipHeap (new)
&Borrow PointerSafe, compile-time borrow/reference to another soul's dataExisting Soul

Handle vs. Soul: Implicit Dereferencing

One of the key usability features of the Hat Principle is the strict bifurcation between a pointer's container and its underlying data:

  • Handle (The Hat): An identifier with its sigil (^ptr, *ptr, ~ptr) represents the pointer container itself (the metadata holding the address).
  • Soul (The Data): An identifier without its sigil (ptr) represents the underlying data (the actual value).

By operating directly on the Soul (omitting the sigil), Toka completely eliminates the need for explicit dereferencing operators like C's *p or Rust's *p. For example, ptr.x = 42 directly mutates the underlying heap data without manual dereferencing.


The Pointer Analysis Layer (PAL)

The compiler's Pointer Analysis Layer (PAL) Checker inspects Hat configurations during compilation to statically enforce strict safety guarantees:

  1. Strict Move Semantics: A Unique Pointer (^) automatically transfers ownership on assignment. The PAL Checker blocks any "use-after-move" of the original handle.
  2. Deterministic Destruction: When an owned pointer (^ or the last ~) exits its declared scope, its resource is automatically freed.
  3. Rigorous Borrow Checking: Borrow Pointers (&) are checked to ensure they never outlive the underlying Soul, preventing dangling references.
  4. Data Race Prevention: The PAL Checker ensures that mutable access (#) is exclusive, while shared access is read-only.

Learning Path

To master the Hat Principle, explore the following sections in order:

  • Soul & Identity: Master the Handle/Soul split, implicit dereferencing, and the syntax of member borrowings (including standard parentheses and Hat-Terminal Morphology).
  • Ownership & Hats: Explore the four ownership models, default moves versus copying, the cede keyword, and the visual distinction between mutable local declarations and mutable method call receivers.
  • Memory Safety & PAL: Deep dive into the Pointer Analysis Layer and see how Toka achieves zero-overhead compile-time memory safety.

Soul & Identity

Toka's Hat Principle introduces a strict, clear distinction between a pointer's Handle (its syntactic container) and its Soul (its underlying data). Mastering this separation is essential to understanding Toka's memory management model.


Handle vs. Soul

Every pointer identifier in Toka possesses two distinct aspects in syntax and memory:

  • Handle (The Hat): An identifier prefixed with its pointer sigil (^p, *p, ~p). It represents the physical pointer container in memory—the slot holding the target memory address.
  • Soul (The Data): An identifier written without its sigil (p). It represents the underlying data/resource being pointed to.
fn handle_soul_example() {
    auto ^p# = new Point(x=10, y=20)
    p.x = 30
    auto sum = p.x + p.y
    println("sum: {}", sum)
}

In the example above, ^p# is the mutable unique handle, while p.x directly accesses the field of the underlying Point soul.


Ergonomic Implicit Dereferencing

Toka completely eliminates the visual clutter of traditional dereferencing operators (such as C's *p / p-> or Rust's *p).

Whenever you need to read, write, or access fields of the data behind a pointer, you simply operate directly on its Soul (the identifier without its sigil). The Toka compiler automatically resolves this to a dereference operation under the hood with zero runtime overhead:

fn implicit_deref_example() {
    unsafe {
        auto *p# = alloc i32
        p = 100
        auto val = p
        println("val: {}", val)
    }
}

This implicit dereferencing brings a clean, script-like syntax to high-performance systems programming, drastically increasing code readability.


Identity: The Address-Of Operator *expr

To retrieve the raw, physical memory address of a local variable or resource, Toka provides the unary *expr syntax. This returns a raw pointer *T pointing to the variable's location:

fn address_of_example() {
    auto a# = 42
    auto *raw_ptr = *a
    println("addr: {}", raw_ptr)
}

[!NOTE] The Hat sigil (like ^ or ~) does not mean "address of". Sigils are strictly type specifiers for pointer handles, whereas *expr is the runtime operator to extract a memory address.


References and the Borrow Pointer &

A Borrow Pointer (&) is a reference that allows safe, temporary, and compiler-checked access to a Soul without taking ownership of it.

Clean Local Variable Borrowing

When borrowing a standard, non-member local variable, no parentheses are needed. Simply prefix the soul with & to create a borrow pointer:

auto x = 42
auto &y = &x // y is a borrow pointer pointing directly to the soul of x

The Member Access Chain Borrow Ambiguity

When attempting to borrow a specific field within a struct or shape (a member access chain), writing &pt.x is syntactically ambiguous. It is unclear whether you want to borrow the entire member chain &(pt.x) or access the member x on a borrowed pointer (&pt).x.

To ensure clarity and type safety, the Toka compiler rejects &pt.x with a compile error and requires one of two clear and legal options:

  1. Option A (Standard Parentheses): Explicitly wrap the member chain in parentheses: &(pt.x).
  2. Option B (Hat-Terminal Morphology): Place the & borrow sigil directly before the terminal field name: pt.&x.

pt.&x is an intuitive form, allowing the borrow operation to integrate directly into the member access chain.

fn borrow_example() {
    auto x = 42
    auto &y = &x // Clean local variable borrow, no parentheses needed!
    
    auto pt = Point(x = 10, y = 20)
    
    // Member borrow Path A: standard parentheses
    auto &rx1 = &(pt.x)
    
    // Member borrow Path B: Hat-Terminal Morphology (Toka's signature aesthetic)
    auto &rx2 = pt.&x
    
    println("y: {}, rx1: {}, rx2: {}", y, rx1, rx2)
}

Ownership & Hats

Ownership in Toka is governed entirely by the Hat Principle. Rather than hiding allocations behind a generic type system, Toka uses distinct hat sigils to make a value's ownership model, copy/move semantics, and access permissions immediately clear directly in the syntax.


Four Ownership Models

Toka defines four pointer typologies, each supporting a distinct resource management strategy:

1. * — Raw Pointer (Manual Lifecycle)

Low-level raw pointers provide zero compile-time safety and must be managed manually within an unsafe block:

fn raw_ptr_example() {
    unsafe {
        auto *p# = alloc i32
        p = 99
        println("raw: {}", p)
    }
}

2. ^ — Unique Pointer (Exclusive Heap Ownership)

Unique pointers enforce strict exclusive ownership. Only one ^ handle can point to a heap resource at a time. When a unique pointer exits its scope, its bound memory is automatically freed:

fn unique_ptr_example() {
    auto ^p = new i32(42)
    auto ^q = ^p
    println("unique: {}", q)
}

3. ~ — Shared Pointer (Reference-Counted Heap Ownership)

Shared pointers allow multiple handles to share ownership of the same heap-allocated resource via thread-safe reference counting. The resource is automatically freed when the last ~ handle goes out of scope:

shape Point(x: i32, y: i32, z: i32)
auto ~s1# = new Point(x = 100, y = 200, z = 0)
auto ~s2# = ~s1  // Shared Copy (ref count increments)
s2.x = 300       // Directly mutates the underlying soul

4. & — Borrow Pointer (Reference Semantics)

Borrow pointers represent temporary, compiler-checked references to existing souls without taking ownership, strictly governed by the Pointer Analysis Layer (PAL).


Moving vs. Copying

Toka has clear rules to distinguish between copying data and transferring ownership:

Default Copy Semantics

By default, standard assignments in Toka perform a copy (value copies for simple scalar types like i32/bool, and shallow copies for standard complex shape types):

fn move_copy_example() {
    auto a# = 42
    auto b = a
    a = 99
    println("a: {}, b: {}", a, b)
}

Default Move Semantics (Unique Pointers)

Move semantics apply by default exclusively to Unique Pointers (^). Assigning one unique pointer to another automatically transfers exclusive ownership from the source to the destination, rendering the source handle immediately invalid:

shape Point(x: i32, y: i32, z: i32)
auto ^p1 = new Point(x = 10, y = 20, z = 0)
auto ^p2 = ^p1  // Ownership transfers (moves) to p2; p1 is no longer valid!

Explicit Move with cede

For other types (such as custom shapes or string), copy semantics are used by default. To explicitly transfer ownership of such a value (avoiding copies), you must use the cede keyword. Ceding transfers the resource to the destination and invalidates the source variable:

auto s1 = string::from("hello")
auto s2 = cede s1 // Explicit move: s1 is invalidated

Function Parameters: Zero-Copy Capture

In Toka, function parameters are immutable by default and passed via an incredibly efficient zero-copy implicit reference capture mechanism.

The compiler automatically passes arguments by reference under the hood with zero runtime overhead and zero copying. Therefore, you do not need special pointer sigils for standard parameter passing unless you explicitly intend to pass or rebind pointer handles:

fn process(data: i32) {
    println("data: {}", data)
}

fn borrow_func_example() {
    auto val = 10
    process(val)
    println("val: {}", val)
}

The # Mutability Marker & Permission Views

Toka introduces the # marker to explicitly declare and track mutable access. Its usage is governed by strict compiler lifecycles to eliminate redundant code noise while maximizing visual safety.

1. Declaring Mutability

To declare a local variable mutable, you must append # to the identifier at its declaration site:

fn mutable_local_example() {
    auto val# = 42
    val = 99 // Everyday context assignment: NO '#' suffix allowed here!
    println("val: {}", val)
}

2. Forbidden in Everyday Contexts (Assignments)

Once a variable is declared mutable, its mutable state is registered in its Permission View (type system). Therefore, you must NOT append # to the variable in ordinary assignments or expressions:

auto val# = 42
val = 99 // Everyday assignment: NO '#' allowed! Writing 'val# = 99' is a compiler error.

This prevents useless syntactic noise in everyday code.

3. Required at Mutating Method Call Sites (Receiver Suffix)

A key safety feature in Toka is that mutating method calls must be explicitly flagged at the call site.

When invoking a method that mutates a shape, the compiler requires you to append the # suffix to the receiver object (e.g. obj#.mutate()). This makes the state mutation explicit, aiding code readability and auditing:

shape Counter (
    val#: i32 = 0
)


impl Counter@encap {
    pub fn clone(self) -> Counter {
        return Counter(val = self.val)
    }

    fn drop(self#) {}

    pub fn increment(self#) {
        self.val = self.val + 1
    }
}



fn mutable_method_example() {
    auto c# = Counter(val = 10) // Declaration: '#' is required for mutability
    c#.increment()             // Mutation Site: '#' receiver suffix is required and highly visible!
    println("c.val: {}", c.val)
}

By restricting the # suffix to declarations and mutating method call sites, Toka keeps the syntax intuitive while providing clear safety visibility.

Memory Safety & PAL

Toka achieves rigorous, compile-time memory safety without the heavy runtime overhead of a Garbage Collector, and without requiring complex, verbose lifetime annotations.

This is accomplished by the compiler's Pointer Analysis Layer (PAL) Checker, which acts as a static verification engine inspecting the usage of Hat pointer typologies and access permission modifiers.


How the PAL Checker Works

The PAL Checker performs static compile-time flow analysis to track the Permission View and Active Scope (Region) of every resource in your codebase.

By requiring explicit pointer specifiers (Hats like ^, ~, &) and mutation intent markers (like # on declarations and receiver method call sites), the compiler gains enough semantic information to perform rigorous safety checking automatically.

It guarantees four core pillars of memory safety at compile time:

1. No Use After Move (Unique Pointers ^)

A unique pointer ^ represents exclusive heap ownership. When it is assigned to another handle, the original handle is marked as "moved-from." The PAL Checker statically blocks any subsequent read or write to the original variable:

fn no_use_after_move_example() {
    auto ^p = new i32(42)
    auto ^q = ^p
    println("q: {}", q)
}

2. No Dangling References (Borrow Pointers &)

A borrow pointer & must never outlive its referent. The PAL Checker tracks the lifetime bounds of the underlying Soul and rejects compilation if a borrow is returned or held beyond the soul's deallocation scope.

3. No Double Free

For owned resources (^ unique pointers or the last ~ shared pointer), the compiler injects a single, deterministic destruction call when the handle exits its scope. Handlers that have been moved or ceded are bypassed, preventing double frees statically.

4. No Data Races / Aliasing Violations

To prevent data races and modification conflicts, Toka enforces the fundamental aliasing rule: you may have either one active mutable borrow OR multiple read-only borrows, but never both simultaneously.

Because Toka requires mutating method calls to explicitly tag their receiver (e.g. obj#.mutate()), the PAL Checker can trivially and securely verify exclusive mutable access at every method call boundary.


Zero-Copy Argument Safety

Toka's function argument passing utilizes the zero-copy implicit reference capture mechanism. When passing arguments to a function, the PAL Checker automatically captures variables by reference under the hood with zero copying.

Because parameters are immutable inside the function by default, the caller's argument remains perfectly safe from modification:

fn show(x: i32) {
    println("x: {}", x)
}

fn borrowing_safe_example() {
    auto val = 10
    show(val)
    println("val: {}", val)
}

To allow a function to modify a parameter, the parameter must be declared mutable (#) in the function signature, and the PAL Checker will then enforce exclusive borrowing at the call site.


PAL Static Assurances at a Glance

The PAL Checker statically analyzes and verifies memory safety during compilation:

Scenario / ActionPAL Checker Static ResponseSafety Context
Accessing a unique pointer ^ after moveCompile ErrorPrevents use-after-move and double-frees
Holding a borrow & after its Soul is droppedCompile ErrorEliminates dangling pointers & use-after-free
Triggering double unsafe free on *Compile ErrorRestricts manual deallocation errors
Overlapping mutable borrow obj#.mutate() with shared borrowsCompile ErrorGuarantees thread safety and no data races
Normal borrow parameter passingPassedHigh-performance, zero-copy read-only access
Handle exiting its declared scopePassedGenerates zero-overhead automatic resource cleanup

By shifting the verification of memory safety to the Pointer Analysis Layer (PAL), Toka allows developers to write safe, high-performance code without the need for manual lifetime annotations.

Advanced Features

Having mastered the language basics and gained a deep understanding of the Hat Principle regarding the management of Soul and Handle, you have already conquered Toka's steepest learning curve. Now, we enter the world of Toka's Advanced Features.

Toka's advanced features provide high-level abstract expressiveness while strictly adhering to the Zero-Copy Capture Mechanism and runtime efficiency. Here, you will see the integration of strong type systems and algebraic data types.


Chapter Map

This chapter will guide you through the following four pillars of system development:

flowchart TD
    Root("Toka Advanced Features & Abstractions")

    Generics("**Generics**")
    Error("**Error Handling**")
    Pattern("**Pattern Matching**")
    Concurrency("**Concurrency**")

    GenericsDesc("Zero-overhead ADT representation<br>Avoid Soul Collapse")
    ErrorDesc("Algebraic data type contracts<br>Short-circuit (!) propagation")
    PatternDesc("Deconstruct Shapes<br>Combined w/ guards")
    ConcurrencyDesc("Lightweight fibers<br>Multicore scaling")

    Root --> Generics & Error & Pattern & Concurrency
    
    Generics --> GenericsDesc
    Error --> ErrorDesc
    Pattern --> PatternDesc
    Concurrency --> ConcurrencyDesc

    style Root fill:#1e1b4b,stroke:#a855f7,stroke-width:2px,color:#fff;
    style Generics stroke:#3b82f6,stroke-width:1.5px;
    style Error stroke:#10b981,stroke-width:1.5px;
    style Pattern stroke:#f59e0b,stroke-width:1.5px;
    style Concurrency stroke:#ec4899,stroke-width:1.5px;

1. Generics

Achieve zero-overhead polymorphism while maintaining strong type safety. You will learn about Toka's unique Morphic Generic Types (like 'A) and the strict rule of prefixing corresponding Shape fields with a single quote (e.g., 'first: 'A) to avoid "Soul Collapse".

2. Error Handling

Toka discards runtime exception-throwing mechanisms. Instead, it leverages algebraic data types, specifically Option<T> and Result<T, E>, to represent and propagate errors. Together with the concise ! short-circuit operator, your error handling will be clearer and more direct than nested pattern matches.

3. Pattern Matching

Pattern matching allows you to deconstruct Shapes and dispatch logic intuitively. Here, you will understand how variable patterns binding and shadowing work under the hood, and learn to combine patterns with if guards for precise range and boundary checks.

4. Concurrency

Toka provides coroutines and threading primitives to build concurrent systems safely.


[!TIP] Mental Model Shift When reading this chapter, focus on alternative solutions to inheritance and runtime polymorphism. Toka achieves polymorphism at compile time through Shape deconstruction, Trait constraints, and Pattern Matching. Combined with the Hat Principle, your code will be both safe and highly efficient.

Generics

Generics allow you to write flexible, reusable code that works with any type while maintaining compile-time safety.

In Toka, when defining custom generics, you typically use the intuitive T (without a single quote) form. The single-quoted 'T (Morphic generic) is only needed in generic container scenarios where compatibility with both soul elements and pointer elements is required.

Generic Functions

Define a generic function using the standard T syntax:

fn identity<T>(value: T) -> T {
    return value
}

auto x = identity(42)      // Works with integers
auto y = identity("hello") // Works with strings

Generic Constraints

Constrain generics with traits:

fn max<T: @PartialOrd>(a: T, b: T) -> T {
    if a > b {
        return a
    }
    return b
}

This function works with any type that implements @PartialOrd.

Generic Data Structures

pub shape Pair<'A, 'B>(
    'first: 'A,
    'second: 'B
)

impl<'A, 'B> Pair<'A, 'B> {
    pub fn new(first: 'A, second: 'B) -> Pair<'A, 'B> {
        return Pair('first = first, 'second = second)
    }
    
    pub fn first(self) -> 'A {
        return self.first
    }
    
    pub fn second(self) -> 'B {
        return self.second
    }
}

When defining shapes with Morphic generic types (those with a single quote prefix like 'A), Toka enforces a strict rule: the corresponding fields must also be prefixed with a single quote (e.g., 'first: 'A). This indicates that these fields can dynamically accept different pointer morphology states, avoiding "soul collapse." However, when calling methods or retrieving fields, you refer to them as normal field names (e.g., self.first instead of self.'first).

Choosing Between Morphic and Standard Generics

When defining custom generics or generic parameters, Toka supports both single-quoted (e.g., 'T) and standard (e.g., T) styles. The core differences and use cases are:

  • T (Standard Generics, without single quote): Generally, custom generics only need this T form. Whether you are writing high-level business logic, custom standard data structures, or helper functions, standard generics are highly recommended. It completely eliminates single-quote syntax noise, making code cleaner and matching standard developer intuition.
  • 'T (Morphic Generics, with single quote): This form is only needed in generic container or low-level infrastructure scenes (such as Vec, HashMap, Slab, or concurrent Channel). Because generic containers must be fully compatible with both soul elements (plain values/structures) and pointer elements (such as unique ^ or shared ~ pointers) to avoid "soul collapse" and perform zero-cost layouts, Morphic generics adapt dynamically to different memory morphologies.

[!NOTE] For the vast majority of daily programming tasks, you only need to use T just like in other traditional programming languages, which greatly simplifies readability.

Type Inference

Toka can infer generic types in most cases, so you rarely need to specify them explicitly:

fn pair<'A, 'B>(a: 'A, b: 'B) -> Pair<'A, 'B> {
    return Pair::new(a, b)
}

auto p = pair(1, "world")  // Pair<i32, str>

Generic Requirements

Use trait bounds to specify what operations a generic type must support:

TraitDescription
@PartialEqEquality comparison (==, !=)
@PartialOrdOrdering comparison (<, >, <=, >=)
@HashHash computation
@encapEncapsulation / interior mutability

Error Handling

Toka provides type-safe error handling through the Result and Option types. This model, rooted in Algebraic Data Types (ADTs), traces its origins back to the ML language family (such as Standard ML and OCaml) and Haskell. Rust later popularized this approach within modern systems programming. Toka adopts this model, combining it with language-level syntax—such as the ! operator for error propagation—to deliver a concise developer experience.

The Option Type

Use Option for values that may or may not exist:

import core/option::{Option}
import std/io::println

fn find_user(id: i32) -> Option<string> {
    if id == 1 {
        return Option<string>::Some(string::from("Alice"))
    }
    return Option<string>::None
}

fn main() -> i32 {
    auto result = find_user(1)
    match result {
        auto Option<string>::Some(&name) => println("Found: {}", name)
        auto Option<string>::None => println("User not found")
    }
    return 0
}

The Result Type

Use Result for operations that can succeed or fail:

import core/result::{Result}

fn divide(a: f64, b: f64) -> Result<f64, string> {
    if b == 0.0 {
        return Result<f64, string>::Err(string::from("Division by zero"))
    }
    return Result<f64, string>::Ok(a / b)
}

The Result type is generic over two parameters:

  • T — The successful value type
  • E — The error type

Pattern Matching on Results

import core/result::{Result}
import std/io::println

fn divide(a: f64, b: f64) -> Result<f64, string> {
    if b == 0.0 {
        return Result<f64, string>::Err(string::from("Division by zero"))
    }
    return Result<f64, string>::Ok(a / b)
}

fn main() -> i32 {
    match divide(10.0, 2.0) {
        auto Result<f64, string>::Ok(value) => println("Result: {}", value)
        auto Result<f64, string>::Err(&msg) => println("Error: {}", msg)
    }
    return 0
}

Short-Circuiting with !

Use the ! operator to propagate errors automatically:

import core/result::{Result}

fn read_file(path: string) -> Result<string, string> {
    return Result<string, string>::Ok(path)
}

fn parse(content: string) -> Result<string, string> {
    return Result<string, string>::Ok(content)
}

fn format_result(parsed: string) -> string {
    return parsed
}

fn process_file(path: string) -> Result<string, string> {
    auto content = read_file(path)!  // Returns early on error
    auto parsed = parse(content)!    // Same here
    return Result<string, string>::Ok(format_result(parsed))
}

This is much cleaner than nested match statements.

The Default Case with or

Provide a default value in case of error:

auto value = parse_int("42").unwrap_or(0)  // Uses 0 if parsing fails

Custom Error Types

You can define structured errors:

import core/result::{Result}

pub shape Config()

pub shape ParseError(
    line: i32,
    col: i32,
    message: string
)

fn parse_config(text: string) -> Result<Config, ParseError> {
    if text.len() == 0 {
        return Result<Config, ParseError>::Err(ParseError(line = 0, col = 0, message = string::from("Empty input")))
    }
    return Result<Config, ParseError>::Ok(Config())
}

Pattern Matching

Pattern matching is one of Toka's most expressive features, allowing you to destructure and match values concisely.

Basic Match

fn describe(n: i32) -> str {
    return match n {
        0 => pass "zero"
        1 => pass "one"
        _ => pass "many"
    }
}

The _ wildcard matches any value — it's the default case.

Range Patterns

Match against ranges:

auto score = 85
auto grade = match score {
        auto s if s >= 0 && s < 60 => { pass "F" }
        auto s if s >= 60 && s < 70 => { pass "D" }
        auto s if s >= 70 && s < 80 => { pass "C" }
        auto s if s >= 80 && s < 90 => { pass "B" }
        auto s if s >= 90 && s <= 100 => { pass "A" }
        _ => { pass "invalid score" }
}

Note that Toka does not support native range patterns (like 0..10). Instead, use variables with if guard expressions to perform range checking.

Matching on Options

import std/io::println
import core/option::Option

fn main() -> i32 {
    auto id = 1
    auto opt: Option<str> = Option<str>::None
    match opt {
        auto Option<str>::Some(&name) => { println("Found: {}", name) }
        auto Option<str>::None => { println("User not found") }
    }
    return 0
}

Matching on Results

import std/io::println
import core/result::Result

fn main() -> i32 {
    auto res: Result<f32, str> = Result<f32, str>::Ok(5.0)
    match res {
        auto Result<f32, str>::Ok(value) => { println("Result: {}", value) }
        auto Result<f32, str>::Err(&msg) => { println("Error: {}", msg) }
    }
    return 0
}

Destructuring Shapes

Pattern match on custom shapes:

import std/io::println

pub shape Point(x: i32, y: i32)

fn origin(p: Point) {
    match p {
        auto pt if pt.x == 0 && pt.y == 0 => { println("At origin") }
        auto pt if pt.y == 0 => { println("On X-axis") }
        auto pt if pt.x == 0 => { println("On Y-axis") }
        _ => { println("Somewhere else") }
    }
}

Match as Expression

Match returns a value, so you can use it in assignments:

auto score = 85
auto grade = match score {
    auto s if s >= 90 && s <= 100 => pass "A"
    auto s if s >= 80 && s < 90 => pass "B"
    auto s if s >= 70 && s < 80 => pass "C"
    auto s if s >= 60 && s < 70 => pass "D"
    _ => pass "F"
}

No Type-Based Matching

Toka does not support matching directly on types (such as writing i32 => ... or str => ... inside a match expression). Any type name used in a branch without standard syntax will be treated as a new variable binding pattern (Variable Pattern), which matches any value and shadows other cases, leading to compilation errors or unreachable branches.

Concurrency

Toka provides lightweight concurrency through tasks and message passing, enabling efficient parallel execution.

Tasks

Spawn concurrent tasks with the task module:

import std/io::println
import std/thread::thread_spawn

fn worker(id: i32) -> i32 {
    println("Worker {} started", id)
    // Do work...
    println("Worker {} done", id)
    return 0
}

fn main() -> i32 {
    auto t1# = thread_spawn<i32>({ => return cede worker(1) })
    auto t2# = thread_spawn<i32>({ => return cede worker(2) })
    
    t1#.join()
    t2#.join()
    return 0
}

MPSC Channels

Communicate between tasks using MPSC (Multi-Producer, Single-Consumer) channels:

import std/channel::channel
import std/thread::thread_spawn
import std/io::println

fn main() -> i32 {
    auto pair# = channel<i32>()
    
    auto tx# = cede pair.tx
    auto rx# = cede pair.rx
    
    thread_spawn<i32>({ [cede tx] => 
        tx#.send(cede 42)
        return cede 0
    })
    
    thread_spawn<i32>({ [cede rx] =>
        auto res_opt = rx#.recv()
        println("Got a message!")
        return cede 0
    })
    
    return 0
}

Atomic Operations

Use atomic types for lock-free concurrent access:

import std/atomic::*

fn main() -> i32 {
    auto counter = AtomicI32::new(0)
    counter.fetch_add(1, Ordering::SeqCst)
    return 0
}

Mutex / Sync

For shared mutable state:

import std/sync::Mutex

fn main() -> i32 {
    auto lock# = Mutex<i32>::new(0:i32)
    
    auto g = lock#.lock().unwrap()
    // Access shared data safely
    // g released automatically when it goes out of scope
    return 0
}

Safety Guarantees

Toka's concurrency model prevents:

  • Data races: Two tasks cannot simultaneously write to the same memory
  • Deadlocks: The compiler analyzes lock ordering
  • Send/Sync violations: Types that are not thread-safe cannot be shared across tasks

Standard Library Overview

Toka's standard library provides a comprehensive set of modules for everyday programming tasks.

Module Structure

The standard library is organized into four tiers:

lib/core/ — Core Language Primitives

These modules provide the fundamental types and traits that the language itself depends on:

ModuleDescription
preludeAuto-imported basics for every Toka program
typesType definitions and limits
traitsCore traits (@Hash, @PartialEq, @PartialOrd)
charUnicode character handling and classification
strString slice operations
stringUTF-8 dynamic string type and views
bytesRead-only binary byte-stream view
memoryMemory management primitives
optionOption<T> type for nullable values
resultResult<T, E> type for error handling
taskFundamental coroutine execution runtime and task base

lib/sys/ — Low-level System Primitives

These modules provide direct bindings and primitives interacting with the operating system and low-level runtime:

ModuleDescription
libcPlatform-dependent C standard library API declarations and bindings
termiosLow-level Tty terminal mode and control attributes configuration
threadLower-level OS native thread interfaces
syncOS-level synchronization primitives and lock implementations
linux / macos / windowsPlatform-specific system calls and bindings

lib/std/ — Standard Library

Ready-to-use standard modules for application development:

ModuleDescription
vecDynamically growing sequential array container (Vec)
dequeDouble-ended queue based on ring buffers (VecDeque)
slabZero-copy generational slab allocator (Slab / SlabID)
hashmapHigh-performance hash table based map (HashMap)
hashsetHash table based unique element collection (HashSet)
btreemapB-Tree based ordered key-value map (BTreeMap)
btreesetB-Tree based ordered unique set (BTreeSet)
heapPriority queue implemented with max/min binary heap (BinaryHeap)
arenaRegion-based arena allocator for high performance allocation (Arena)
ringHigh throughput lock-free ring buffers (RingBuffer)
ioBuffered standard console I/O (stdin / stdout / println)
fsFile system read/write and directory metadata operations
pathCross-platform file path parsing and manipulation (Path / PathBuf)
envEnvironment variables, process arguments, and system context interaction
processSubprocess spawning, state control, and pipe communication
threadOS native thread management and lifecycle control (Thread)
syncThread synchronization primitives (Mutex / Condvar / WaitGroup)
atomicHardware-level atomic operations and lock-free sync primitives
channelThread message passing communication channel (channel / sync_channel)
taskCoroutine task scheduling, context management, and async runtime
netTCP & UDP socket network communication interfaces
mathCommon mathematical functions and limit constants
timeSystem time and monotonic durations (Duration / Instant)
fmtText formatting and debug printing utilities (Format)
errorCommon error traits (Error) and failure base definitions
panicRuntime fatal error triggering, intercepting, and stack hooks

lib/stdx/ — Experimental / Extended (stdx)

New modules that are still evolving or optional extensions:

ModuleDescription
logBasic logging utilities and severity filtering
net/httpHTTP client and server
net/urlURL parsing
net/websocketWebSocket client and server
serde/jsonJSON serialization
crypto/md5MD5 hashing
crypto/sha1SHA-1 hashing
crypto/sha256SHA-256 hashing
encoding/base64Base64 encoding and decoding
encoding/hexHexadecimal encoding and decoding
io/bufioBuffered advanced I/O streams (BufReader / BufWriter)
rand/randPseudo-random number generator and random utilities (Random)
trace/spanMethod execution timing and trace spans
cli/flagCLI flag parsing

Design Philosophy

Toka's standard library follows these principles:

  1. Zero dependencies — Everything is built with pure Toka and the LLVM backend
  2. Consistent API — Similar patterns across different modules
  3. Error-aware — Every fallible operation returns Result or Option
  4. Performant — Compiled to native code with no hidden overhead

IO & File System

Toka's IO module provides file operations, console output, and stream handling — all with a clean, consistent API.

Console Output

import std/io::{println, print}

println("Hello with newline")  // Prints with trailing newline
print("No newline here")       // Prints without trailing newline

Reading Files

import std/fs
import core/result::Result
import std/io::IoStringResult

fn read_config(path: string) -> IoStringResult {
    return fs::read_to_string(path)
}

Writing Files

import std/fs
import core/result::Result

fn save_data(path: string, data: string) -> Result<bool, string> {
    return fs::write_string(path, data.as_str())
}

File System Operations

The fs module provides standard file operations:

import std/fs
import std/io::println
import core/option::Option

fn manage_files() {
    auto path = string::from("output")
    if fs::exists(path.clone()) {
        fs::remove_dir(path)
    }
    
    fs::create_dir(string::from("output"))
    
    auto dir# = fs::read_dir(string::from("."))
    loop {
        auto entry = dir#.next()
        if entry.is_none() { break }
        println("{}", entry.unwrap())
    }
}

Working with Paths

import std/io::println
import std/path

fn example() {
    auto full = path::join(string::from("dir"), string::from("file.txt"))
    println("{}", full.c_str())
    
    auto ext = path::extension(string::from("data.json"))
    println("{}", ext.c_str())
    
    auto stem = path::file_stem(string::from("data.json"))
    println("{}", stem.c_str())
}

Environment Variables

import std/io::println
import std/env
import core/option::Option

fn example() {
    auto home_opt = env::var(string::from("HOME"))
    auto home = home_opt.unwrap_or(string::from("/tmp"))
    println("Home directory: {}", home)
    
    env::set_var(string::from("MY_APP_DEBUG"), string::from("true"))
}

Collections

Toka provides a rich set of data structures for storing and organizing data efficiently.

Vec (Dynamic Array)

import std/io::println
import std/vec::Vec

fn example() {
    auto numbers# = Vec<i32>::new()
    
    numbers#.push(1)
    numbers#.push(2)
    numbers#.push(3)
    
    println("{}", numbers.at(0))  // 1
    
    auto i# = 0:usize
    loop i < numbers.len() {
        println("{}", numbers.at(i))
        i = i + 1:usize
    }
}

Map (Hash Map)

import std/io::println
import std/hashmap::HashMap
import core/option::Option
import core/primitives

fn example() {
    auto scores# = HashMap<i32, i32>::new()
    
    scores#.insert(1, 95)
    scores#.insert(2, 87)
    
    match scores.get(1) {
        auto Option<i32>::Some(score) => { println("ID 1: {}", score) }
        auto Option<i32>::None => { println("Not found") }
    }
}

BTreeMap (Ordered Map)

import std/io::println
import std/btreemap::BTreeMap
import core/primitives

fn example() {
    auto items# = BTreeMap<str, i32>::new()
    
    items#.insert("apple", 5)
    items#.insert("banana", 3)
    items#.insert("cherry", 8)
    
    println("Iterated")
}

BTreeSet (Ordered Set)

import std/io::println
import std/btreeset::BTreeSet
import core/primitives

fn example() {
    auto unique# = BTreeSet<i32>::new()
    
    unique#.insert(3)
    unique#.insert(1)
    unique#.insert(2)
    unique#.insert(1)  // Duplicate, ignored
    
    println("{}", unique.len())
}

Deque (Double-Ended Queue)

import std/io::println
import std/deque::VecDeque

fn example() {
    auto queue# = VecDeque<str>::new()
    
    queue#.push_back("first")
    queue#.push_back("second")
    queue#.push_front("priority")
    
    queue#.pop_front()
    println("{}", queue.len())
}

Slab (Generational Slab Allocator)

Toka completely abolishes linked lists to embrace the contiguous physical memory topology of modern CPUs. Instead, the standard library introduces the generational slab allocator std/slab::Slab. It manages objects as slots inside a contiguous memory buffer (Vec), supporting rapid $O(1)$ insertion, removal, and retrieval. It employs a SlabID generational check technique to fully eliminate the risk of ABA problems or stale index lookups.

The Slab's lookup methods (get and get_mut) implement advanced lifetime dependency declarations (<- self), returning zero-copy Option<&'T> and Option<&#'T> borrows.

import std/slab::{Slab, SlabID}
import std/io::{println}
import core/option::{Option}

shape Entity (
    name: string,
    val: i32
)

fn main() -> i32 {
    auto slab# = Slab<Entity>::new()

    // 1. Insert elements, returning a SlabID containing both index and generation
    auto id1 = slab#.insert(Entity(name = string::from("alpha"), val = 10))
    auto id2 = slab#.insert(Entity(name = string::from("beta"), val = 20))

    // 2. Retrieve zero-copy borrowed views safely
    auto e1_opt = slab.get(id1.clone())
    if e1_opt.is_some() {
        auto &e1 = e1_opt.unwrap()
        println("ID1 val: {}", e1.val as i64) // 10
    }

    // 3. Remove an element and reclaim its slot
    auto removed = slab#.remove(id1.clone())

    // 4. Insert another element: Slab automatically reuses Slot 0!
    // However, the generation counter automatically increments to 2!
    auto id3 = slab#.insert(Entity(name = string::from("gamma"), val = 30))

    // 5. Querying with the stale id1 now safely returns None, preventing ABA reads!
    auto old_opt = slab.get(id1)
    assert(old_opt.is_none(), "generational ID should prevent ABA stale read")

    return 0
}

Heap (Priority Queue)

import std/io::println
import std/heap::BinaryHeap
import core/primitives

fn example() {
    auto max_cmp: fn(i32, i32) -> bool = { a, b => a > b }
    auto heap# = BinaryHeap<i32>::new(max_cmp)
    heap#.push(5)
    heap#.push(10)
    heap#.push(3)
    
    heap#.pop()
    println("10")
}

Set

import std/io::println
import std/hashset::HashSet
import core/primitives

fn example() {
    auto tags# = HashSet<i32>::new()
    tags#.insert(1)
    tags#.insert(2)
    tags#.insert(3)
    
    if tags.contains(2) {
        println("Found 2!")
    }
}

Networking

Toka's networking module provides TCP, UDP, and HTTP capabilities for building networked applications.

HTTP Client

Make HTTP requests with the stdx/net/http module:

import core/result::Result

// Note: HTTP client is under development
fn fetch(url: string) -> Result<string, string> {
    // auto response = http::get(url)!
    // return Ok(response.body)
    return Result<string, string>::Ok(string::from("Response"))
}

HTTP Server

Build a simple HTTP server using the stdx/net/http module:

import stdx/net/http::{HttpResponse, HttpRequest}

// Note: HTTP Server is built by integrating std/net with stdx/net/http
fn main() -> i32 {
    // auto listener# = TcpListener::bind(addr)
    // auto stream# = listener#.accept()
    // auto req# = parse_http_request(req_str)
    return 0
}

TCP Connections

Use the net module for raw TCP:

import std/net::TcpStream
import std/io::println
import core/result::Result

fn handle_client(stream#: TcpStream) {
    auto buf: [u8; 1024] = [0:u8; 1024]
    auto *buf_ptr# = &buf[0] as *u8
    auto res = stream#.read(*buf_ptr, 1024:usize)
    match res {
        auto Result<usize, string>::Ok(n) => {
            println("Received {} bytes", n)
            stream#.write_string(string::from("ACK"))
        }
        auto Result<usize, string>::Err(&e) => {
            println("Error")
        }
    }
}

WebSocket

For real-time bidirectional communication, use the stdx/websocket module:

import std/io::println

// Note: WebSocket is under development
fn echo_server() {
    // auto ws = websocket::Server::new()
    // ws.on_message(|msg| => println("Got: {}", msg))
    // ws.listen(9000)
}

URL Parsing

import std/io::println
import core/result::Result
import stdx/net/url::{Url, parse_url}

fn example() {
    auto url_res = parse_url(string::from("https://api.example.com:8080/data?id=1#top"))
    match url_res {
        auto Result<Url, string>::Ok(&url) => {
            println("Host: {}", url.host)
            println("Port: {}", string::from_int(url.port as i32))
        }
        auto Result<Url, string>::Err(&err) => {
            println("Error: {}", err)
        }
    }
}

Time & Math

Toka provides comprehensive time handling and mathematical functions for scientific and systems programming.

Getting Current Time

import std/time::{SystemTime}
import std/io::println

fn example() {
    auto now = SystemTime::now()
    // println("Current timestamp: {}", now.unix())
}

Time Formatting

import std/time::{SystemTime}
import std/io::println

fn format_date() {
    auto now = SystemTime::now()
    // auto formatted = now.format("%Y-%m-%d %H:%M:%S")
    // println("Date: {}", formatted)
}

Durations and Timers

import std/time::{Instant}
import std/io::println

fn measure() {
    auto start = Instant::now()
    
    // Do some work...
    
    auto elapsed = start.elapsed()
    println("Elapsed: {} ms", elapsed.as_millis())
}

Math Functions

import std/math
import std/io::println

fn calculations() {
    auto x = 3.14159
    
    println("{}", math::sin(x))       // Sine
    println("{}", math::cos(x))       // Cosine
    println("{}", math::sqrt(16.0))   // Square root → 4.0
    // println(str(math::abs(-5)))      // Absolute value → 5
    // println(str(math::pow(2.0, 8)))  // Power → 256.0
}

Random Numbers

import stdx/rand/rand::{Random}
import std/io::println

fn gen_random() {
    auto rng# = Random::new(123:u64, 1:u64)
    auto dice = rng#.next_u32() % 6 + 1
    println("You rolled: {}", dice)
    
    // Note: secure_bytes is under development
    // auto secure = rand::secure_bytes(32)
}

Math Constants

// Mathematical limits (from lib/core/types.tk)
pub const MY_LIMITS = (
    u8 = (min = 0, max = 255, bits = 8),
    i32 = (min = -2147483648, max = 2147483647, bits = 32),
    u64 = (min = 0, max = 18446744073709551615, bits = 64),
    f32 = (
        min_positive = 1.17549435e-38,
        epsilon = 1.19209290e-07,
        bits = (nan = 0x7fc00000, infinity = 0x7f800000, neg_zero = 0x80000000)
    )
)

fn dummy_limits() {}

Serialization

Toka provides built-in support for serializing and deserializing data, with JSON support out of the box.

JSON Encoding

Serialize data to JSON:

import stdx/serde/json
import std/io::println

pub shape Person(
    name: string,
    age: i32,
    active: bool
)

fn encode() {
    auto person = Person(name = string::from("Alice"), age = 30, active = true)
    // auto json_str = json::to_json(person)
    // println("{}", json_str)  // {"name":"Alice","age":30,"active":true}
}

JSON Decoding

Parse JSON back into Toka types:

import stdx/serde/json
import std/io::println
import core/result::Result

pub shape Person(
    name: string,
    age: i32,
    active: bool
)

fn decode() {
    auto data = "{\"name\":\"Bob\",\"age\":25,\"active\":false}"
    // auto person_res = json::deserialize_shape<Person>(data)
}

Base64 Encoding

import stdx/encoding/base64
import std/io::println

fn example() {
    auto original = string::from("Hello, Toka!")
    auto encoded = base64::encode_str(original.as_str())
    println("{}", encoded)  // SGVsbG8sIFRva2Eh
    
    // Note: base64::decode is under development
    // auto decoded = base64::decode(encoded)!
}

Hex Encoding

import stdx/encoding/hex
import std/io::println

fn example() {
    auto bytes: [u8; 5] = [0x48, 0x65, 0x6C, 0x6C, 0x6F]
    auto hex_str = hex::encode_hex(*bytes as *[u8], 5:usize)
    println("{}", hex_str)  // 48656C6C6F
    
    // Note: hex::decode is under development
    // auto decoded = hex::decode(hex_str)!
}

Custom Serialization

Implement the @Serialize trait for custom types:

import stdx/serde/json::{@ToJson}

pub shape Person(name: string, age: i32, active: bool)

impl Person@ToJson {
    pub fn write_json(self, buf#: string) -> string {
        buf#.push_str("{\"name\":\"")
        buf#.push_str(self.name.as_str())
        buf#.push_str("\",\"age\":")
        buf#.push_str(string::from_int(self.age).as_str())
        buf#.push_str("}")
        return buf
    }
}

Cryptography

Toka provides a standard cryptography module with support for common hash algorithms.

MD5 Hashing

import std/io::println
import stdx/crypto/md5::Md5

fn example() {
    auto md5# = Md5::new()
    md5#.update("Hello, Toka!")
    auto hash = md5#.finalize_hex()
    println("MD5: {}", hash)
}

SHA-1

import std/io::println
import stdx/crypto/sha1::Sha1

fn example() {
    auto sha1# = Sha1::new()
    sha1#.update("Hello, Toka!")
    auto hash = sha1#.finalize_hex()
    println("SHA1: {}", hash)
}

SHA-256

import std/io::println
import stdx/crypto/sha256::Sha256

fn example() {
    auto sha256# = Sha256::new()
    sha256#.update("Hello, Toka!")
    auto hash = sha256#.finalize_hex()
    println("SHA256: {}", hash)
}

File Hashing

Hash the contents of a file:

import std/fs
import stdx/crypto/sha256::Sha256
import core/result::Result

fn verify_file(path: string) -> Result<bool, string> {
    auto content = fs::read_to_string(path).unwrap()
    auto sha256# = Sha256::new()
    sha256#.update(content.as_str())
    auto computed = sha256#.finalize_hex()
    
    return Result<bool, string>::Ok(computed.len() > 0:usize)
}

Secure Random

For cryptographic applications:

import stdx/rand/rand::Random

fn generate_key() -> u64 {
    // Pseudorandom bytes (Not secure, for demonstration)
    auto rng# = Random::new(12345:u64, 1:u64)
    return rng#.next_u64()
}

The crypto module is useful for:

  • Password hashing and verification
  • File integrity checking
  • Data signing and verification
  • Secure random number generation

Projects

Putting theory into practice is the single best way to truly master a systems programming language. Having mastered Toka's language basics, the Hat Principle, and advanced abstractions, this chapter will guide you through three carefully designed practical projects to complete your transformation from a syntax learner to a systems developer.

These projects are not detached "toy code." Instead, they directly target the three pillars of low-level software engineering: systems tool development, high-performance concurrent networking, and language/text parsing.


Practical Roadmap

The three projects in this chapter progress in a step-by-step fashion to help you gradually build robust system-level development mental models:

flowchart TD
    Step1("**Step 1: CLI Tool**<br>Familiarize with stdx/cli/flag standard APIs")
    Step2("**Step 2: HTTP Server**<br>Master raw TCP & Hat concurrency safety")
    Step3("**Step 3: Regex Engine**<br>Exercise Token stream parsing & pattern matching")
    Champ("🏆 **Full-fledged Systems Developer**")

    Step1 --> Step2 --> Step3 --> Champ

    style Champ stroke:#a855f7,stroke-width:2px;

1. CLI Tool with stdx/cli/flag

  • Engineering Value: This is your first practical project. You will move away from outdated multi-level chain calls and learn to leverage the official standard stdx/cli/flag extension package. You will elegently parse flags, handle boolean options using the non-chained mutable self# API, and safely collect and filter positional arguments with pattern matching.

2. High-Performance HTTP Server

  • Engineering Value: How do you build highly concurrent, low-level network services in Toka? In this project, you will start with low-level TCP listening (TcpListener) and connection acceptance (accept()). Combined with multi-threaded concurrency, you will handcraft an RFC-compliant concurrent HTTP response server. This is a comprehensive test of your understanding of the Hat Principle and Toka's I/O modules.

3. Regex Engine

  • Engineering Value: Text matching and compiler frontends are fascinating areas of systems programming. You will challenge yourself to implement a micro regular expression engine from scratch. In this project, you will deeply train your control over token streams, state machine transitions, deep tree structure representations, and learn to leverage Toka's elegant match pattern matching for complex lexical and syntactic branching.

[!IMPORTANT] Development & Debugging Preparation Before starting each project, make sure you have correctly configured your toka command-line environment and that the tokac compiler works properly. You can quickly run and debug your project using the following basic command:

toka run src/main.tk -- -n Toka

In each project chapter, detailed unit tests and execution examples are provided. It is highly recommended that you type every line of code yourself and observe compiler error outputs. This will give you a deep, visceral intuition for Toka's "Handle" and "Soul" rebinding rules.

CLI Tool with stdx/cli/flag

In this project, we'll build a command-line tool using Toka and the standard stdx/cli/flag argument parser library.

Setting Up

Create a new project:

toka init my-cli
cd my-cli

Since stdx/cli/flag is a standard library extension in Toka, you do not need to add any external dependencies via the package manager. It is ready to use out-of-the-box!

Defining Arguments

import stdx/cli/flag::{Parser, ParsedArgs}
import std/env
import std/io

fn main() -> i32 {
    // Parser::new takes the program name and a brief description
    auto parser# = Parser::new(string::from("my-cli"), string::from("A sample CLI tool built with Toka"))
    
    // Add options to the parser
    parser#.add_string(string::from("name"), 110:char, string::from("World"), string::from("Your name"))
    parser#.add_bool(string::from("verbose"), 118:char, false, string::from("Enable verbose output"))

    auto args = env::args()
    auto res = parser.parse(args)
    match res {
        auto Result<ParsedArgs, string>::Ok(parsed) => {
            auto who = parsed.get_string(string::from("name"))
            io::println("Hello, %s!", who.c_str())
            
            if parsed.get_bool(string::from("verbose")) {
                io::println("[Verbose] Running with debug output")
            }
        }
        auto Result<ParsedArgs, string>::Err(&err) => {
            if err == string::from("help requested") {
                parser.print_help()
                return 0
            }
            io::println("Error: %s", err.c_str())
            return 1
        }
    }
    return 0
}

Running

toka run src/main.tk -- -n Toka
# Output: Hello, Toka!

toka run src/main.tk -- -n Toka -v
# Output: Hello, Toka!
# [Verbose] Running with debug output

Advanced Argument Handling

Toka's current stdx/cli/flag library provides basic options and flags parsing with types like bool, i64, f64, and string.

Positional arguments are captured automatically and can be fetched from the parsed arguments using positionals():

auto pos_args = parsed.positionals()
// pos_args is a Vec<string> containing any arguments not matching flags or options

For complex command-line interfaces requiring nested subcommands (like git status or docker run), you can manually match on pos_args to delegate execution to different parser configurations.

HTTP Server

Build a fully-functional HTTP server using Toka's modern networking library.

Basic Server

Toka's HTTP engine is located in stdx/net/http. You can build a lightweight HTTP server by binding a TcpListener from std/net and processing incoming connections:

import std/io::{println}
import stdx/net/http::{HttpRequest, HttpResponse, parse_http_request}
import std/net::{TcpListener, TcpStream, Ipv4Addr, SocketAddrV4}
import core/result::{Result}

fn handle_client(stream#: TcpStream) {
    auto buf: [char; 1024] = [0 as char; 1024]
    auto *buf_ptr# = &buf[0] as *u8
    
    auto read_res = stream#.read(*buf_ptr, 1024:usize)
    match read_res {
        auto Result::Ok(n) => {
            if n > 0:usize {
                auto req_str = string::from_with_len(&buf[0] as *char, n as i32)
                auto req# = parse_http_request(req_str)
                
                auto resp# = HttpResponse::not_found()
                if req.path.eq(string::from("/")) {
                    resp = HttpResponse::html(string::from("<h1>Hello, Toka!</h1>"))
                }
                
                auto resp_str = resp#.to_string()
                auto *ptr = resp_str.c_str() as *u8
                stream#.write(*ptr, resp_str.len() as usize)
            }
        }
        _ => {}
    }
    stream#.close()
}

fn main() -> i32 {
    // Demonstration server setup
    return 0
}

API with JSON Responses

You can use the @ToJson trait from stdx/serde/json to automatically serialize custom shape objects and return them as JSON responses:

import stdx/net/http::{HttpResponse}
import stdx/serde/json::{serialize_shape, to_json, @ToJson}

pub shape Message(text: string, status: string)

impl Message@ToJson {
    pub fn write_json(self, buf#: string) -> string {
        return serialize_shape(self, buf)
    }
}

fn api_status() -> HttpResponse {
    auto msg = Message(
        text = string::from("Server is running"),
        status = string::from("ok")
    )
    auto json_body = to_json(msg)
    return HttpResponse(
        status_code = 200,
        content_type = string::from("application/json"),
        body = json_body
    )
}

fn main() -> i32 {
    return 0
}

Route Parameters

You can easily match dynamic parts of a URL path to extract route parameters manually:

import stdx/net/http::{HttpRequest, HttpResponse}

fn handle_user_route(req: HttpRequest) -> HttpResponse {
    // Match dynamic path "/api/users/<id>"
    if req.path.as_str().starts_with("/api/users/") {
        auto user_id = req.path.substr(11, req.path.len() - 11)
        auto body# = string::from("User ID: ")
        body#.push_view(user_id)
        return HttpResponse(
            status_code = 200,
            content_type = string::from("text/plain"),
            body = body
        )
    }
    return HttpResponse::not_found()
}

fn main() -> i32 {
    return 0
}

Middleware

Wrap your routing handlers to inject custom middleware functionality, such as request logging or execution timing:

import stdx/net/http::{HttpRequest, HttpResponse}
import std/io::{println}

fn logger_middleware(req: HttpRequest, next: fn(HttpRequest) -> HttpResponse) -> HttpResponse {
    println("Request Path: {}", req.path)
    auto res = next(req)
    println("Response Status: {}", string::from_int(res.status_code))
    return res
}

fn main() -> i32 {
    return 0
}

Static Files

Serve local assets by reading files dynamically using the std/fs module:

import stdx/net/http::{HttpResponse}
import std/fs::{read_to_string}
import core/result::{Result}

fn serve_static_file(path: string) -> HttpResponse {
    auto file_content = read_to_string(path)
    match file_content {
        auto Result::Ok(&content) => {
            return HttpResponse(
                status_code = 200,
                content_type = string::from("text/html"),
                body = content.clone()
            )
        }
        _ => return HttpResponse::not_found()
    }
}

fn main() -> i32 {
    return 0
}

Full Example

A complete HTTP server featuring routing, HTML rendering, and custom API JSON responses:

import std/io::{println}
import stdx/net/http::{HttpRequest, HttpResponse, HttpMethod, parse_http_request}
import std/net::{TcpListener, TcpStream, Ipv4Addr, SocketAddrV4}
import core/result::{Result}

fn route_request(req: HttpRequest) -> HttpResponse {
    auto is_get# = false
    match req.method {
        auto HttpMethod::GET => { is_get = true }
        _ => {}
    }
    
    if is_get && req.path.eq(string::from("/status")) {
        return HttpResponse(
            status_code = 200,
            content_type = string::from("application/json"),
            body = string::from("{\"status\":\"ok\"}")
        )
    }
    
    if is_get && req.path.eq(string::from("/")) {
        return HttpResponse::html(string::from("<h1>Toka HTTP Server</h1>"))
    }
    
    return HttpResponse::not_found()
}

fn handle_connection(stream#: TcpStream) {
    auto buf: [char; 1024] = [0 as char; 1024]
    auto *buf_ptr# = &buf[0] as *u8
    
    auto read_res = stream#.read(*buf_ptr, 1024:usize)
    match read_res {
        auto Result::Ok(n) => {
            if n > 0:usize {
                auto req_str = string::from_with_len(&buf[0] as *char, n as i32)
                auto req# = parse_http_request(req_str)
                auto resp# = route_request(req)
                auto resp_str = resp#.to_string()
                
                auto *ptr = resp_str.c_str() as *u8
                stream#.write(*ptr, resp_str.len() as usize)
            }
        }
        _ => {}
    }
    stream#.close()
}

fn main() -> i32 {
    // Demonstration server setup
    return 0
}

Regex Engine

Build a regular expression engine using the toka-regex library, which implements a Thompson NFA (Nondeterministic Finite Automaton).

What is Thompson NFA?

A Thompson NFA compiles a regex pattern into a state machine that can match strings efficiently. It works by:

  1. Compiling the pattern into a graph of states
  2. Simulating all possible paths simultaneously
  3. Accepting if any path reaches an accept state

Basic Usage

import regex::{Regex}

import std/io::println

fn example() {
    auto re = Regex::new("hello|world")
    
    if re.test(string::from("hello world")) {
        println("Match found!")
    }
}

Pattern Syntax

The engine supports standard regex patterns:

PatternMatches
abcLiteral string "abc"
`ab`
a*Zero or more "a"s
a+One or more "a"s
a?Optional "a" (zero or one)
[abc]Character class: a, b, or c
[^abc]Negated character class
.Any single character

Matching

import std/io::println
import core/option::Option

fn example() {
    auto re = Regex::new("\\d+")  // One or more digits
    
    match re.find(string::from("Order #42")) {
        auto Option::Some(m) => println("Found: {}", m.text),
        auto Option::None => println("No match")
    }
}

Replacing

import std/io::println

fn example() {
    auto re = Regex::new("\\s+")
    auto result = re.replace(string::from("hello    world"), string::from(" "))
    println("{}", result)  // "hello world"
}

The Engine Architecture

The regex engine is built in pure Toka:

  • Pattern Compiler — Parses the regex string into NFA states
  • State Simulator — Runs the NFA against input text
  • Matcher — Handles capture groups and position tracking

This makes it a great example of how Toka can implement non-trivial algorithms with clean, safe code.

Appendix

To help you fully master the Toka language, this Appendix provides a wealth of reference materials and practical development tools.

For developers coming to Toka from other mainstream languages (such as C++, Rust, or Go), this appendix is designed to help you smoothly transition and migrate to Toka.


Appendix Reference Directory

This appendix consists of the following three core reference modules:

1. Toka vs. Other Languages

  • Contents: While Toka draws inspiration from various modern languages, it introduces unique concepts (such as dereferencing "wearing/removing a hat," which is the exact opposite of C++). This chapter provides clear comparison tables and side-by-side code snippets comparing Toka with C/C++, Rust, and Go to help you quickly build an accurate comparative mental model.

2. Migration Guide

  • Contents: How do you smoothly migrate existing code logic to Toka? Written for experienced engineers, this chapter focuses on translating traditional "object-oriented" or "imperative pointer-passing" logic into highly efficient systems-level code that conforms to Toka's Shape deconstruction, Hat rebinding, and zero-copy implicit reference capture paradigms.

3. FAQ

  • Contents: A compilation of the most common pitfalls and questions from the developer community. From beginner confusion like "why can't I use curly braces to define Shapes" to deeper questions like "how does pointer rebinding work inside method calls," this chapter offers direct answers and diagnostic compiler error explanations to help resolve build-time issues.

[!NOTE] Continuous Learning & Community Support Programming is an art of practice, and Toka is rapidly evolving. If you encounter any issues or discover bugs while coding or reading this manual, you are highly encouraged to submit an Issue or Pull Request to the official repository. We hope this manual becomes a helpful companion in exploring the low-level systems world!

Toka vs Other Languages

How does Toka compare to other languages in the systems programming space?

Toka vs Rust

AspectRustToka
Memory safetyBorrow checker with lifetimesHat Principle + PAL Checker
Learning curveSteep (lifetimes, ownership)Gentle (hat tokens are intuitive)
Compile speedSlow (monomorphization)Fast (LLVM backend, ~80k loc/s)
SyntaxComplex (macros, attributes)Clean, Go-like readability
GCNoNo (compile-time managed)
C interopVia extern "C"Native C interop without FFI overhead

Toka vs Go

AspectGoToka
Memory modelGC with runtimeCompile-time ownership
PerformanceGood (but GC pauses)Native speed, zero overhead
SafetyGC handles memoryPAL Checker at compile time
ConcurrencyGoroutines + channelsTasks + MPSC channels
Binary size~5-20 MB (includes runtime)~250 KB (no runtime)

Toka vs C

AspectCToka
SafetyManual memory, buffer overflowsHat Principle prevents UB
Modern featuresNone (pre-1989 design)Generics, pattern matching, traits
Compile speedFastFast (compiles itself in <1s)
PortabilityUniversalLLVM backend, portable

Toka vs Zig

AspectZigToka
PhilosophyBetter CMemory safety without annotations
MemoryManual (allocator passed)Automatic (compile-time tracking)
MetaprogrammingcomptimeCompile-time features
Error handlingError union typesResult/Option with ! operator
Build systemBuilt-inpackage.tk (declarative)

Migration Guide

Migrating from other languages to Toka? Here's what you need to know.

From Rust

Ownership model:

  • Rust: Borrow checker with 'a lifetimes
  • Toka: Hat Principle with ^ syntax — no lifetime annotations needed

Error handling:

  • Rust: Result<T, E> with ? operator
  • Toka: Same Result<T, E> with ! operator

Pattern matching:

  • Rust: match with exhaustive checking
  • Toka: Same match with wildcard _

Traits:

  • Rust: trait Foo { fn bar(&self); }
  • Toka: pub trait Foo { fn bar(self); } with @ syntax

From Go

Error handling:

  • Go: if err != nil everywhere
  • Toka: Result/Option with ! operator — cleaner and safer

Concurrency:

  • Go: Goroutines + channels
  • Toka: Tasks + MPSC channels

Interfaces:

  • Go: Implicit interface satisfaction
  • Toka: Explicit trait implementation with @ syntax

From C

Pointers:

  • C: Raw pointers * with no safety
  • Toka: Tracked hats ^ with PAL Checker

Memory:

  • C: Manual malloc/free
  • Toka: Automatic compile-time memory management

Build:

  • C: Makefile / CMakeLists.txt
  • Toka: package.tk (declarative)

From Python

Dynamic vs Static:

  • Python: Dynamic typing, runtime errors
  • Toka: Static typing, compile-time safety

Performance:

  • Python: Interpreted, slow
  • Toka: Compiled, native speed (via LLVM)

Quick Syntax Reference

ConceptToka
Variableauto x = 10
Mutableauto x# = 10
Functionfn add(a: i32, b: i32) -> i32
If/elseif cond { } else { }
Loopfor i in 0..10 { }
Matchmatch val { 1 => "one", _ => "other" }
Comment// Single line
Importimport std/io::println
Returnreturn value

Frequently Asked Questions

General

Q: Is Toka production-ready?

Toka is currently in beta (v0.9.8-03). It's suitable for personal projects, prototyping, and experimentation. The 1.0 release is planned with a focus on production stability.

Q: What platforms does Toka support?

Linux, macOS, and Windows are supported. The LLVM backend provides cross-compilation capabilities.

Q: Is there a package manager?

Toka has a built-in package manager via toka add. Official library registry at pkg.tokalang.dev.

Language Design

Q: How is Toka different from Rust?

Toka achieves memory safety through the Hat Principle instead of a borrow checker. This means no lifetime annotations — just simple hat (^) tokens that make ownership visible in the syntax.

Q: Does Toka have a garbage collector?

No. Memory is managed at compile time through the PAL Checker. There is no runtime GC overhead.

Q: Is Toka compatible with C libraries?

Yes. Toka has native C interop without FFI overhead. You can call C functions directly.

Learning

Q: Do I need to know C or Rust to learn Toka?

Not at all. Toka's syntax is clean and Go-like. If you know any programming language, you can learn Toka in a weekend.

Q: Where can I find more examples?

Check out the examples/ directory in the Toka repository and the tokalibs collection of community libraries.

Q: Is there a community or forum?

Join the Toka community on GitHub Discussions at github.com/tokalang/toka.

Technical

Q: How fast is Toka?

Toka compiles at approximately 80,000 lines of code per second (Clang backend) and produces optimized native binaries via LLVM 20. Performance is comparable to C for equivalent code.

Q: How large are Toka binaries?

A minimal HTTP server binary is approximately 250 KB — no runtime, no VM, just native code.

Q: Does Toka support multithreading?

Yes. Toka provides tasks, MPSC channels, atomic operations, and mutexes for concurrent programming.