Skip to content

Latest commit

 

History

History
866 lines (638 loc) · 14.8 KB

File metadata and controls

866 lines (638 loc) · 14.8 KB

NAAb Language User Guide

Version: 1.1.0 Last Updated: April 29, 2026

Table of Contents

  1. Introduction
  2. Getting Started
  3. Language Basics
  4. Working with Data
  5. Functions
  6. Control Flow
  7. Error Handling
  8. Standard Library
  9. Multi-File Applications
  10. Block Assembly
  11. Advanced Features
  12. Best Practices

Introduction

NAAb is a modern polyglot orchestration language designed for seamlessly integrating code across multiple programming languages within a single application. NAAb's core philosophy is: Orchestrate in NAAb, Compute in the Best Language for the Task.

Key Features

  • Polyglot by design: Execute code blocks in 12 languages — Python, JavaScript, Shell, Go, Nim, Rust, C++, C#, Ruby, PHP, Zig, and Julia — all within << >> blocks
  • Bytecode VM: Stack-based bytecode compiler and virtual machine as the default execution engine (~8x faster than tree-walking)
  • Governance engine: 50+ built-in checks, taint tracking, 3-tier enforcement (HARD/SOFT/ADVISORY), agent roles, and CI/CD integration
  • Pipeline syntax: Chain operations with |> operator
  • Rich stdlib: 19 modules (array, string, math, json, file, time, env, io, csv, regex, crypto, debug, dict, path, log, uuid, validate, process, bolo)
  • NaN-boxing: 8-byte inline values for int/double/bool/null — zero heap allocation for primitives
  • Type-safe composition: Validate block compatibility before execution
  • Exception handling: try/catch with stack traces
  • Module system: Import/export for code organization

Getting Started

Installation

Build

cmake -B build cmake --build build -j4

Install (symlink to PATH)

ln -sf $(pwd)/build/naab-lang /usr/local/bin/naab


### Your First Program

Create `hello.naab`:

```naab
print("Hello, NAAb!")

Run it:

naab hello.naab

Output:

Hello, NAAb!

Interactive REPL

~/naab-repl

Try these commands:

> let x = 42
> print(x)
42
> let sum = 10 + 32
> print(sum)
42

Language Basics

Variables

let name = "Alice"
let age = 30
let score = 95.5
let active = true

Variables are dynamically typed but support type annotations:

let count: int = 42
let name: string = "Bob"

Data Types

  • Int: 42, -10, 0
  • Float: 3.14, -0.5, 2.0
  • String: "hello", 'world'
  • Bool: true, false
  • Array: [1, 2, 3], ["a", "b", "c"]
  • Dict: {"key": "value", "count": 42}

Operators

Arithmetic:

let a = 10 + 5    // 15
let b = 10 - 5    // 5
let c = 10 * 5    // 50
let d = 10 / 5    // 2
let e = 10 % 3    // 1

Comparison:

let eq = (5 == 5)   // true
let ne = (5 != 3)   // true
let lt = (3 < 5)    // true
let le = (5 <= 5)   // true
let gt = (5 > 3)    // true
let ge = (5 >= 5)   // true

Logical:

let and = true && false    // false
let or = true || false     // true
let not = !true            // false

Short-circuit evaluation:

// Second expression not evaluated if first is false
if (x != 0 && (100 / x) > 5) {
    print("Safe division")
}

Working with Data

Arrays

import "stdlib" as std

let numbers = [1, 2, 3, 4, 5]

// Access
print(numbers[0])  // 1

// Length
print(std.length(numbers))  // 5

// Add element
numbers = std.push(numbers, 6)  // [1, 2, 3, 4, 5, 6]

// Remove last
let last = std.pop(numbers)  // 6

// Reverse
let reversed = std.reverse(numbers)  // [5, 4, 3, 2, 1]

// Check contains
let has = std.contains(numbers, 3)  // true

// Join to string
let joined = std.join(numbers, ",")  // "1,2,3,4,5"

Higher-Order Array Functions

// Map - transform array
fn double(x) {
    return x * 2
}
let doubled = std.map_fn(numbers, double)  // [2, 4, 6, 8, 10]

// Filter - select elements
fn is_even(x) {
    return x % 2 == 0
}
let evens = std.filter_fn(numbers, is_even)  // [2, 4]

// Reduce - aggregate
fn add(acc, x) {
    return acc + x
}
let sum = std.reduce_fn(numbers, add, 0)  // 15

// Find - first match
fn greater_than_3(x) {
    return x > 3
}
let found = std.find(numbers, greater_than_3)  // 4

Strings

import "stdlib" as std

let text = "Hello, World!"

// Length
print(std.length(text))  // 13

// Case conversion
let upper = std.upper(text)  // "HELLO, WORLD!"
let lower = std.lower(text)  // "hello, world!"

// Trim whitespace
let trimmed = std.trim("  hello  ")  // "hello"

// Split
let words = std.split(text, ", ")  // ["Hello", "World!"]

// Replace
let replaced = std.replace(text, "World", "NAAb")  // "Hello, NAAb!"

// Check contains
let has = std.contains(text, "World")  // true

// Check prefix/suffix
let starts = std.starts_with(text, "Hello")  // true
let ends = std.ends_with(text, "!")  // true

// Substring
let sub = std.substring(text, 0, 5)  // "Hello"

// Find index
let index = std.index_of(text, "World")  // 7

// Repeat
let repeated = std.repeat("ha", 3)  // "hahaha"

Dictionaries

let person = {
    "name": "Alice",
    "age": 30,
    "city": "Boston"
}

// Access
print(person["name"])  // "Alice"

// Modify
person["age"] = 31

// Check key exists
// (use try/catch for safe access)

Functions

Function Declaration

fn greet(name) {
    return "Hello, " + name + "!"
}

let message = greet("Alice")
print(message)  // "Hello, Alice!"

Default Parameters

fn greet(name = "World") {
    return "Hello, " + name + "!"
}

print(greet())        // "Hello, World!"
print(greet("Bob"))   // "Hello, Bob!"

Recursive Functions

fn factorial(n) {
    if (n <= 1) {
        return 1
    }
    return n * factorial(n - 1)
}

print(factorial(5))  // 120

Function as Values

fn apply(callback, value) {
    return callback(value)
}

fn double(x) {
    return x * 2
}

let result = apply(double, 5)  // 10

Control Flow

If Statements

let age = 25

if (age >= 18) {
    print("Adult")
} else {
    print("Minor")
}

Nested If

let score = 85

if (score >= 90) {
    print("A")
} else if (score >= 80) {
    print("B")
} else if (score >= 70) {
    print("C")
} else {
    print("F")
}

While Loops

let count = 0

while (count < 5) {
    print(count)
    count = count + 1
}
// Prints: 0 1 2 3 4

For Loops

let numbers = [1, 2, 3, 4, 5]

for (num in numbers) {
    print(num)
}
// Prints: 1 2 3 4 5

Break and Continue

// Break - exit loop
let i = 0
while (true) {
    if (i >= 5) {
        break
    }
    print(i)
    i = i + 1
}

// Continue - skip iteration
for (x in [1, 2, 3, 4, 5]) {
    if (x % 2 == 0) {
        continue  // Skip even numbers
    }
    print(x)  // Prints: 1 3 5
}

Error Handling

Try/Catch

try {
    // Risky operation
    let result = 10 / 0
} catch (error) {
    print("Error occurred: " + error)
}

Try/Catch/Finally

let file = "data.txt"

try {
    // Open and read file
    let data = read_file(file)
    process(data)
} catch (error) {
    print("Failed to process file: " + error)
} finally {
    // Always executed
    print("Cleanup complete")
}

Throwing Errors

fn divide(a, b) {
    if (b == 0) {
        throw "Division by zero"
    }
    return a / b
}

try {
    let result = divide(10, 0)
} catch (error) {
    print("Error: " + error)  // "Error: Division by zero"
}

Standard Library

NAAb provides 13 built-in modules:

Core Modules

io - File I/O operations:

import "stdlib" as std

// Read file
let content = std.read_file("data.txt")

// Write file
std.write_file("output.txt", "Hello")

// Check exists
let exists = std.exists("data.txt")

json - JSON parsing and serialization:

import "stdlib" as std

// Parse JSON
let obj = std.parse('{"name": "Alice", "age": 30}')

// Stringify
let json = std.stringify(obj)

http - HTTP requests:

import "stdlib" as std

// GET request
let response = std.get("https://api.example.com/data")

// POST request
let result = std.post("https://api.example.com/create", {
    "name": "Bob",
    "email": "bob@example.com"
})

Data Modules

string - String manipulation (see Strings section)

array - Array operations (see Arrays section)

math - Mathematical functions:

import "stdlib" as std

let abs_val = std.abs(-5)         // 5
let floor_val = std.floor(3.7)    // 3.0
let ceil_val = std.ceil(3.2)      // 4.0
let round_val = std.round(3.6)    // 4.0
let max_val = std.max(5, 10)      // 10
let min_val = std.min(5, 10)      // 5
let pow_val = std.pow(2, 3)       // 8.0
let sqrt_val = std.sqrt(16)       // 4.0

collections - Advanced data structures

System Modules

time - Time operations:

import "stdlib" as std

let now = std.now()
let timestamp = std.timestamp()

env - Environment variables:

import "stdlib" as std

let home = std.getenv("HOME")
std.setenv("MY_VAR", "value")

csv - CSV file handling

regex - Regular expressions

crypto - Cryptographic functions

file - Advanced file operations


Multi-File Applications

Exporting Functions

Create math_utils.naab:

export fn add(a, b) {
    return a + b
}

export fn multiply(a, b) {
    return a * b
}

Importing Functions

Create main.naab:

import {add, multiply} from "./math_utils.naab"

let sum = add(5, 3)        // 8
let product = multiply(5, 3)  // 15

print("Sum: " + sum)
print("Product: " + product)

Wildcard Imports

import * as math from "./math_utils.naab"

let sum = math.add(5, 3)
let product = math.multiply(5, 3)

Aliasing

import {add as plus, multiply as times} from "./math_utils.naab"

let result = plus(5, times(2, 3))  // 11

Block Assembly

Searching for Blocks

naab blocks search "validate email"

Output:

Search results for "validate email":

1. BLOCK-PY-09145 (python)
   Validate email address format
   Input: string → Output: bool
   Score: 0.95

2. BLOCK-JS-03421 (javascript)
   Email validation with regex
   Input: string → Output: bool
   Score: 0.87

Listing Available Blocks

naab blocks list

Output:

Total blocks: 24,483

By language:
  Python:     8,234 blocks
  C++:        7,621 blocks
  JavaScript: 5,142 blocks
  Go:         2,341 blocks
  Rust:         845 blocks
  Java:         300 blocks

Using Blocks in Code

use BLOCK-PY-09145 as validate_email

let email = "alice@example.com"
let valid = validate_email(email)

if (valid) {
    print("Valid email")
} else {
    print("Invalid email")
}

Validating Block Composition

naab validate "BLOCK-PY-09145,BLOCK-JS-03421"

Output shows type compatibility and suggestions for adapters if types don't match.


Advanced Features

Pipeline Syntax

Chain operations with |>:

let result = data
    |> normalize
    |> validate
    |> process
    |> format

// Equivalent to:
let temp1 = normalize(data)
let temp2 = validate(temp1)
let temp3 = process(temp2)
let result = format(temp3)

Example with arrays:

let numbers = [1, 2, 3, 4, 5]

let result = numbers
    |> filter_evens
    |> double_values
    |> sum_all

print(result)

Type Annotations

fn add(x: int, y: int): int {
    return x + y
}

let numbers: array<int> = [1, 2, 3]
let config: dict<string, any> = {"debug": true}

Supported types:

  • int, float, string, bool, void, any
  • array<T> - homogeneous arrays
  • dict<K,V> - key-value maps
  • function<T1, T2, ..., R> - function types

Best Practices

1. Use Type Annotations for Public APIs

// Good
export fn calculate_discount(price: float, percent: float): float {
    return price * (1 - percent / 100)
}

// Less clear
export fn calculate_discount(price, percent) {
    return price * (1 - percent / 100)
}

2. Handle Errors Gracefully

// Good
try {
    let data = std.read_file("config.json")
    let config = std.parse(data)
    process(config)
} catch (error) {
    print("Failed to load config: " + error)
    use_defaults()
}

// Bad - unhandled errors crash program
let data = std.read_file("config.json")
let config = std.parse(data)

3. Use Descriptive Variable Names

// Good
let user_email = "alice@example.com"
let total_price = 99.99
let is_valid = true

// Bad
let e = "alice@example.com"
let t = 99.99
let v = true

4. Break Down Complex Functions

// Good
fn process_order(order) {
    let validated = validate_order(order)
    let calculated = calculate_totals(validated)
    let formatted = format_receipt(calculated)
    return formatted
}

// Bad - too much in one function
fn process_order(order) {
    // 50 lines of validation, calculation, formatting...
}

5. Use Constants for Magic Numbers

// Good
let TAX_RATE = 0.08
let total = price * (1 + TAX_RATE)

// Bad
let total = price * 1.08

6. Leverage the Standard Library

// Good - use stdlib
import "stdlib" as std
let upper = std.upper(text)

// Bad - reinvent the wheel
fn to_upper(text) {
    // Manual uppercase implementation...
}

7. Organize Code into Modules

// utils/string_helpers.naab
export fn capitalize(text) { ... }
export fn reverse(text) { ... }

// utils/math_helpers.naab
export fn average(numbers) { ... }
export fn median(numbers) { ... }

// main.naab
import * as strings from "./utils/string_helpers.naab"
import * as math from "./utils/math_helpers.naab"

Governance

NAAb includes a built-in governance engine that enforces project-level policies on polyglot code blocks. Place a govern.json file in your project directory to enable it.

Quick Example

{
  "version": "5.0",
  "mode": "enforce",
  "code_quality": {
    "no_secrets": { "level": "hard" },
    "no_oversimplification": { "level": "soft" },
    "no_hallucinated_apis": { "level": "advisory" }
  }
}

Key features:

  • 50+ built-in checks for security, code quality, and LLM anti-drift
  • Three enforcement levels: HARD (block), SOFT (overridable), ADVISORY (warn)
  • CI/CD integration via --governance-sarif and --governance-junit flags
  • Custom rules with regex patterns for project-specific policies

For the full governance reference, see Chapter 21: Governance and LLM Code Quality.


Next Steps


Getting Help

  • Documentation: docs/book/
  • Examples: examples/
  • Tests: tests/

Run naab --help for command-line options.