Logos / Docs

Examples

Here are practical examples to help you get started with Logos. Each example demonstrates different features of the language.

Todo CLI App

A command-line todo list manager with persistent storage:

todo_app.lgs
// todo_app.lgs - Command-line todo manager

let todoFile = "todos.json"
let todos = []

let loadTodos = fn() {
    if !fileExists(todoFile) {
        return []
    }
    let res = fileRead(todoFile)
    if !res.ok {
        return []
    }
    let parsed = parseJson(res.value)
    if parsed == null {
        return []
    }
    return parsed
}

let saveTodos = fn() {
    let json = toJson(todos)
    let res = fileWrite(todoFile, json)
    return res.ok
}

let listTodos = fn() {
    if len(todos) == 0 {
        print(colorYellow("  No todos yet!"))
        return null
    }
    let i = 0
    for i < len(todos) {
        let todo = todos[i]
        let status = ""
        if todo["done"] {
            status = colorGreen("[x]")
        } else {
            status = colorYellow("[ ]")
        }
        print("  " + toStr(i + 1) + ". " + status + " " + todo["task"])
        i = i + 1
    }
}

let addTodo = fn(task) {
    let todo = table{
        "task": task,
        "done": false,
        "created": dateTimeStr(),
    }
    todos = push(todos, todo)
    saveTodos()
    print(colorGreen("Added: " + task))
}

let completeTodo = fn(index) {
    if index < 1 || index > len(todos) {
        print(colorRed("Invalid todo number"))
        return null
    }
    let todo = todos[index - 1]
    todo["done"] = true
    todos[index - 1] = todo
    saveTodos()
    print(colorGreen("Completed: " + todo["task"]))
}

// Main loop
print(colorBold(colorCyan("Todo App")))
todos = loadTodos()
print(colorGreen("Loaded " + toStr(len(todos)) + " todo(s)"))

let running = true
for running {
    let input = trim(prompt(colorBold("todo> ")))
    let parts = split(input, " ")
    let cmd = lower(parts[0])

    if cmd == "quit" || cmd == "q" {
        running = false
    }
    if cmd == "list" || cmd == "ls" {
        listTodos()
    }
    if cmd == "add" {
        if len(parts) < 2 {
            print(colorRed("Usage: add <task>"))
        } else {
            let task = join(slice(parts, 1, len(parts)), " ")
            addTodo(task)
        }
    }
    if cmd == "done" {
        if len(parts) < 2 {
            print(colorRed("Usage: done <number>"))
        } else {
            completeTodo(toInt(parts[1]))
        }
    }
}
print(colorYellow("Goodbye!"))

HTTP API Client

Fetch data from a REST API with proper error handling:

http_client.lgs
// http_client.lgs - Fetch and display API data

let fetchUsers = fn() {
    let res = httpGet("https://jsonplaceholder.typicode.com/users")
    
    if !res.ok {
        print(colorRed("Error: " + res.error))
        return []
    }

    // HTTP responses have body and status in value
    let users = parseJson(res.value.body)
    return users
}

let displayUser = fn(user) {
    print("---")
    print("Name: " + user["name"])
    print("Email: " + user["email"])
    print("Company: " + user["company"]["name"])
}

// Fetch and display users
print(colorCyan("Fetching users from API..."))
print("")

let users = fetchUsers()

if len(users) > 0 {
    for user in users {
        displayUser(user)
    }
    print("---")
    print(colorGreen("Total users: " + toStr(len(users))))
}

JSON Configuration Manager

Load and manage JSON configuration files:

json_config.lgs
// json_config.lgs - Configuration file manager

let loadConfig = fn(path) {
    let res = fileRead(path)
    if !res.ok {
        return null
    }
    let parsed = parseJson(res.value)
    if parsed == null {
        print(colorRed("Error: invalid JSON in " + path))
        return null
    }
    return parsed
}

let saveConfig = fn(path, config) {
    let json = toJson(config)
    let res = fileWrite(path, json)
    return res.ok
}

let getConfigValue = fn(config, key, defaultValue) {
    if config == null {
        return defaultValue
    }
    if !has(config, key) {
        return defaultValue
    }
    return config[key]
}

// Load or create default config
let configPath = "config.json"
let config = null

if fileExists(configPath) {
    config = loadConfig(configPath)
    print(colorGreen("Loaded config from: " + configPath))
} else {
    print(colorYellow("Creating default config..."))
    config = table{
        "app": table{
            "name": "MyApp",
            "version": "1.0.0",
            "debug": false,
        },
        "server": table{
            "host": "localhost",
            "port": 8080,
        },
    }
    saveConfig(configPath, config)
}

// Access config values with defaults
let appName = getConfigValue(config["app"], "name", "Unknown")
let port = getConfigValue(config["server"], "port", 3000)

print("Application: " + appName)
print("Port: " + toStr(port))

Search for files by name pattern with optional content search:

file_search.lgs
// file_search.lgs - Search files by pattern

let searchFiles = fn(dir, pattern, searchText) {
    let results = []
    let dirRes = fileReadDir(dir)
    if !dirRes.ok {
        return results
    }
    
    for entry in dirRes.value {
        let path = dir + "/" + entry
        
        // Check if filename matches pattern
        if contains(lower(entry), lower(pattern)) {
            if len(searchText) == 0 {
                // Just matching filename
                results = push(results, table{
                    "path": path,
                    "match": "filename",
                })
            } else {
                // Also search file contents
                let fileRes = fileRead(path)
                if fileRes.ok {
                    let lines = split(fileRes.value, "\n")
                    let lineNum = 1
                    for line in lines {
                        if contains(lower(line), lower(searchText)) {
                            results = push(results, table{
                                "path": path,
                                "line": lineNum,
                                "match": trim(line),
                            })
                        }
                        lineNum = lineNum + 1
                    }
                }
            }
        }
    }
    return results
}

// Search for .lgs files containing "fn"
let dir = "."
let pattern = ".lgs"
let searchText = "fn"

print(colorYellow("Searching for '" + pattern + "' files containing '" + searchText + "'..."))
print("")

let results = searchFiles(dir, pattern, searchText)

if len(results) == 0 {
    print(colorYellow("No matches found"))
} else {
    print(colorBold("Found " + toStr(len(results)) + " match(es):"))
    for result in results {
        if has(result, "line") {
            print(colorGreen("  " + result["path"]) + ":" + toStr(result["line"]))
            print("    " + result["match"])
        } else {
            print(colorGreen("  " + result["path"]))
        }
    }
}

Concurrent Processing

Process items concurrently using spawn:

concurrent.lgs
// concurrent.lgs - Parallel processing example
use "std/math"

let processItem = fn(item) {
    // Simulate some computation
    let result = mathFactorial(item)
    print("Processed " + toStr(item) + "! = " + toStr(result))
    return result
}

let items = [5, 6, 7, 8, 9, 10]

print("Processing items concurrently...")
print("")

// Process all items in parallel using spawn for
spawn for item in items {
    processItem(item)
}

print("")
print("All items queued for processing!")

// You can also spawn individual blocks
spawn {
    sleep(100)
    print("This runs in the background")
}

Testing Example

Write tests using the testing standard library:

test_math.lgs
// test_math.lgs - Example test file
use "std/testing"
use "std/math"

let add = fn(a, b) -> a + b
let multiply = fn(a, b) -> a * b

suite("arithmetic", fn() {
    assert("add positive", add(2, 3), 5)
    assert("add negative", add(-1, 1), 0)
    assert("add zero", add(0, 0), 0)
    assert("multiply", multiply(3, 4), 12)
    assert("multiply by zero", multiply(5, 0), 0)
})

suite("math stdlib", fn() {
    assert("factorial 5", mathFactorial(5), 120)
    assert("factorial 0", mathFactorial(0), 1)
    assert("fib 10", mathFib(10), 55)
    assert("isPrime 17", mathIsPrime(17), true)
    assert("isPrime 4", mathIsPrime(4), false)
    assert("gcd", mathGcd(48, 18), 6)
})

summary()

// Run with: lgs test_math.lgs
// Output:
// ok    arithmetic, math stdlib    11 tests passed

FizzBuzz

The classic FizzBuzz problem:

fizzbuzz.lgs
// fizzbuzz.lgs - Classic FizzBuzz

let fizzbuzz = fn(n) {
    let i = 1
    for i <= n {
        if i % 15 == 0 {
            print("FizzBuzz")
        } else if i % 3 == 0 {
            print("Fizz")
        } else if i % 5 == 0 {
            print("Buzz")
        } else {
            print(toStr(i))
        }
        i = i + 1
    }
}

fizzbuzz(30)

CLI Tool with Arguments

Build command-line tools that accept arguments:

greet.lgs
// greet.lgs - CLI tool example

let cliArgs = args()

// First arg is the script name, skip it
if len(cliArgs) < 2 {
    print("Usage: lgs greet.lgs <name> [--loud]")
    exit(1)
}

let name = cliArgs[1]
let loud = false

// Check for flags
let i = 2
for i < len(cliArgs) {
    if cliArgs[i] == "--loud" {
        loud = true
    }
    i = i + 1
}

let greeting = "Hello, " + name + "!"

if loud {
    print(colorBold(upper(greeting)))
} else {
    print(greeting)
}

// Usage:
// lgs greet.lgs World           -> Hello, World!
// lgs greet.lgs World --loud    -> HELLO, WORLD!

More Examples

Find more examples in the GitHub repository, including:

  • Backup script with file operations
  • Cron job scheduler
  • Movie file organizer
  • Line counter utility
  • Guessing game