axon-std
axon-std — AXON Standard Library
Section titled “axon-std — AXON Standard Library”The official standard library for the AXON programming language.
Modules
Section titled “Modules”| Module | Import Path | Description |
|---|---|---|
| math | std/math.axs | Integer & float math: abs, min, max, clamp, gcd, lcm, fsqrt, fpow, etc. |
| string | std/string.axs | String ops: len, eq, dup, concat, char_at, is_empty, println |
| io | std/io.axs | Output helpers: println, println_bool, print2, print3 |
| mem | std/mem.axs | Memory management: alloc_bytes, free_ptr, resize, copy, move, compare |
| os | std/os.axs | Process control: quit |
| collections | std/collections.axs | Dynamic array (Vec): vec_new, vec_push, vec_pop, vec_get, vec_set, etc. |
| sort | std/sort.axs | Sorting & search: sort_vec, binary_search, vec_min, vec_max, vec_sum |
| hash | std/hash.axs | Non-cryptographic FNV-1a hashing (32/64-bit) over bytes and strings: fnv1a64, fnv1a64_str, fnv1a32, fnv1a32_str. Axon strings are byte-indexed UTF-8, so the _str variants hash the same bytes as the buffer variants (verified for multi-byte input). Not collision-resistant — do not use where an adversary controls keys. |
| sha256 | std/sha256.axs | Pure-Axon SHA-256 (FIPS 180-4), no FFI: sha256, sha256_str (raw 32-byte digest), sha256_hex, sha256_hex_str (64-char lowercase hex), hex_of_digest. Verified bit-exact against the published NIST known-answer test vectors through axonc → qbe → cc → run. |
| bigint | std/bigint.axs | Arbitrary-precision signed integers (base-10, pure Axon, no FFI): from_i64, from_string, to_string, sign, is_zero, neg, abs, cmp/eq/lt, and schoolbook add/sub/mul. destroy releases. Division/Karatsuba/modpow deferred to follow-up slices (#129). |
| time | std/time.axs | Time utilities: now_secs, now_ms, sleep_ms, sleep_secs, elapsed_secs |
| fmt | std/fmt.axs | String formatting: fmt1, fmt2, fmt3, to_str, f64_to_str, bool_to_str |
| hashmap | std/hashmap.axs | Hash map: map_new, map_set, map_val, map_get_or, map_has, map_del |
| hotswap | std/hotswap.axs | Hot-swap runtime: load, gc, register_state, enter, exit |
| thread | std/thread.axs | Thread spawning and mutex primitives: spawn, join, mutex, lock, unlock |
| net | std/net.axs | TCP/UDP socket wrapper: tcp_new, sock_bind, sock_listen, sock_accept, sock_connect, etc. |
| http | std/http.axs | HTTP response builder and request parser: build_response, parse_method, parse_path, status/header constants |
| evloop | std/evloop.axs | Event loop wrapper for epoll/kqueue: evloop_new, evloop_wait, evloop_add, evloop_del |
| channel | std/channel.axs | MPSC channel primitives: chan_new, chan_send, chan_recv, chan_try_send, chan_len |
| option | std/option.axs | Option_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 |
| result | std/result.axs | Result_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 |
| raylib | std/raylib.axs | raylib FFI bindings: 38 functions for window, drawing, input, and timing |
| encoding | std/encoding.axs | Encode/decode: hex_encode, base64_encode, url_encode, base32_encode + decode counterparts |
| uuid | std/uuid.axs | RFC 4122 UUID v4: |
| unicode | std/unicode.axs | ASCII property predicates (is_ascii, is_ascii_upper/lower/digit/alpha/alnum/hex/whitespace) + utf8_byte_len codepoint→byte-width lookup (v0.1) |
| regex | std/regex.axs | Linear-time regular expressions (Thompson NFA / Pike VM, pure Axon, no FFI): compile, is_match, find, test, escape, destroy. Matching is O(n·m) with no catastrophic backtracking on any input. Slice 1 supports literals, ., classes [a-z]/[^…] with \d\w\s, anchors ^/$, quantifiers * + ?, alternation |, and groups ( ). Captures, lazy quantifiers, lookaround and replace are deferred to follow-up slices (#125). |
Machine-readable metadata (*.meta.json)
Section titled “Machine-readable metadata (*.meta.json)”Every module ships a committed std/<module>.meta.json describing its public
surface — functions, types, constants and imports — under a stable, versioned
schema (schema_version: 1). These are generated from source with the
compiler’s introspection subcommand:
axonc introspect std/fmt.axs --format=json # see axon-lang docs/cli/introspect.mdThey give tooling (an axpm search std/fmt:to_str-style index, editor
back-ends, doc generators) a way to discover the API without re-parsing .axs
source. tests/meta-drift.sh keeps them in lock-step with the sources (the
test:meta-drift CI job fails on drift); after editing a module, refresh with:
./tests/meta-drift.sh --update1. Set the library path
Section titled “1. Set the library path”Point the compiler to this repository using -L or the AXON_LIB_PATH environment variable:
# Via CLI flagaxonc -L /path/to/axon-std my_program.axs
# Via environment variableexport AXON_LIB_PATH=/path/to/axon-stdaxonc my_program.axs2. Import modules in your code
Section titled “2. Import modules in your code”(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))))Available Functions
Section titled “Available Functions”std/math
Section titled “std/math”| Function | Signature | Description |
|---|---|---|
abs | (i64) → i64 | Absolute value |
min | (i64, i64) → i64 | Smaller of two values |
max | (i64, i64) → i64 | Larger of two values |
clamp | (i64, i64, i64) → i64 | Constrain to [lo, hi] |
sign | (i64) → i64 | Returns -1, 0, or 1 |
pow | (i64, i64) → i64 | Integer exponentiation (fast squaring) |
gcd | (i64, i64) → i64 | Greatest common divisor |
lcm | (i64, i64) → i64 | Least common multiple |
div_floor | (i64, i64) → i64 | Floor division (toward −∞) |
is_even | (i64) → bool | Even check |
is_odd | (i64) → bool | Odd check |
factorial | (i64) → i64 | n! (iterative) |
fsqrt | (f64) → f64 | Square root |
fsin / fcos / ftan | (f64) → f64 | Trigonometric functions |
fpow | (f64, f64) → f64 | Floating-point power |
ffloor / fceil / fround | (f64) → f64 | Rounding |
float_abs | (f64) → f64 | Absolute value (float) |
to_radians / to_degrees | (f64) → f64 | Angle conversion |
lerp | (f64, f64, f64) → f64 | Linear interpolation |
std/string
Section titled “std/string”| Function | Signature | Description |
|---|---|---|
len | ((ptr i8)) → i64 | String length (bytes) |
eq | ((ptr i8), (ptr i8)) → bool | String 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) → i64 | Byte at index (panics OOB) |
is_empty | ((ptr i8)) → bool | Zero-length check |
println | ((ptr i8)) → void | Print string with newline |
std/io
Section titled “std/io”| Function | Signature | Description |
|---|---|---|
println | (i64) → void | Print integer with newline |
println_bool | (bool) → void | Print 1/0 for true/false |
print2 | (i64, i64) → void | Print two values |
print3 | (i64, i64, i64) → void | Print three values |
std/os
Section titled “std/os”| Function | Signature | Description |
|---|---|---|
quit | (i32) → void | Exit process with code |
std/mem
Section titled “std/mem”| Function | Signature | Description |
|---|---|---|
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)) → void | Free 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) → i32 | Compare n bytes |
std/collections
Section titled “std/collections”| Function | Signature | Description |
|---|---|---|
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) → void | Append element (auto-grows) |
vec_pop | ((ptr i64)) → i64 | Remove and return last element |
vec_get | ((ptr i64), i64) → i64 | Get element at index (bounds-checked) |
vec_set | ((ptr i64), i64, i64) → void | Set element at index (bounds-checked) |
vec_len | ((ptr i64)) → i64 | Current number of elements |
vec_cap | ((ptr i64)) → i64 | Current capacity |
vec_is_empty | ((ptr i64)) → bool | Check if empty |
vec_first / vec_last | ((ptr i64)) → i64 | Access first/last element |
vec_contains | ((ptr i64), i64) → bool | Check if value exists |
vec_index_of | ((ptr i64), i64) → i64 | Find index (-1 if not found) |
vec_swap | ((ptr i64), i64, i64) → void | Swap elements at two indices |
vec_reverse | ((ptr i64)) → void | Reverse in-place |
vec_clear | ((ptr i64)) → void | Set length to 0 |
vec_free | ((ptr i64)) → void | Free Vec and backing storage |
std/sort
Section titled “std/sort”Note: Import
std/collections.axsbeforestd/sort.axsin your program.
| Function | Signature | Description |
|---|---|---|
sort_vec | ((ptr i64)) → void | Quicksort a Vec (ascending, in-place) |
sort_vec_desc | ((ptr i64)) → void | Sort descending (sort + reverse) |
is_sorted | ((ptr i64)) → bool | Check ascending order |
is_sorted_desc | ((ptr i64)) → bool | Check descending order |
binary_search | ((ptr i64), i64) → i64 | Find index in sorted Vec (-1 if not found) |
vec_min | ((ptr i64)) → i64 | Minimum value |
vec_max | ((ptr i64)) → i64 | Maximum value |
vec_sum | ((ptr i64)) → i64 | Sum of all elements |
std/time
Section titled “std/time”| Function | Signature | Description |
|---|---|---|
now_secs | () → i64 | Current epoch time (seconds) |
now_ms | () → i64 | Current epoch time (milliseconds, second precision) |
sleep_ms | (i64) → void | Sleep for milliseconds |
sleep_secs | (i64) → void | Sleep for seconds |
elapsed_secs | (i64, i64) → i64 | Elapsed seconds between two timestamps |
has_elapsed | (i64, i64) → bool | Check if duration has passed since timestamp |
std/fmt
Section titled “std/fmt”Template-based formatting with {} placeholders. Since Axon doesn’t support varargs, use the appropriate arity function.
| Function | Signature | Description |
|---|---|---|
to_str | (i64) → string | Convert integer to string |
f64_to_str | (f64) → string | Convert float to string |
bool_to_str | (i64) → string | Convert 0/1 to “true”/“false” |
fmt1 | (string, i64) → string | Format with 1 integer |
fmt2 | (string, i64, i64) → string | Format with 2 integers |
fmt3 | (string, i64, i64, i64) → string | Format with 3 integers |
fmt_f1 / fmt_f2 | (string, f64, ...) → string | Format with floats |
fmt_b1 | (string, i64) → string | Format with boolean |
fmt_s1 / fmt_s2 | (string, string, ...) → string | Format with strings |
fmt_si | (string, string, i64) → string | Format: string then integer |
fmt_is | (string, i64, string) → string | Format: integer then string |
std/hashmap
Section titled “std/hashmap”String-keyed hash map wrapping the compiler’s built-in (map K V) type with convenience functions.
| Function | Signature | Description |
|---|---|---|
map_new | () → (map string i64) | Create a new empty map |
map_set | (map, string, i64) → void | Insert or update a key-value pair |
map_get | (map, string) → (ptr i64) | Get pointer to value (panics if missing) |
map_val | (map, string) → i64 | Get dereferenced value (panics if missing) |
map_get_or | (map, string, i64) → i64 | Get value or return default |
map_has | (map, string) → bool | Check if key exists |
map_del | (map, string) → bool | Remove a key |
map_len | (map) → i64 | Number of entries |
map_is_empty | (map) → bool | Check if map has no entries |
map_free | (map) → void | Free the map |
std/hotswap
Section titled “std/hotswap”Thread-safe dynamic module loading and hot-swap support. Wraps the runtime’s dlopen/dlsym-based symbol redirection table.
| Function | Signature | Description |
|---|---|---|
load | (string) → i32 | Load a shared object (.so/.dll) and swap hotswap-tagged function pointers. Returns 0 on success, -1 on failure. |
gc | () → void | Garbage-collect old module handles once all epoch references are released. |
register_state | ((ptr (ptr void)), string) → void | Register 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)) → void | Exit an epoch-safe region, decrementing the reference count. |
std/thread
Section titled “std/thread”Note:
std/threadmust be imported afterstd/collectionsfor the Vec types used internally by the thread module’s internal structures.
Thread spawning and mutex primitives wrapping POSIX threads via runtime FFI.
| Function | Signature | Description |
|---|---|---|
spawn | ((fn (ptr void)), (arg (ptr void))) → i64 | Spawn a new thread. Returns a handle for join. |
join | (handle: i64) → void | Block until the thread identified by handle terminates. |
mutex | () → i64 | Allocate and initialize a new mutex. |
lock | (mtx: i64) → void | Lock the mutex (blocks until available). |
unlock | (mtx: i64) → void | Unlock the mutex. |
mutex_free | (mtx: i64) → void | Destroy and free the mutex. |
See docs/api/thread.md for the full API reference.
std/net
Section titled “std/net”TCP and UDP socket wrappers providing a portable network API. All socket operations return an i64 file descriptor; check for < 0 to detect errors.
| Function | Signature | Description |
|---|---|---|
tcp_new | () → i64 | Create a new TCP socket. Returns fd or -1 on error. |
udp_new | () → i64 | Create a new UDP socket. Returns fd or -1 on error. |
set_nonblock | (fd: i64) → i64 | Set socket to non-blocking mode. Returns 0 on success. |
set_reuseaddr | (fd: i64) → i64 | Enable SO_REUSEADDR on the socket. Returns 0 on success. |
sock_bind | (fd: i64, port: i64) → i64 | Bind socket to the given port. Returns 0 on success. |
sock_listen | (fd: i64, backlog: i64) → i64 | Start listening with the given backlog. Returns 0 on success. |
sock_accept | (fd: i64) → i64 | Accept an incoming connection. Returns new client fd or -1. |
sock_connect | (fd: i64, addr: string, port: i64) → i64 | Connect to addr:port. Returns 0 on success. |
sock_read | (fd: i64, buf: (ptr void), len: i64) → i64 | Read up to len bytes into buf. Returns bytes read or -1. |
sock_write | (fd: i64, buf: (ptr void), len: i64) → i64 | Write len bytes from buf. Returns bytes written or -1. |
sock_write_str | (fd: i64, s: string) → i64 | Write a string to the socket. Returns bytes written or -1. |
sock_close | (fd: i64) → void | Close the socket. |
See docs/api/net.md for the full API reference.
std/http
Section titled “std/http”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.
| Function | Signature | Description |
|---|---|---|
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) → string | Compose a full HTTP response string. |
parse_method | (raw: string) → string | Extract HTTP method from a raw request line (e.g. "GET"). |
parse_path | (raw: string) → string | Extract request path from a raw request line (e.g. "/index.html"). |
See docs/api/http.md for the full API reference.
std/evloop
Section titled “std/evloop”Event loop wrapper for epoll (Linux) and kqueue (macOS). Manages a set of file descriptors and reports readable/writable/error events.
| Function | Signature | Description |
|---|---|---|
ev_read | () → i64 | Event mask flag for read readiness (value 1). |
ev_write | () → i64 | Event mask flag for write readiness (value 2). |
ev_error | () → i64 | Event mask flag for error condition (value 4). |
evloop_new | () → i64 | Create a new event loop. Returns handle or -1 on error. |
evloop_close | (loop: i64) → void | Destroy the event loop. |
evloop_add | (loop: i64, fd: i64, events: i64) → i64 | Register fd with the event loop. Returns 0 on success. |
evloop_del | (loop: i64, fd: i64) → i64 | Remove fd from the event loop. Returns 0 on success. |
evloop_wait | (loop: i64, buf: (ptr i64), max_events: i64, timeout_ms: i64) → i64 | Wait 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)) → void | Free an event buffer allocated by evloop_alloc_buf. |
See docs/api/evloop.md for the full API reference.
std/channel
Section titled “std/channel”Multi-producer, single-consumer (MPSC) channel for passing i64 values between threads. Channels are created with a fixed capacity; sending blocks when full.
| Function | Signature | Description |
|---|---|---|
chan_new | (capacity: i64) → i64 | Create a new channel with the given buffer capacity. |
chan_send | (ch: i64, value: i64) → void | Send a value (blocks if channel is full). |
chan_recv | (ch: i64) → i64 | Receive a value (blocks if channel is empty). |
chan_try_send | (ch: i64, value: i64) → i64 | Try to send without blocking. Returns 1 on success, 0 if full. |
chan_len | (ch: i64) → i64 | Current number of items in the channel buffer. |
chan_close | (ch: i64) → void | Close the channel (wake all blocked receivers). |
chan_free | (ch: i64) → void | Destroy and free the channel. |
See docs/api/channel.md for the full API reference.
std/raylib
Section titled “std/raylib”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.mdfor the full list.
Key bindings include:
| Category | Functions |
|---|---|
| Window | InitWindow, CloseWindow, WindowShouldClose, SetWindowTitle, SetWindowSize, GetScreenWidth, GetScreenHeight, ToggleFullscreen |
| Drawing | ClearBackground, BeginDrawing, EndDrawing, DrawRectangle, DrawCircle, DrawLine, DrawTriangle, DrawText, DrawFPS, MeasureText |
| Input | IsKeyPressed, IsKeyDown, IsKeyReleased, GetKeyPressed, GetCharPressed, IsMouseButtonPressed, GetMouseX, GetMouseY, GetMouseWheelMove |
| Timing | SetTargetFPS, GetFPS, GetFrameTime, GetTime |
See docs/api/raylib.md for the full API reference.
std/encoding
Section titled “std/encoding”Binary-to-text encoding and decoding. Pure Axon implementation — no additional C FFI required.
| Function | Signature | Description |
|---|---|---|
hex_encode | ((ptr u8), i64) → string | Encode bytes as lower-case hexadecimal |
hex_decode | (string) → (ptr i64) | Decode hex string to bytes (returns [ptr, len] header) |
base64_encode | ((ptr u8), i64) → string | RFC 4648 base64 encode with = padding |
base64_decode | (string) → (ptr i64) | Decode base64 string to bytes |
url_encode | (string) → string | RFC 3986 percent-encoding (unreserved chars pass through) |
url_decode | (string) → string | Decode percent-encoded string (%XX and +) |
base32_encode | ((ptr u8), i64) → string | RFC 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)) → i64 | Extract length from decode result header |
decode_to_str | ((ptr i64)) → string | Convert decode result to Axon string |
See docs/encoding.md for the full API reference.
std/uuid
Section titled “std/uuid”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.
| Function | Signature | Description |
|---|---|---|
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)) → i64 | Extract high 64 bits from UUID header |
uuid_lo | ((ptr i64)) → i64 | Extract low 64 bits from UUID header |
uuid_to_string | ((ptr i64)) → string | Format 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)) → i64 | Extract version nibble (4 for v4) |
uuid_variant | ((ptr i64)) → i64 | Extract variant bits (2 for RFC 4122) |
uuid_eq | ((ptr i64), (ptr i64)) → i64 | Compare two UUIDs for equality |
uuid_is_nil | ((ptr i64)) → i64 | Check if UUID is nil |
See docs/uuid.md for the full API reference.
Documentation
Section titled “Documentation”Auto-generated API reference docs for all 19 modules are available in docs/api/.
To regenerate the docs after modifying standard library modules:
./scripts/gen_docs.shThis 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.
Development
Section titled “Development”Running tests locally
Section titled “Running tests locally”# Build the compiler firstcd ../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.shConcurrency stress tests
Section titled “Concurrency stress tests”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_sendreturns -1 on full channel, 0 after recv. Verifieschan_sendblocks 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).
Hotswap regression tests
Section titled “Hotswap regression tests”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-backload()+gc()cycles, a 50-load burst followed by a singlegc(), alternating empty-string and missing-file loads, and a clean-runtimegc(). - test_hotswap_error — Verifies every
load()error path returns-1without 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 verifiesgc()still works after a burst of failed loads.
Both tests are picked up automatically by the test:axon-e2e job.
Run locally:
AXONC=../axon-lang/build/axonc \QBE=../axon-lang/build/qbe \LIB=../axon-lang/build/libaxon_rt.a \ scripts/run_concurrency_tests.shCI runs these via the test:concurrency job (parallel to test:axon-e2e).
Coverage tracking
Section titled “Coverage tracking”CI runs line coverage tracking via test:coverage job:
- Builds axonc + stdlib with
--coverageflags - 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:
# Build axonc with coveragecd ../axon-lang && make CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="-fprofile-arcs -ftest-coverage"
# Collect coverageAXONC_REPO=../axon-lang ./scripts/collect_coverage.sh
# Check thresholdspython3 tools/check_coverage.py coverage.jsonKnown low-coverage modules (targets per #63):
std/sort.axs— currently 0%, target ≥ 80%std/hashmap.axs— currently ~30%, target ≥ 80%
Performance benchmarks
Section titled “Performance benchmarks”Two CI jobs track runtime perf regressions:
-
performance:type-check-time— measuresaxonc --checktime per std module, gated againstmetrics/type_check_baseline.json. Uses a dual ratio+absolute threshold (1.5× AND 30ms) over a 3-sample median to survive shared-runner jitter. Seedocs/typecheck-regression.md. -
bench:hotpaths(axon-std#62) — links C micro-benchmarks againstlibaxon_rt.ato profile the actual runtime primitives (string ops, hashmap, channel send/recv, evloop, alloc). Gated againstmetrics/bench_baseline.json. Seedocs/benchmarks.md.
Local runs:
# Type-check baselineAXONC=../axon-lang/build/axonc STDDIR=std N_SAMPLES=3 \ scripts/bench_typecheck.sh > /tmp/samples.tsvpython3 scripts/check_typecheck_regression.py /tmp/samples.tsv \ --baseline metrics/type_check_baseline.json
# Hot-path benchmarkspython3 tools/run_benchmarks.py --lib ../axon-lang/build/libaxon_rt.apython3 -m pytest tests/test_run_benchmarks.py tests/test_check_typecheck_regression.py -vstd/hotswap.axs— currently minimal, target ≥ 70%
License
Section titled “License”MIT — see axon-lang for details.