Skip to content

axon-std Overview

The official standard library for the AXON programming language.

ModuleImport PathDescription
mathstd/math.axsInteger & float math: abs, min, max, clamp, gcd, lcm, fsqrt, fpow, etc.
stringstd/string.axsString ops: len, eq, dup, concat, char_at, is_empty, println
iostd/io.axsOutput helpers: println, println_bool, print2, print3
memstd/mem.axsMemory management: alloc_bytes, free_ptr, resize, copy, move, compare
osstd/os.axsProcess control: quit
collectionsstd/collections.axsDynamic array (Vec): vec_new, vec_push, vec_pop, vec_get, vec_set, etc.
sortstd/sort.axsSorting & search: sort_vec, binary_search, vec_min, vec_max, vec_sum
timestd/time.axsTime utilities: now_secs, now_ms, sleep_ms, sleep_secs, elapsed_secs
fmtstd/fmt.axsString formatting: fmt1, fmt2, fmt3, to_str, f64_to_str, bool_to_str
hashmapstd/hashmap.axsHash map: map_new, map_set, map_val, map_get_or, map_has, map_del
hotswapstd/hotswap.axsHot-swap runtime: load, gc, register_state, enter, exit
threadstd/thread.axsThread spawning and mutex primitives: spawn, join, mutex, lock, unlock
netstd/net.axsTCP/UDP socket wrapper: tcp_new, sock_bind, sock_listen, sock_accept, sock_connect, etc.
httpstd/http.axsHTTP response builder and request parser: build_response, parse_method, parse_path, status/header constants
evloopstd/evloop.axsEvent loop wrapper for epoll/kqueue: evloop_new, evloop_wait, evloop_add, evloop_del
channelstd/channel.axsMPSC channel primitives: chan_new, chan_send, chan_recv, chan_try_send, chan_len
optionstd/option.axsOption_i64 / Option_str sum type: some_i64, none_i64, is_some_i64, unwrap_i64, unwrap_or_i64, map_i64, zip_with_i64, plus string variants
resultstd/result.axsResult_ii / Result_is sum type: ok_ii, err_ii, is_ok_ii, unwrap_ii, unwrap_err_ii, map_ii, map_err_ii, plus i64/string variant
raylibstd/raylib.axsraylib FFI bindings: 38 functions for window, drawing, input, and timing
encodingstd/encoding.axsEncode/decode: hex_encode, base64_encode, url_encode, base32_encode + decode counterparts
uuidstd/uuid.axsRFC 4122 UUID v4: uuid_v4, uuid_to_string, uuid_from_string, uuid_version, uuid_variant, uuid_eq, uuid_is_nil

Point the compiler to this repository using -L or the AXON_LIB_PATH environment variable:

Terminal window
# Via CLI flag
axonc -L /path/to/axon-std my_program.axs
# Via environment variable
export AXON_LIB_PATH=/path/to/axon-std
axonc my_program.axs
(module
(import math "std/math.axs")
(import io "std/io.axs")
(extern print_i64 ((n i64)) void)
(fn main () i32
(block
;; Use qualified access: module.function
(call io.println (call math.pow (i64 2) (i64 10)))
(call io.println (call math.gcd (i64 12) (i64 18)))
(i32 0))))
FunctionSignatureDescription
abs(i64) → i64Absolute value
min(i64, i64) → i64Smaller of two values
max(i64, i64) → i64Larger of two values
clamp(i64, i64, i64) → i64Constrain to [lo, hi]
sign(i64) → i64Returns -1, 0, or 1
pow(i64, i64) → i64Integer exponentiation (fast squaring)
gcd(i64, i64) → i64Greatest common divisor
lcm(i64, i64) → i64Least common multiple
div_floor(i64, i64) → i64Floor division (toward −∞)
is_even(i64) → boolEven check
is_odd(i64) → boolOdd check
factorial(i64) → i64n! (iterative)
fsqrt(f64) → f64Square root
fsin / fcos / ftan(f64) → f64Trigonometric functions
fpow(f64, f64) → f64Floating-point power
ffloor / fceil / fround(f64) → f64Rounding
float_abs(f64) → f64Absolute value (float)
to_radians / to_degrees(f64) → f64Angle conversion
lerp(f64, f64, f64) → f64Linear interpolation
FunctionSignatureDescription
len((ptr i8)) → i64String length (bytes)
eq((ptr i8), (ptr i8)) → boolString equality
dup((ptr i8)) → (ptr i8)Heap-allocate copy (must free)
concat((ptr i8), (ptr i8)) → (ptr i8)Concatenate (must free)
char_at((ptr i8), i64) → i64Byte at index (panics OOB)
is_empty((ptr i8)) → boolZero-length check
println((ptr i8)) → voidPrint string with newline
FunctionSignatureDescription
println(i64) → voidPrint integer with newline
println_bool(bool) → voidPrint 1/0 for true/false
print2(i64, i64) → voidPrint two values
print3(i64, i64, i64) → voidPrint three values
FunctionSignatureDescription
quit(i32) → voidExit process with code
FunctionSignatureDescription
alloc_bytes(i64) → (ptr u8)Allocate n bytes (via malloc)
alloc_zeroed(i64, i64) → (ptr u8)Allocate zeroed memory (via calloc)
resize((ptr u8), i64) → (ptr u8)Resize allocation (via realloc)
free_ptr((ptr u8)) → voidFree allocation
zero((ptr u8), i64) → (ptr u8)Zero-fill n bytes
fill((ptr u8), i32, i64) → (ptr u8)Fill n bytes with value
copy((ptr u8), (ptr u8), i64) → (ptr u8)Copy n bytes (non-overlapping)
move((ptr u8), (ptr u8), i64) → (ptr u8)Copy n bytes (overlapping-safe)
compare((ptr u8), (ptr u8), i64) → i32Compare n bytes
FunctionSignatureDescription
vec_new() → (ptr i64)Create empty Vec (capacity 4)
vec_with_capacity(i64) → (ptr i64)Create Vec with initial capacity
vec_push((ptr i64), i64) → voidAppend element (auto-grows)
vec_pop((ptr i64)) → i64Remove and return last element
vec_get((ptr i64), i64) → i64Get element at index (bounds-checked)
vec_set((ptr i64), i64, i64) → voidSet element at index (bounds-checked)
vec_len((ptr i64)) → i64Current number of elements
vec_cap((ptr i64)) → i64Current capacity
vec_is_empty((ptr i64)) → boolCheck if empty
vec_first / vec_last((ptr i64)) → i64Access first/last element
vec_contains((ptr i64), i64) → boolCheck if value exists
vec_index_of((ptr i64), i64) → i64Find index (-1 if not found)
vec_swap((ptr i64), i64, i64) → voidSwap elements at two indices
vec_reverse((ptr i64)) → voidReverse in-place
vec_clear((ptr i64)) → voidSet length to 0
vec_free((ptr i64)) → voidFree Vec and backing storage

Note: Import std/collections.axs before std/sort.axs in your program.

FunctionSignatureDescription
sort_vec((ptr i64)) → voidQuicksort a Vec (ascending, in-place)
sort_vec_desc((ptr i64)) → voidSort descending (sort + reverse)
is_sorted((ptr i64)) → boolCheck ascending order
is_sorted_desc((ptr i64)) → boolCheck descending order
binary_search((ptr i64), i64) → i64Find index in sorted Vec (-1 if not found)
vec_min((ptr i64)) → i64Minimum value
vec_max((ptr i64)) → i64Maximum value
vec_sum((ptr i64)) → i64Sum of all elements
FunctionSignatureDescription
now_secs() → i64Current epoch time (seconds)
now_ms() → i64Current epoch time (milliseconds, second precision)
sleep_ms(i64) → voidSleep for milliseconds
sleep_secs(i64) → voidSleep for seconds
elapsed_secs(i64, i64) → i64Elapsed seconds between two timestamps
has_elapsed(i64, i64) → boolCheck if duration has passed since timestamp

Template-based formatting with {} placeholders. Since Axon doesn’t support varargs, use the appropriate arity function.

FunctionSignatureDescription
to_str(i64) → stringConvert integer to string
f64_to_str(f64) → stringConvert float to string
bool_to_str(i64) → stringConvert 0/1 to “true”/“false”
fmt1(string, i64) → stringFormat with 1 integer
fmt2(string, i64, i64) → stringFormat with 2 integers
fmt3(string, i64, i64, i64) → stringFormat with 3 integers
fmt_f1 / fmt_f2(string, f64, ...) → stringFormat with floats
fmt_b1(string, i64) → stringFormat with boolean
fmt_s1 / fmt_s2(string, string, ...) → stringFormat with strings
fmt_si(string, string, i64) → stringFormat: string then integer
fmt_is(string, i64, string) → stringFormat: integer then string

String-keyed hash map wrapping the compiler’s built-in (map K V) type with convenience functions.

FunctionSignatureDescription
map_new() → (map string i64)Create a new empty map
map_set(map, string, i64) → voidInsert or update a key-value pair
map_get(map, string) → (ptr i64)Get pointer to value (panics if missing)
map_val(map, string) → i64Get dereferenced value (panics if missing)
map_get_or(map, string, i64) → i64Get value or return default
map_has(map, string) → boolCheck if key exists
map_del(map, string) → boolRemove a key
map_len(map) → i64Number of entries
map_is_empty(map) → boolCheck if map has no entries
map_free(map) → voidFree the map

Thread-safe dynamic module loading and hot-swap support. Wraps the runtime’s dlopen/dlsym-based symbol redirection table.

FunctionSignatureDescription
load(string) → i32Load a shared object (.so/.dll) and swap hotswap-tagged function pointers. Returns 0 on success, -1 on failure.
gc() → voidGarbage-collect old module handles once all epoch references are released.
register_state((ptr (ptr void)), string) → voidRegister a state pointer + migration hook name for @migrate-tagged structs.
enter((ptr (ptr void)), (ptr (ptr void))) → (ptr void)Enter an epoch-safe region for a hotswap module.
exit((ptr void)) → voidExit an epoch-safe region, decrementing the reference count.

Note: std/thread must be imported after std/collections for the Vec types used internally by the thread module’s internal structures.

Thread spawning and mutex primitives wrapping POSIX threads via runtime FFI.

FunctionSignatureDescription
spawn((fn (ptr void)), (arg (ptr void))) → i64Spawn a new thread. Returns a handle for join.
join(handle: i64) → voidBlock until the thread identified by handle terminates.
mutex() → i64Allocate and initialize a new mutex.
lock(mtx: i64) → voidLock the mutex (blocks until available).
unlock(mtx: i64) → voidUnlock the mutex.
mutex_free(mtx: i64) → voidDestroy and free the mutex.

See docs/api/thread.md for the full API reference.

TCP and UDP socket wrappers providing a portable network API. All socket operations return an i64 file descriptor; check for < 0 to detect errors.

FunctionSignatureDescription
tcp_new() → i64Create a new TCP socket. Returns fd or -1 on error.
udp_new() → i64Create a new UDP socket. Returns fd or -1 on error.
set_nonblock(fd: i64) → i64Set socket to non-blocking mode. Returns 0 on success.
set_reuseaddr(fd: i64) → i64Enable SO_REUSEADDR on the socket. Returns 0 on success.
sock_bind(fd: i64, port: i64) → i64Bind socket to the given port. Returns 0 on success.
sock_listen(fd: i64, backlog: i64) → i64Start listening with the given backlog. Returns 0 on success.
sock_accept(fd: i64) → i64Accept an incoming connection. Returns new client fd or -1.
sock_connect(fd: i64, addr: string, port: i64) → i64Connect to addr:port. Returns 0 on success.
sock_read(fd: i64, buf: (ptr void), len: i64) → i64Read up to len bytes into buf. Returns bytes read or -1.
sock_write(fd: i64, buf: (ptr void), len: i64) → i64Write len bytes from buf. Returns bytes written or -1.
sock_write_str(fd: i64, s: string) → i64Write a string to the socket. Returns bytes written or -1.
sock_close(fd: i64) → voidClose the socket.

See docs/api/net.md for the full API reference.

HTTP status constants, header constants, response builder, and basic request parser. The build_response function composes a full HTTP/1.1 response from status, content-type, and body. The parse_method and parse_path helpers extract those fields from a raw HTTP request line.

FunctionSignatureDescription
status_200() → string"HTTP/1.1 200 OK\r\n"
status_404() → string"HTTP/1.1 404 Not Found\r\n"
status_400() → string"HTTP/1.1 400 Bad Request\r\n"
status_500() → string"HTTP/1.1 500 Internal Server Error\r\n"
header_html() → string"Content-Type: text/html\r\n"
header_text() → string"Content-Type: text/plain\r\n"
header_json() → string"Content-Type: application/json\r\n"
header_close() → string"Connection: close\r\n"
header_content_length(len: i64) → string"Content-Length: <n>\r\n"
crlf() → string"\r\n"
build_response(status: string, content_type: string, body: string) → stringCompose a full HTTP response string.
parse_method(raw: string) → stringExtract HTTP method from a raw request line (e.g. "GET").
parse_path(raw: string) → stringExtract request path from a raw request line (e.g. "/index.html").

See docs/api/http.md for the full API reference.

Event loop wrapper for epoll (Linux) and kqueue (macOS). Manages a set of file descriptors and reports readable/writable/error events.

FunctionSignatureDescription
ev_read() → i64Event mask flag for read readiness (value 1).
ev_write() → i64Event mask flag for write readiness (value 2).
ev_error() → i64Event mask flag for error condition (value 4).
evloop_new() → i64Create a new event loop. Returns handle or -1 on error.
evloop_close(loop: i64) → voidDestroy the event loop.
evloop_add(loop: i64, fd: i64, events: i64) → i64Register fd with the event loop. Returns 0 on success.
evloop_del(loop: i64, fd: i64) → i64Remove fd from the event loop. Returns 0 on success.
evloop_wait(loop: i64, buf: (ptr i64), max_events: i64, timeout_ms: i64) → i64Wait for events. Returns number of events or -1.
evloop_alloc_buf(n: i64) → (ptr i64)Allocate an event buffer for use with evloop_wait. Each slot is 16 bytes.
evloop_free_buf(buf: (ptr i64)) → voidFree an event buffer allocated by evloop_alloc_buf.

See docs/api/evloop.md for the full API reference.

Multi-producer, single-consumer (MPSC) channel for passing i64 values between threads. Channels are created with a fixed capacity; sending blocks when full.

FunctionSignatureDescription
chan_new(capacity: i64) → i64Create a new channel with the given buffer capacity.
chan_send(ch: i64, value: i64) → voidSend a value (blocks if channel is full).
chan_recv(ch: i64) → i64Receive a value (blocks if channel is empty).
chan_try_send(ch: i64, value: i64) → i64Try to send without blocking. Returns 1 on success, 0 if full.
chan_len(ch: i64) → i64Current number of items in the channel buffer.
chan_close(ch: i64) → voidClose the channel (wake all blocked receivers).
chan_free(ch: i64) → voidDestroy and free the channel.

See docs/api/channel.md for the full API reference.

Raw FFI bindings to the raylib library. All functions are direct bindings to the C API — no higher-level wrapper is provided. You must link your program with -lraylib.

Note: This module has no public functions (all declarations are FFI externs). It provides 38 function bindings and 34 constant bindings to raylib. See docs/api/raylib.md for the full list.

Key bindings include:

CategoryFunctions
WindowInitWindow, CloseWindow, WindowShouldClose, SetWindowTitle, SetWindowSize, GetScreenWidth, GetScreenHeight, ToggleFullscreen
DrawingClearBackground, BeginDrawing, EndDrawing, DrawRectangle, DrawCircle, DrawLine, DrawTriangle, DrawText, DrawFPS, MeasureText
InputIsKeyPressed, IsKeyDown, IsKeyReleased, GetKeyPressed, GetCharPressed, IsMouseButtonPressed, GetMouseX, GetMouseY, GetMouseWheelMove
TimingSetTargetFPS, GetFPS, GetFrameTime, GetTime

See docs/api/raylib.md for the full API reference.

Binary-to-text encoding and decoding. Pure Axon implementation — no additional C FFI required.

FunctionSignatureDescription
hex_encode((ptr u8), i64) → stringEncode bytes as lower-case hexadecimal
hex_decode(string) → (ptr i64)Decode hex string to bytes (returns [ptr, len] header)
base64_encode((ptr u8), i64) → stringRFC 4648 base64 encode with = padding
base64_decode(string) → (ptr i64)Decode base64 string to bytes
url_encode(string) → stringRFC 3986 percent-encoding (unreserved chars pass through)
url_decode(string) → stringDecode percent-encoded string (%XX and +)
base32_encode((ptr u8), i64) → stringRFC 4648 base32 encode (A-Z2-7, = padding)
base32_decode(string) → (ptr i64)Decode base32 string to bytes (case-insensitive)
decode_ptr((ptr i64)) → (ptr u8)Extract pointer from decode result header
decode_len((ptr i64)) → i64Extract length from decode result header
decode_to_str((ptr i64)) → stringConvert decode result to Axon string

See docs/encoding.md for the full API reference.

RFC 4122 UUID v4 generation, parsing, formatting, and inspection. UUIDs are stored as two i64 values in a (ptr i64) header. Pure Axon implementation — no additional C FFI required.

FunctionSignatureDescription
uuid_nil() → (ptr i64)Returns the nil UUID (all zeros)
uuid_v4() → (ptr i64)Generate a random UUID v4
uuid_v4_seeded(i64, i64) → (ptr i64)Generate a deterministic UUID v4 from two seed values
uuid_hi((ptr i64)) → i64Extract high 64 bits from UUID header
uuid_lo((ptr i64)) → i64Extract low 64 bits from UUID header
uuid_to_string((ptr i64)) → stringFormat UUID as 8-4-4-4-12 lowercase hex string
uuid_from_string(string) → (ptr i64)Parse UUID string (case-insensitive)
uuid_version((ptr i64)) → i64Extract version nibble (4 for v4)
uuid_variant((ptr i64)) → i64Extract variant bits (2 for RFC 4122)
uuid_eq((ptr i64), (ptr i64)) → i64Compare two UUIDs for equality
uuid_is_nil((ptr i64)) → i64Check if UUID is nil

See docs/uuid.md for the full API reference.

Auto-generated API reference docs for all 19 modules are available in docs/api/.

To regenerate the docs after modifying standard library modules:

Terminal window
./scripts/gen_docs.sh

This parses each .axs module and extracts function signatures, parameter types, and return types directly from the S-expression source. One markdown file is generated per module, plus an index at docs/api/README.md.

Terminal window
# Build the compiler first
cd ../axon-lang && make
# Type-check all modules
./build/axonc --check std/math.axs
./build/axonc --check std/io.axs
./build/axonc --check std/os.axs
# Run test programs
./build/axonc --emit-qbe tests/test_math.axs -o /tmp/test.ssa && \
qbe -o /tmp/test.s /tmp/test.ssa && \
cc -o /tmp/test /tmp/test.s ../axon-lang/build/libaxon_rt.a && \
/tmp/test
# Run the full test suite
./scripts/comprehensive_test.sh

The tests/concurrency/ directory contains stress tests for the thread, channel, and evloop modules. These tests verify:

  • test_thread_race — 4 threads each increment a shared counter 100 times. Final must be 400 (no lost increments due to races).
  • test_channel_blocking — Verifies chan_try_send returns -1 on full channel, 0 after recv. Verifies chan_send blocks when channel is at capacity.
  • test_channel_deadlock — 3 producer threads send 10 values each; main thread receives 30 and verifies the sum. Completing successfully demonstrates no deadlock.
  • test_evloop_concurrent — Registers 8 fds with different event types, waits with 0ms timeout, removes all. Verifies add/wait/del consistency.
  • test_mutex_contention — 4 threads each do 100 lock/increment/unlock cycles on a shared mutex. Final must be 400 (mutex is exclusive).

The tests/test_hotswap_*.axs files are regression tests for the std/hotswap module’s load and gc runtime functions. They cover the two most failure-prone surfaces:

  • test_hotswap_gc — Verifies gc() does not crash or leak after 1000+ back-to-back load()+gc() cycles, a 50-load burst followed by a single gc(), alternating empty-string and missing-file loads, and a clean-runtime gc().
  • test_hotswap_error — Verifies every load() error path returns -1 without crashing: empty string, nonexistent paths, absolute missing paths, directory-traversal paths, very long (1024-char) paths, repeated identical queries (must be deterministic), and mixed-error sequences. Also verifies gc() still works after a burst of failed loads.

Both tests are picked up automatically by the test:axon-e2e job.

Run locally:

Terminal window
AXONC=../axon-lang/build/axonc \
QBE=../axon-lang/build/qbe \
LIB=../axon-lang/build/libaxon_rt.a \
scripts/run_concurrency_tests.sh

CI runs these via the test:concurrency job (parallel to test:axon-e2e).

CI runs line coverage tracking via test:coverage job:

  • Builds axonc + stdlib with --coverage flags
  • Runs the E2E test suite
  • Collects coverage with gcovr
  • Enforces thresholds via tools/check_coverage.py:
    • Overall line coverage: ≥ 70%
    • Per-module line coverage: ≥ 50% (with low-coverage modules flagged)

HTML coverage report is published as a pipeline artifact.

To run coverage locally:

Terminal window
# Build axonc with coverage
cd ../axon-lang && make CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="-fprofile-arcs -ftest-coverage"
# Collect coverage
AXONC_REPO=../axon-lang ./scripts/collect_coverage.sh
# Check thresholds
python3 tools/check_coverage.py coverage.json

Known low-coverage modules (targets per #63):

  • std/sort.axs — currently 0%, target ≥ 80%
  • std/hashmap.axs — currently ~30%, target ≥ 80%

Two CI jobs track runtime perf regressions:

Local runs:

Terminal window
# Type-check baseline
AXONC=../axon-lang/build/axonc STDDIR=std N_SAMPLES=3 \
scripts/bench_typecheck.sh > /tmp/samples.tsv
python3 scripts/check_typecheck_regression.py /tmp/samples.tsv \
--baseline metrics/type_check_baseline.json
# Hot-path benchmarks
python3 tools/run_benchmarks.py --lib ../axon-lang/build/libaxon_rt.a
python3 -m pytest tests/test_run_benchmarks.py tests/test_check_typecheck_regression.py -v
  • std/hotswap.axs — currently minimal, target ≥ 70%

MIT — see axon-lang for details.