For AI & LLM Code Generation
Copy this reference and paste it in your AI prompts. All code examples are validated against the v0.4.5 interpreter.
LLM Reference
This reference is the authoritative source for generating accurate Logos code. All examples are validated against the v0.4.5 interpreter.
Quick Facts
- File extension:
.lgs - CLI:
lgs file.lgs|lgs build file.lgs|lgs fmt file.lgs - Interpreter: Pratt parser + tree-walking evaluator in Go
- GitHub: github.com/codetesla51/logos
Variables
// Basic variables
let x = 10
let name = "Alice"
let pi = 3.14
let active = true
let nothing = null
// Reassign freely
x += 5 // 15
x -= 2 // 13
// const - immutable binding (v0.4.2)
const PI = 3.14159
const API_KEY = "abc123"
PI = 3.14 // Error! Cannot reassign const
// Postfix operators (v0.4)
let i = 0
i++ // 1
i-- // 0Strings
let s = "hello world"
// String interpolation (v0.4+)
let name = "Alice"
let greeting = "Hello, ${name}!" // "Hello, Alice!"
// No quoted strings inside ${}
let dollar = "$"
let price = "${dollar}10" // CORRECT
// Functions
upper("hello") // "HELLO"
lower("HELLO") // "hello"
trim(" hi ") // "hi"
split("a,b,c", ",") // ["a", "b", "c"]
join(["a", "b"], "-") // "a-b"Arrays
let nums = [1, 2, 3, 4, 5]
let mixed = [1, "hello", true]
nums[0] // 1 (zero-indexed)
len(nums) // 5
contains(nums, 3) // true
// Mutations (modify in place)
push(nums, 6) // append: [1,2,3,4,5,6]
prepend(nums, 0) // prepend: [0,1,2,3,4,5,6]
pop(nums) // remove last, return it
first(nums) // first element
last(nums) // last element
tail(nums) // all except first
// Returns new array
reverse([1, 2, 3]) // [3, 2, 1]
sort([3, 1, 2]) // [1, 2, 3] (strings OR numbers)Tables (Objects/Maps)
let user = table{
name: "Alice",
age: 30,
active: true,
}
// Dot access (string keys)
user.name // "Alice"
user.name = "Bob" // mutate
// Bracket access (dynamic keys)
let key = "age"
user[key] // 30
// Nested tables
let company = table{
name: "Acme",
address: table{ city: "Seattle" },
}
company.address.city // "Seattle"
// Table utilities
keys(user) // ["name", "age", "active"]
values(user) // ["Bob", 30, true]
has(user, "email") // false
tableDelete(user, "age") // remove key
merge(t1, t2) // merge two tables
// ⚠️ Bracket access is type-aware
let t = table{ "1": "one", 1: "one-again" }
t["1"] // "one" (string key)
t[1] // "one-again" (number key)Control Flow
For Loops
// While-style
let i = 0
for i < 5 {
print(i)
i += 1
}
// For-in arrays
for item in items {
print(item)
}
// For-in with index
for i, v in items {
print("${i}: ${v}")
}
// range() (v0.4.2) — end is EXCLUSIVE
for i in range(0, 5) {
print(i) // 0, 1, 2, 3, 4 (NOT 5!)
}
// With step
for i in range(0, 10, 2) {
print(i) // 0, 2, 4, 6, 8
}
// Countdown (step = -1)
for i in range(5, 0, -1) {
print(i) // 5, 4, 3, 2, 1
}
// For-in over table keys
for key in keys(user) {
print(key + ": " + str(user[key]))
}Switch
switch role {
case "admin" { print("full access") }
case "editor" { print("can edit") }
default { print("read only") }
}
// No fallthroughFunctions
// Named function
fn greet(name) {
return "Hello, " + name
}
// Arrow function (implicit return)
let double = fn(x) -> x * 2
// First-class values
let apply = fn(f, x) -> f(x)
apply(double, 5) // 10
// Closures - capture surrounding scope
let makeAdder = fn(x) {
return fn(y) -> x + y
}
let add5 = makeAdder(5)
add5(3) // 8
add5(10) // 15Error Handling
// Result pattern - manual checking
let res = httpGet("https://api.example.com")
if res.ok {
print(res.value.body)
} else {
print("Error: " + res.error)
}
// Try expression (v0.4+) - unwraps and propagates
fn readConfig(path) {
let content = try fileRead(path)
let config = try parseJson(content)
return config
}
// Without try - verbose
fn readConfigVerbose(path) {
let res = fileRead(path)
if !res.ok { return res.error }
let json = parseJson(res.value)
if !json.ok { return json.error }
return json.value
}Try + Pipe (v0.4+)
Errors propagate automatically through the chain:
let data = try httpGet("https://api.example.com")
|> try parseJson
|> try filter(fn(u) -> u.active)
// If httpGet fails, the whole chain returns the errorConcurrency
// Spawn single task
spawn {
print("runs in background")
}
// Spawn loop - each iteration concurrent
let urls = ["https://api.example.com/1", "https://api.example.com/2"]
spawn for url in urls {
let data = try httpGet(url)
cache(url, data)
}
// Program waits for ALL spawns to complete before exitCLI Arguments
args() returns user arguments starting at index 0. The binary path and script path are already removed.
// Running: lgs script.lgs --name "Alice" --verbose
let cliArgs = args()
print(cliArgs[0]) // "--name" (NOT the binary path!)
print(cliArgs[1]) // "Alice"
len(cliArgs) // 2 (binary & script already removed)
// Common pattern: flag checking
if contains(cliArgs, "--verbose") {
print("Verbose mode")
}
if contains(cliArgs, "--name") {
let idx = indexOf(cliArgs, "--name")
let name = cliArgs[idx + 1]
print("Name: " + name)
}Built-in Functions
I/O
print(x) outputs with trailing newline. printn(x) outputs without.
input() · prompt(msg) · confirm(msg) · select(msg, opts[]) · clear()
print("Hello!") // with newline
printn("No newline") // without newline
print("Next line")
let name = input() // read stdin
let age = prompt("Age: ") // show prompt, read input
if confirm("Delete?") {
print("Deleted!")
}
let color = select("Pick:", ["red", "green", "blue"])Type
type(val) · len(str|arr) · keys(table) · values(table) · has(table, key)
Type Conversion
str(val) · int(val) · float(val) are short aliases (v0.4.1).
The to* forms still work.
String
upper(s) · lower(s) · trim(s) · replace(s, old, new) · split(s, sep) · join(arr, sep) · contains(str|arr, val) · startsWith(s, prefix) · endsWith(s, suffix) · indexOf(s, sub) · repeat(s, n) · slice(str|arr, start, end) · format(tmpl, args...)
Array
push(arr, val) · prepend(arr, val) · pop(arr) · first(arr) · last(arr) · tail(arr) · reverse(arr) · sort(arr) · contains(arr, val) · range(start, end, step?)
Important: range() end is EXCLUSIVE. range(0, 10) gives 0-9, not 0-10.
JSON
parseJson(str) · toJson(val) · prettyJson(val)
// Parse JSON
let data = try parseJson('{"name": "Alice", "age": 30}')
print(data.name) // "Alice"
print(str(data.age)) // "30"
// Convert to JSON
let user = table{ name: "Bob", score: 95 }
let json = try toJson(user)
// Pretty format
let pretty = try prettyJson(data)HTTP
httpGet(url, headers?) · httpPost(url, body, headers?) · httpPut(url, body) · httpPatch(url, body) · httpDelete(url)
// GET request
let body = try httpGet("https://api.example.com/users")
// With headers
let headers = table{
"Authorization": "Bearer " + env("API_TOKEN"),
"Content-Type": "application/json"
}
let data = try httpGet("https://api.example.com/private", headers)
// POST with JSON
let payload = try toJson(table{ name: "Alice", email: "alice@example.com" })
let res = try httpPost("https://api.example.com/users", payload)
// Methods: httpGet, httpPost, httpPut, httpPatch, httpDeleteFile I/O CLI Only
fileRead(path) · fileWrite(path, data) · fileAppend(path, data) · fileDelete(path) · fileExists(path) · fileMkdir(path) · fileReadDir(path) · fileGlob(pattern) · fileCopy(src, dst) · fileMove(src, dst)
// ⚠️ File I/O only works in CLI, NOT playground
let content = try fileRead("config.json")
try fileWrite("output.txt", "Hello!")
try fileAppend("log.txt", "New entry\n")
if fileExists("data.json") {
let data = try fileRead("data.json")
}
try fileMkdir("backup/2024")
let files = try fileReadDir(".")
let scripts = try fileGlob("*.lgs")Math
mathAbs(n) · mathSqrt(n) · mathPow(base, exp) · mathFloor(n) · mathCeil(n) · mathRound(n) · mathMin(a, b) · mathMax(a, b) · mathRandom() · mathRandomInt(min, max) · mathPi()
Time
timeNow() · timeMs() · timeStr() · dateStr() · dateTimeStr() · timeFormat(ts, fmt) · sleep(ms)
System
osname() · pwd() · cd(path) · env(key) · setenv(key, val) · args() · exit(code) · run(cmd, args...) · shell(cmd)
Color Output
colorRed(s) · colorGreen(s) · colorYellow(s) · colorBlue(s) · colorBold(s)
print(colorRed("Error!"))
print(colorGreen("Success"))
print(colorBold(colorYellow("Warning")))Regex (v0.4.3)
reMatch(pattern, text) · reFind(pattern, text) · reFindAll(pattern, text) · reReplace(pattern, text, repl) · reSplit(pattern, text) · reGroups(pattern, text)
Uses Go regexp syntax. Use backticks for raw patterns.
// reMatch - true/false if matches
reMatch(`\d+`, "abc123") // true
// reFind - first match or null
reFind(`\d+`, "3 cats") // "3"
// reFindAll - array of matches
reFindAll(`\d+`, "1 and 2") // ["1", "2"]
// reReplace - replace all
reReplace(`\d+`, "3 cats", "X") // "X cats"
// reSplit - split by pattern
reSplit(`\s+`, "a b c") // ["a", "b", "c"]
// reGroups - capture groups
let parts = reGroups(`(\w+)@(\w+)`, "alice@example.com")
parts[0] // "alice"
parts[1] // "example"
// Use backticks for raw patterns (Go regexp)Standard Library
std/array
map(arr, fn) · filter(arr, fn) · reduce(arr, fn, init) · unique(arr) · sum(arr) · min(arr) · max(arr) · indexOf(arr, val)
use "std/array"
// Map - transform each element
map([1, 2, 3], fn(x) -> x * 2) // [2, 4, 6]
// Filter - keep matching elements
filter([1, 2, 3, 4], fn(x) -> x % 2 == 0) // [2, 4]
// Reduce - combine to single value
reduce([1, 2, 3], fn(acc, x) -> acc + x, 0) // 6
// Other utilities
unique([1, 2, 2, 3]) // [1, 2, 3]
sum([1, 2, 3]) // 6
min([3, 1, 2]) // 1
max([3, 1, 2]) // 3
indexOf(["a", "b", "c"], "b") // 1
// ⚠️ Playground: Use loops insteadstd/math
mathFib(n) · mathFactorial(n) · mathIsPrime(n) · mathGcd(a, b) · mathLcm(a, b) · mathMean(arr) · mathMedian(arr) · mathClamp(n, min, max) · mathLerp(a, b, t)
use "std/math"
mathFib(10) // 55 (10th Fibonacci)
mathFactorial(5) // 120 (5!)
mathIsPrime(17) // true
mathGcd(48, 18) // 6
mathLcm(4, 6) // 12
mathMean([1, 2, 3]) // 2.0
mathMedian([1, 2, 3]) // 2
mathClamp(15, 0, 10) // 10 (constrain to range)
mathLerp(0, 100, 0.5) // 50.0 (linear interpolation)std/string
strCapitalize(s) · strReverse(s) · strIsPalindrome(s) · strIsEmpty(s) · strCount(s, sub) · strPadStart(s, len, c) · strPadEnd(s, len, c)
use "std/string"
strCapitalize("hello world") // "Hello World"
strReverse("hello") // "olleh"
strIsPalindrome("racecar") // true
strIsEmpty("") // true
strCount("banana", "a") // 3
strPadStart("42", 6, "0") // "000042"
strPadEnd("hi", 6, ".") // "hi...."std/path
pathJoin(parts) · pathBase(p) · pathDir(p) · pathExt(p) · pathWithoutExt(p) · pathIsAbs(p) · pathExists(p)
use "std/path"
pathJoin(["home", "user", "docs"]) // "home/user/docs"
pathBase("/home/user/file.txt") // "file.txt"
pathDir("/home/user/file.txt") // "/home/user"
pathExt("/home/user/file.txt") // ".txt"
pathWithoutExt("/home/user/file.txt") // "/home/user/file"
pathIsAbs("/home/user") // true
pathExists("/etc/passwd") // truestd/time
datetimeNow() · datetimeFromTimestamp(ts) · datetimeFormat(dt, fmt) · datetimeAdd(dt, n, unit) · datetimeSubtract(dt, n, unit) · datetimeDiff(d1, d2, unit) · datetimeIsAfter(d1, d2) · datetimeIsBefore(d1, d2) · datetimeIsEqual(d1, d2) · datetimeToStr(dt)
use "std/time"
let now = datetimeNow()
print(now["date"]) // "2026-03-20"
print(now["str"]) // "2026-03-20 15:04:05"
// Add/subtract
datetimeAdd(now, 1, "days")
datetimeSubtract(now, 7, "days")
// Format (Go time layout)
datetimeFormat(now, "January 2, 2006") // "March 20, 2026"
datetimeFormat(now, "02/01/2006") // "03/20/2026"
// Comparison
datetimeIsAfter(tomorrow, now) // true
datetimeIsBefore(yesterday, now) // true
datetimeIsEqual(now, now) // truestd/type
isString(val) · isInt(val) · isFloat(val) · isNumber(val) · isBool(val) · isArray(val) · isTable(val) · isNull(val) · isCallable(val)
std/log
logDebug(msg) · logInfo(msg) · logWarn(msg) · logError(msg)
std/testing
assert(name, got, expected) · suite(name, fn) · summary()
Go Embedding
import "github.com/codetesla51/logos/logos"
vm := logos.New()
vm.Register("greet", func(args ...logos.Object) logos.Object {
name := args[0].(*logos.String).Value
return &logos.String{Value: "Hello, " + name}
})
vm.SetVar("count", 42)
err := vm.Run(`print(greet("World"))`)
result := vm.GetVar("count")Sandbox Mode
Restrict capabilities for untrusted code:
vm := logos.NewWithConfig(logos.SandboxConfig{
AllowFileIO: false, // Disable file operations
AllowNetwork: false, // Disable HTTP
AllowShell: false, // Disable shell/exec
AllowExit: false, // Disable exit()
})Gotchas & Common Mistakes
// WRONG
let bad = "${dollar}10" // syntax error - no strings inside ${}
// Can't put quoted strings directly inside interpolation
// CORRECT
let hi = "hi"
let greeting = "${hi}" // use variable, not quoted string
for i in range(10, 0, -1) {} // countdown (end is EXCLUSIVE)
let item = len(arr) > 0 ? arr[0] : null // check length first
// Type-aware bracket access
let t = table{ 1: "one", "1": "one-again" }
t[1] // number key: "one"
t["1"] // string key: "one-again"
// sort() works on strings AND numbers
sort(["c", "a", "b"]) // ["a", "b", "c"]
sort([3, 1, 2]) // [1, 2, 3]Known Limitations
- Dot access only works with string-keyed table fields
- Bracket access is type-aware:
t["1"]≠t[1] - No try/catch — use result pattern or try expression
- No classes/structs — use tables
- No variadic user functions — only builtins support
args... spawnwaits for all goroutines to complete before exit- std/array not available on playground server
args()does not work in compiled binaries — uselgs script.lgs
Quick Cheat Sheet
Variables
let x = 10
const PI = 3.14
x += 5Strings
"Hello ${name}"
split("a,b", ",")Arrays
[1, 2, 3]
push(arr, x)
sort(arr)Tables
let u = table{
name: "Alice"
}
u.nameFunctions
fn add(a, b) {
return a + b
}
fn(x) -> x * 2Loops
for i in range(0, 10) {
print(i)
}Errors
try httpGet(url)
|> try parseJsonHTTP
try httpGet(url)
try httpPost(url, body)Full reference: See llm.txt for the complete reference.
