Reference
Standard library
What ships with Lira today — the builtins always in scope, and the 21 importable std modules. Every signature here was read from the source, every example runs.
Lira draws a clear line between two kinds of functionality. Some functions
are VM builtins: implemented in the runtime and always in
scope, no import required. Everything else lives in std modules, written in Lira itself under stdlib/, and pulled in with
import std.X.
Builtins vs. stdlib
Builtins need no import. They cover I/O, the core array and
channel operations, file handles, JSON, and a handful of numeric and time
primitives:
-
I/O:
println,eprintln -
Arrays:
len,push,pop -
Channels & fibers:
chan,send,recv,close,spawn,select -
Files:
file_open,file_read,file_write,file_close -
JSON:
json_parse,json_stringify -
Numbers & time:
abs,sqrt,time_ms,sleep
// No import needed — these are VM builtins, always in scope.
fn main() {
// I/O
println("hello from a builtin")
// Collections: arrays are mutated in place by push/pop.
let xs = [1, 2, 3]
push(xs, 4)
println(len(xs)) // 4
println(pop(xs)) // 4
// Numbers
println(abs(-7)) // 7
println(sqrt(144.0)) // 12
// A timestamp, straight from the VM.
let t = time_ms()
println(t > 0) // true
}import std.core
fn main() {
// abs and clamp are methods on int.
println((-5).abs()) // 5
println((15).clamp(0, 10)) // 10
// min and max are free functions taking two ints.
println(min(3, 9)) // 3
println(max(3, 9)) // 9
}The 21 std modules
Every module below imports cleanly today. The pure ones are self-contained Lira you can read end to end; the I/O ones are thin, honest wrappers around runtime builtins (file handles, sockets, the system clock, env vars).
std.collections
pure
Array methods — sum, min, max, sort, unique, filter_even, contains, slice, concat — plus range / range_step generators.
std.core
pure
abs and clamp as methods on int; min and max as free functions.
std.math
pure
factorial, fibonacci, is_prime, sign on numbers; gcd, lcm, lerp, hypot and the math_pi / math_e constants.
std.strings
pure
Methods on the string type: to_upper, trim, split, replace, starts_with, pad_start, and more; join as a free function.
std.json
pure
Helpers (json_has, json_get, json_object) over the json_parse / json_stringify builtins.
std.sync
pure
IntMutex, StringMutex, WaitGroup, Semaphore — explicit lock/unlock and with, built honestly on channels.
std.regex
pure
is_email, is_url, extract_numbers, extract_words over the regex_* builtins.
std.random
pure
random_bool, random_range, dice_roll, coin_flip, shuffle_int_array over the random() builtin.
std.uuid
pure
uuid, time_ordered, is_nil, version — wrappers over uuid_v4 / uuid_v7 builtins.
std.url
pure
url_parse / url_build into a URL struct, plus query_parse / query_get / query_has.
std.path
pure
dirname, basename, extension, starts_with — Unix-style path string manipulation.
std.hash
pure
verify_md5 / verify_sha256, salted variants over the md5 / sha1 / sha256 / sha512 builtins.
std.time
pure
A Timestamp struct with timestamp_now, parsing, and formatting helpers.
std.env
I/O
get_or, get_bool, is_ci, user, shell over the env_get / env_args builtins.
std.fs
I/O
read_file, write_file, append_file, exists, size — high-level file ops.
std.os
I/O
walk, exists, home_dir, temp_dir.
std.io
I/O
print_str, print_line, print_fmt, assert, plus now_ms / measure_time timing helpers.
std.log
I/O
Leveled logging — debug, info, warn, error, fatal — as stateless functions.
std.http
I/O
get, get_ok, post_json plus status-class predicates (is_success, is_redirect, …).
std.net
I/O
TCP helpers — tcp_try_connect, tcp_write_line, tcp_read_exact, tcp_close_safe.
std.test
I/O
describe, test, assert, assert_eq, summary — a tiny stateless assertion toolkit.
Strings
std.strings extends the string type with methods,
so you write name.to_upper() rather than
to_upper(name). split returns
[string]; the inverse, join, is a free function.
import std.strings
fn main() {
let title = " the lyre is tuned "
// Methods hang off the string type itself.
println(title.trim().title_case()) // The Lyre Is Tuned
let name = "lira"
println(name.to_upper()) // LIRA
println(name.capitalize()) // Lira
println(name.repeat(3)) // liralira lira -> liraliralira
println(name.starts_with("li")) // true
println(name.index_of("r")) // 2
// split returns [string]; join is a free function.
let parts = "a,b,c".split(",")
println(len(parts)) // 3
println(join(parts, " / ")) // a / b / c
}Math
std.math hangs methods off int and
float for the single-argument operations, and exposes free
functions for the multi-argument ones. Note that many trig and rounding
functions (sin, cos, floor,
pow) are VM builtins — std.math adds the rest.
import std.math
fn main() {
// Methods on int.
println((5).factorial()) // 120
println((10).fibonacci()) // 55
println((17).is_prime()) // true
println((-4).sign()) // -1
// Methods on float.
println((180.0).to_radians()) // 3.14159...
// Free functions for multi-argument math.
println(gcd(48, 36)) // 12
println(lcm(4, 6)) // 12
println(lerp(0.0, 10.0, 0.5)) // 5
// Constants are functions.
println(math_pi()) // 3.141592653589793
}Collections
std.collections adds methods to typed arrays —
[int], [float], and [string].
Transformations like sort and filter_even return
fresh arrays; reductions like sum and max return
a scalar.
import std.collections
fn main() {
let xs = [5, 3, 8, 1, 3, 9]
// Reductions.
println(xs.sum()) // 29
println(xs.max()) // 9
println(xs.min()) // 1
// Transformations return new arrays.
println(xs.sort()) // [1, 3, 3, 5, 8, 9]
println(xs.unique().sort()) // [1, 3, 5, 8, 9]
println(xs.filter_even()) // [8]
// Search.
println(xs.contains(8)) // true
println(xs.index_of(8)) // 2
println(xs.count(3)) // 2
// Generators.
println(range(0, 5)) // [0, 1, 2, 3, 4]
}JSON
The heavy lifting — json_parse and
json_stringify — is built into the VM. std.json layers
on convenience helpers like json_has and
json_get. Parse a string, index into it, and round-trip it
back:
import std.json
fn main() {
// json_parse / json_stringify are VM builtins; std.json adds helpers.
let text = "{\"name\": \"lira\", \"stars\": 7}"
let obj = json_parse(text)
// Index into the parsed object.
println(obj["name"]) // lira
println(obj["stars"]) // 7
// json_has is a std.json helper.
println(json_has(obj, "name")) // true
println(json_has(obj, "missing")) // false
// Round-trip back to a string.
let out = json_stringify(obj)
println(len(out) > 0) // true
}Sync
std.sync gives you mutual exclusion and coordination built on
the same channels and fibers covered in the
concurrency guide. Because Lira has no RAII,
locking is explicit: lock() takes the value
out, unlock(v) puts one back. The with closure
form brackets that pair for you.
import std.sync
// Each worker increments the shared counter once, then signals done.
fn worker(m: IntMutex, wg: WaitGroup) {
let v = m.lock()
m.unlock(v + 1)
wg.done()
}
fn main() {
let counter = new_int_mutex(0)
let wg = new_wait_group()
let n = 5
var i = 0
while i < n {
spawn worker(counter, wg)
i = i + 1
}
// Block until all n workers have finished.
wg.wait(n)
// No RAII in Lira, so locking is explicit: lock to read, unlock to release.
let total = counter.lock()
counter.unlock(total)
println(total) // 5
}Where to go next
Ready to put these to work? The
guide walks through your first program, types covers generics and optionals, patterns covers
matching and exhaustiveness, and concurrency goes
deep on fibers, channels, and select.