Examples

Practical code examples and tutorials for Behl.

Table of contents

  1. Basic Examples
    1. Hello World
    2. Variables and Types
    3. Simple Calculator
  2. Functions and Closures
    1. Fibonacci
    2. Factorial
    3. Counter with Closure
    4. Higher-Order Functions
  3. Working with Tables
    1. Array Operations
    2. Dictionary Operations
    3. Nested Tables
  4. Control Flow Examples
    1. FizzBuzz
    2. Prime Number Checker
    3. Binary Search
  5. Using the Standard Library
    1. Math Module
    2. String Module
    3. Table Module
  6. Error Handling
    1. Protected Call Example
    2. Input Validation
  7. Metatables
    1. Custom toString
    2. Custom Arithmetic
  8. Algorithms
    1. Bubble Sort
    2. Quick Sort
  9. Practical Examples
    1. Simple Calculator REPL (Concept)
    2. Data Processing
  10. C++ Integration Examples
    1. Userdata: Custom File API
    2. Userdata: Vector Math Library
  11. More Examples

Basic Examples

Hello World

print("Hello, World!");

Variables and Types

// Variables
let name = "Alice";
let age = 30;
let height = 5.7;
let isStudent = false;

// Constants
const PI = 3.14159;
const MAX_SIZE = 100;

// Type checking
print(typeof(name));    // "string"
print(typeof(age));     // "integer"
print(typeof(height));  // "number"

Simple Calculator

function add(a, b) {
    return a + b;
}

function subtract(a, b) {
    return a - b;
}

function multiply(a, b) {
    return a * b;
}

function divide(a, b) {
    if (b == 0) {
        error("Division by zero!");
    }
    return a / b;
}

print(add(5, 3));        // 8
print(subtract(10, 4));  // 6
print(multiply(7, 6));   // 42
print(divide(20, 4));    // 5

Functions and Closures

Fibonacci

function fibonacci(n) {
    if (n <= 1) {
        return n;
    }
    return fibonacci(n - 1) + fibonacci(n - 2);
}

for (let i = 0; i < 10; i++) {
    print("fib(" + tostring(i) + ") = " + tostring(fibonacci(i)));
}

Factorial

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

print(factorial(5));  // 120

Counter with Closure

function makeCounter(initial) {
    let count = initial;
    
    return function() {
        count = count + 1;
        return count;
    };
}

let counter1 = makeCounter(0);
let counter2 = makeCounter(10);

print(counter1());  // 1
print(counter1());  // 2
print(counter2());  // 11
print(counter1());  // 3
print(counter2());  // 12

Higher-Order Functions

function map(func, arr) {
    let result = {};
    for (let i = 0; i < rawlen(arr); i++) {
        result[i] = func(arr[i]);
    }
    return result;
}

function square(x) {
    return x * x;
}

let numbers = {1, 2, 3, 4, 5};
let squares = map(square, numbers);

for (let i = 0; i < rawlen(squares); i++) {
    print(squares[i]);  // 1, 4, 9, 16, 25
}

Working with Tables

Array Operations

// Create array
let arr = {10, 20, 30, 40, 50};

// Access elements
print(arr[0]);  // 10
print(arr[4]);  // 50

// Modify
arr[2] = 99;

// Length
let len = rawlen(arr);
print("Length: " + tostring(len));

// Iterate
for (let i = 0; i < rawlen(arr); i++) {
    print("arr[" + tostring(i) + "] = " + tostring(arr[i]));
}

Dictionary Operations

// Create dictionary
let person = {
    ["name"] = "Alice",
    ["age"] = 30,
    ["city"] = "Seattle"
};

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

// Modify
person["age"] = 31;
person["email"] = "alice@example.com";

// Iterate with pairs
for (key, value in pairs(person)) {
    print(key + ": " + tostring(value));
}

Nested Tables

let company = {
    ["name"] = "TechCorp",
    ["employees"] = {
        {["name"] = "Alice", ["role"] = "Engineer"},
        {["name"] = "Bob", ["role"] = "Designer"},
        {["name"] = "Carol", ["role"] = "Manager"}
    }
};

let employees = company["employees"];
for (let i = 0; i < rawlen(employees); i++) {
    let emp = employees[i];
    print(emp["name"] + " - " + emp["role"]);
}

Control Flow Examples

FizzBuzz

for (let i = 1; i <= 30; i++) {
    if (i % 15 == 0) {
        print("FizzBuzz");
    } elseif (i % 3 == 0) {
        print("Fizz");
    } elseif (i % 5 == 0) {
        print("Buzz");
    } else {
        print(i);
    }
}

Prime Number Checker

function isPrime(n) {
    if (n <= 1) {
        return false;
    }
    if (n == 2) {
        return true;
    }
    if (n % 2 == 0) {
        return false;
    }
    
    let i = 3;
    while (i * i <= n) {
        if (n % i == 0) {
            return false;
        }
        i = i + 2;
    }
    return true;
}

for (let n = 0; n < 20; n++) {
    if (isPrime(n)) {
        print(tostring(n) + " is prime");
    }
}
function binarySearch(arr, target) {
    let left = 0;
    let right = rawlen(arr) - 1;
    
    while (left <= right) {
        let mid = (left + right) / 2;
        let midVal = arr[mid];
        
        if (midVal == target) {
            return mid;
        } elseif (midVal < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    
    return -1;  // Not found
}

let sorted = {1, 3, 5, 7, 9, 11, 13, 15};
let index = binarySearch(sorted, 9);
print("Found at index: " + tostring(index));  // 4

Using the Standard Library

Math Module

const math = import("math");

// Constants
print("PI = " + tostring(math.PI));

// Basic operations
print(math.sqrt(16));      // 4
print(math.pow(2, 10));    // 1024
print(math.abs(-42));      // 42

// Trigonometry
let angle = math.PI / 4;
print(math.sin(angle));    // 0.707...
print(math.cos(angle));    // 0.707...

// Rounding
print(math.floor(3.7));    // 3
print(math.ceil(3.2));     // 4
print(math.round(3.5));    // 4

String Module

const string = import("string");

let text = "Hello, World!";

print(string.len(text));           // 13
print(string.upper(text));         // "HELLO, WORLD!"
print(string.lower(text));         // "hello, world!"
print(string.reverse("behl"));     // "lheb"

let sub = string.sub(text, 0, 4);
print(sub);  // "Hello"

Table Module

const table = import("table");

let arr = {10, 20, 30};

table.insert(arr, 40);        // Append
table.insert(arr, 0, 5);      // Insert at beginning

table.print(arr);              // Debug print

let removed = table.remove(arr, 1);
print("Removed: " + tostring(removed));

Error Handling

Protected Call Example

const math = import("math");

function riskyOperation(x) {
    if (x < 0) {
        error("Negative value not allowed!");
    }
    return math.sqrt(x);
}

function safeCall(value) {
    let success, result = pcall(riskyOperation, value);
    
    if (success) {
        print("Result: " + tostring(result));
    } else {
        print("Error: " + result);
    }
}

safeCall(16);   // Result: 4
safeCall(-5);   // Error: Negative value not allowed!

Input Validation

function validateAge(age) {
    if (typeof(age) != "integer" && typeof(age) != "number") {
        error("Age must be a number");
    }
    if (age < 0 || age > 150) {
        error("Age must be between 0 and 150");
    }
    return true;
}

function processAge(age) {
    let success, err = pcall(validateAge, age);
    
    if (!success) {
        print("Validation failed: " + err);
        return false;
    }
    
    print("Age " + tostring(age) + " is valid");
    return true;
}

processAge(25);      // Valid
processAge(-5);      // Validation failed
processAge("abc");   // Validation failed

Metatables

Custom toString

function createPerson(name, age) {
    let person = {
        ["name"] = name,
        ["age"] = age
    };
    
    let mt = {
        ["__tostring"] = function(p) {
            return p["name"] + " (" + tostring(p["age"]) + ")";
        }
    };
    
    setmetatable(person, mt);
    return person;
}

let alice = createPerson("Alice", 30);
print(tostring(alice));  // "Alice (30)"

Custom Arithmetic

function createVector(x, y) {
    let vec = {["x"] = x, ["y"] = y};
    
    let mt = {
        ["__add"] = function(a, b) {
            return createVector(a["x"] + b["x"], a["y"] + b["y"]);
        },
        ["__tostring"] = function(v) {
            return "(" + tostring(v["x"]) + ", " + tostring(v["y"]) + ")";
        }
    };
    
    setmetatable(vec, mt);
    return vec;
}

let v1 = createVector(1, 2);
let v2 = createVector(3, 4);
let v3 = v1 + v2;  // Uses __add metamethod

print(tostring(v3));  // "(4, 6)"

Algorithms

Bubble Sort

function bubbleSort(arr) {
    let n = rawlen(arr);
    
    for (let i = 0; i < n - 1; i++) {
        for (let j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                // Swap
                let temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

let data = {64, 34, 25, 12, 22, 11, 90};
bubbleSort(data);

for (let i = 0; i < rawlen(data); i++) {
    print(data[i]);
}

Quick Sort

function partition(arr, low, high) {
    let pivot = arr[high];
    let i = low - 1;
    
    for (let j = low; j < high; j++) {
        if (arr[j] < pivot) {
            i = i + 1;
            let temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    
    let temp = arr[i + 1];
    arr[i + 1] = arr[high];
    arr[high] = temp;
    
    return i + 1;
}

function quickSort(arr, low, high) {
    if (low < high) {
        let pi = partition(arr, low, high);
        quickSort(arr, low, pi - 1);
        quickSort(arr, pi + 1, high);
    }
}

let data = {10, 7, 8, 9, 1, 5};
quickSort(data, 0, rawlen(data) - 1);

for (let i = 0; i < rawlen(data); i++) {
    print(data[i]);
}

Practical Examples

Simple Calculator REPL (Concept)

function evaluate(expr) {
    // Simple expression evaluator
    let success, result = pcall(function() {
        return eval_code(expr);
    });
    
    if (success) {
        return result;
    } else {
        return "Error: " + result;
    }
}

// Example usage
print(evaluate("2 + 3 * 4"));     // 14
print(evaluate("sqrt(16)"));      // 4
print(evaluate("sin(PI / 2)"));   // 1

Data Processing

// Process a list of users
let users = {
    {["name"] = "Alice", ["age"] = 30, ["active"] = true},
    {["name"] = "Bob", ["age"] = 25, ["active"] = false},
    {["name"] = "Carol", ["age"] = 35, ["active"] = true}
};

// Filter active users
function filterActive(users) {
    let active = {};
    let count = 0;
    
    for (let i = 0; i < rawlen(users); i++) {
        if (users[i]["active"]) {
            active[count] = users[i];
            count = count + 1;
        }
    }
    
    return active;
}

// Calculate average age
function averageAge(users) {
    let sum = 0;
    let count = rawlen(users);
    
    for (let i = 0; i < count; i++) {
        sum = sum + users[i]["age"];
    }
    
    return sum / count;
}

let activeUsers = filterActive(users);
print("Active users: " + tostring(rawlen(activeUsers)));
print("Average age: " + tostring(averageAge(activeUsers)));

C++ Integration Examples

Userdata: Custom File API

This example shows how to create userdata from C++ and use it in Behl scripts.

C++ Side:

#include <behl/behl.hpp>
#include <cstdio>

// Define userdata type
struct FileHandle {
    FILE* file;
    bool is_open;
};

constexpr uint32_t FileHandle_UID = behl::make_uid("FileHandle");

// Open a file
static int file_open(behl::State* S) {
    auto filename = behl::check_string(S, 0);
    auto mode = behl::check_string(S, 1);
    
    void* ptr = behl::userdata_new(S, sizeof(FileHandle), FileHandle_UID);
    FileHandle* handle = static_cast<FileHandle*>(ptr);
    
    handle->file = fopen(std::string(filename).c_str(), std::string(mode).c_str());
    handle->is_open = (handle->file != nullptr);
    
    if (!handle->is_open) {
        behl::error(S, "Failed to open file");
    }
    
    // Add finalizer for automatic cleanup
    behl::table_new(S);
    behl::push_cfunction(S, file_finalizer);
    behl::table_rawset_field(S, -2, "__gc");
    behl::set_metatable(S, -2);
    
    return 1;
}

// Read a line from file
static int file_read_line(behl::State* S) {
    FileHandle* handle = static_cast<FileHandle*>(
        behl::check_userdata(S, 0, FileHandle_UID)
    );
    
    if (!handle->is_open) {
        behl::push_nil(S);
        return 1;
    }
    
    char buffer[1024];
    if (fgets(buffer, sizeof(buffer), handle->file)) {
        // Remove trailing newline
        size_t len = strlen(buffer);
        if (len > 0 && buffer[len - 1] == '\n') {
            buffer[len - 1] = '\0';
        }
        behl::push_string(S, buffer);
        return 1;
    }
    
    behl::push_nil(S);  // EOF
    return 1;
}

// Close file
static int file_close(behl::State* S) {
    FileHandle* handle = static_cast<FileHandle*>(
        behl::check_userdata(S, 0, FileHandle_UID)
    );
    
    if (handle->is_open) {
        fclose(handle->file);
        handle->is_open = false;
    }
    return 0;
}

// Finalizer (called by GC)
static int file_finalizer(behl::State* S) {
    void* ptr = behl::to_userdata(S, 0);
    if (ptr) {
        FileHandle* handle = static_cast<FileHandle*>(ptr);
        if (handle->is_open) {
            fclose(handle->file);
            handle->is_open = false;
        }
    }
    return 0;
}

// Register the API
void setup_file_api(behl::State* S) {
    behl::register_function(S, "file_open", file_open);
    behl::register_function(S, "file_read_line", file_read_line);
    behl::register_function(S, "file_close", file_close);
}

Behl Script:

// Open and read a file
let f = file_open("data.txt", "r");

while (true) {
    let line = file_read_line(f);
    if (line == nil) {
        break;
    }
    print(line);
}

file_close(f);  // Or let GC do it automatically

// Count lines in a file
function count_lines(filename) {
    let f = file_open(filename, "r");
    let count = 0;
    
    while (file_read_line(f) != nil) {
        count = count + 1;
    }
    
    file_close(f);
    return count;
}

print("Lines: " + tostring(count_lines("data.txt")));

Userdata: Vector Math Library

C++ Side:

#include <behl/behl.hpp>
#include <cmath>

struct Vector2D {
    double x, y;
};

constexpr uint32_t Vector2D_UID = behl::make_uid("Vector2D");

// Create vector
static int vec2_new(behl::State* S) {
    double x = behl::check_number(S, 0);
    double y = behl::check_number(S, 1);
    
    void* ptr = behl::userdata_new(S, sizeof(Vector2D), Vector2D_UID);
    Vector2D* v = static_cast<Vector2D*>(ptr);
    v->x = x;
    v->y = y;
    
    // Attach metatable
    behl::table_rawget_field(S, behl::REGISTRY_INDEX, "Vector2D_mt");
    behl::set_metatable(S, -2);
    
    return 1;
}

// Getters
static int vec2_get_x(behl::State* S) {
    Vector2D* v = static_cast<Vector2D*>(behl::check_userdata(S, 0, Vector2D_UID));
    behl::push_number(S, v->x);
    return 1;
}

static int vec2_get_y(behl::State* S) {
    Vector2D* v = static_cast<Vector2D*>(behl::check_userdata(S, 0, Vector2D_UID));
    behl::push_number(S, v->y);
    return 1;
}

// Addition metamethod
static int vec2_add(behl::State* S) {
    Vector2D* a = static_cast<Vector2D*>(behl::check_userdata(S, 0, Vector2D_UID));
    Vector2D* b = static_cast<Vector2D*>(behl::check_userdata(S, 1, Vector2D_UID));
    
    void* ptr = behl::userdata_new(S, sizeof(Vector2D), Vector2D_UID);
    Vector2D* result = static_cast<Vector2D*>(ptr);
    result->x = a->x + b->x;
    result->y = a->y + b->y;
    
    behl::get_metatable(S, 0);
    behl::set_metatable(S, -2);
    
    return 1;
}

// Magnitude
static int vec2_length(behl::State* S) {
    Vector2D* v = static_cast<Vector2D*>(behl::check_userdata(S, 0, Vector2D_UID));
    double len = std::sqrt(v->x * v->x + v->y * v->y);
    behl::push_number(S, len);
    return 1;
}

// __tostring
static int vec2_tostring(behl::State* S) {
    Vector2D* v = static_cast<Vector2D*>(behl::check_userdata(S, 0, Vector2D_UID));
    std::string str = behl::format("Vector2D({}, {})", v->x, v->y);
    behl::push_string(S, str);
    return 1;
}

void create_vector2d_metatable(behl::State* S) {
    behl::table_new(S);
    
    behl::push_cfunction(S, vec2_add);
    behl::table_rawset_field(S, -2, "__add");
    
    behl::push_cfunction(S, vec2_tostring);
    behl::table_rawset_field(S, -2, "__tostring");
    
    // Store in registry
    behl::table_rawset_field(S, behl::REGISTRY_INDEX, "Vector2D_mt");
}

void setup_vector_api(behl::State* S) {
    create_vector2d_metatable(S);
    behl::register_function(S, "vec2_new", vec2_new);
    behl::register_function(S, "vec2_get_x", vec2_get_x);
    behl::register_function(S, "vec2_get_y", vec2_get_y);
    behl::register_function(S, "vec2_length", vec2_length);
}

Behl Script:

// Create vectors
let v1 = vec2_new(3.0, 4.0);
let v2 = vec2_new(1.0, 2.0);

// Use operator overloading
let v3 = v1 + v2;
print(v3);  // "Vector2D(4.0, 6.0)"

// Calculate magnitude
let len = vec2_length(v1);
print("Length: " + tostring(len));  // 5.0

// Access components
let x = vec2_get_x(v1);
let y = vec2_get_y(v1);
print("x=" + tostring(x) + ", y=" + tostring(y));

// Physics simulation with vectors
function update_position(pos, velocity, dt) {
    let scaled_vel = vec2_new(
        vec2_get_x(velocity) * dt,
        vec2_get_y(velocity) * dt
    );
    return pos + scaled_vel;
}

let position = vec2_new(0.0, 0.0);
let velocity = vec2_new(10.0, 5.0);
let dt = 0.016;  // 60 FPS

for (let i = 0; i < 10; i++) {
    position = update_position(position, velocity, dt);
    print("Frame " + tostring(i) + ": " + tostring(position));
}

More Examples

Check the repository for additional examples:

  • *.behl files in the root directory
  • Unit tests in tests/ for advanced usage patterns

Copyright © 2025 behl Project. Distributed under MIT License.

This site uses Just the Docs, a documentation theme for Jekyll.