Each input() reads the next line. Every run starts from the top. Empty input returns an empty string.
Tab indent · ↑↓ + Enter complete · Ctrl+Enter run
fn main() -> int:
x: int -> 5 // typed binding
y -> 10 // inferred binding
x <- x + 1 // assignment is <-
println(x) // with newline (print has none)
return 0
end
if x > 0:
println("pos")
else:
println("neg")
end
while x > 0:
x <- x - 1
end
for i in 0..10:
println(i)
end
match code:
200 => println("ok")
_ => println("other")
end
fn add(a: int, b: int) -> int:
return a + b
end
fn greet(name: string) -> void ![IO]:
println(name)
end
name: string -> "Olivia" msg: string -> "Hello, $(name)! Seven plus five is $(7 + 5)"
pair: (int, int) -> (3, 4) (x, y) -> pair // destructuring declaration
l: List[int] -> List[int]()
l.push(1)
println(l.get(0))
m: HashMap[string, int] -> HashMap[string, int]()
m.insert("a", 1)
struct Point:
x: int
y: int
end
p: Point -> Point{ x -> 3, y -> 4 }
println(p.x)
enum Color:
Red
Green
end
c: Color -> Color::Red
defer println("last") // runs at scope exit, LIFO
import pie::std::fs::* // core (println, print_int, ...) auto-imports
Double-ended queue (deque) with O(1) push/pop at both ends.
pub unsafe fn null_ptr() -> ptr (@intrinsic("pie.null_ptr"))pub unsafe fn set_ptr_offset(p: ptr, offset: int, value: int) -> void (@intrinsic("pie.ptr_set_offset"))pub unsafe fn get_ptr_offset(p: ptr, offset: int) -> int (@intrinsic("pie.ptr_get_offset"))pub struct Deque[T] - A circular-buffer deque allocated in the active region.pub fn new() -> Deque[T] - Creates an empty deque.pub fn push_back(self, item: T) -> void - Appends an item to the back of the deque.pub fn push_front(self, item: T) -> void - Prepends an item to the front of the deque.pub fn pop_front(self) -> Option[T] - Removes and returns the front item, or None if empty.pub fn pop_back(self) -> Option[T] - Removes and returns the back item, or None if empty.pub fn grow(self) -> void - Doubles the capacity, relocating elements into a fresh buffer.pub fn len(self) -> int - Returns the number of elements in the deque.pub fn length(self) -> int - Returns the number of elements in the deque (alias for len).pub fn is_empty(self) -> bool - Returns true if the deque contains no elements.pub fn clear(self) -> void - Clears the deque, setting count to 0 without freeing memory.Formatting utilities: hex/bin conversion and the Formattable trait.
pub trait Formattable - Trait for types that can format themselves into a StringBuilder.pub fn to_hex_str(val: int) -> string - Converts an integer to its hexadecimal string representation (e.g. 255 -> "ff").pub fn to_bin_str(val: int) -> string - Converts an integer to its binary string representation (e.g. 5 -> "101").Hash map implementation backed by parallel key/value lists.
pub struct HashMap[K, V] (@builtin("map")) - A key-value map. Construct empty with `HashMap[K, V]()` and use the member methods; lookups return `Option[V]`.map: HashMap[string, int] -> HashMap[string, int]()
map.insert("apple", 100)
println(map.len())
match map.get("apple"):
Some(val) => println(val)
None => println(0)
end
pub fn new() -> HashMap[K, V] - Creates an empty map backed by parallel key/value lists.pub fn insert(self, k: K, v: V) -> void - Inserts or replaces the value for k via linear search (O(n)). Rebuilds the parallel lists so no in-place element store is needed.pub fn get(self, k: K) -> Option[V] - Returns the value for k, or None when k is absent (O(n) search).pub fn len(self) -> int - Returns the number of entries in the map.pub fn length(self) -> int - Returns the number of entries in the map (alias for len).pub fn contains(self, k: K) -> bool - Returns true when k maps to some value (O(n) search, no get call so hijacked-name dispatch can never reroute this method).pub fn is_empty(self) -> bool - Returns true when the map holds no entries. Delegates to len() so both struct-backed and native-backed maps answer correctly on every engine (len nodes dispatch per shape).Region-backed dynamic array with exponential growth and O(1) amortized push.
pub unsafe fn null_ptr() -> ptr (@intrinsic("pie.null_ptr"))pub unsafe fn set_ptr_offset(p: ptr, offset: int, value: int) -> void (@intrinsic("pie.ptr_set_offset"))pub unsafe fn get_ptr_offset(p: ptr, offset: int) -> int (@intrinsic("pie.ptr_get_offset"))pub unsafe fn ptr_add(p: ptr, bytes: int) -> ptr (@intrinsic("pie.ptr_add"))pub unsafe fn ptr_diff(p1: ptr, p2: ptr) -> int (@intrinsic("pie.ptr_diff"))pub unsafe fn get_ptr_offset_f32(p: ptr, offset: int) -> float (@intrinsic("pie.ptr_get_offset_f32"))pub unsafe fn set_ptr_offset_f32(p: ptr, offset: int, value: float) -> void (@intrinsic("pie.ptr_set_offset_f32"))pub unsafe fn get_ptr_offset_f64(p: ptr, offset: int) -> float (@intrinsic("pie.ptr_get_offset_f64"))pub unsafe fn set_ptr_offset_f64(p: ptr, offset: int, value: float) -> void (@intrinsic("pie.ptr_set_offset_f64"))pub struct List[T] (@builtin("list")) - A growable array allocated in the active RBMM region.pub fn new() -> List[T] - Creates an empty list.pub fn with_capacity(cap: int) -> List[T] - Creates an empty list with storage for at least cap elements pre-allocated (no reallocation until push exceeds cap).pub fn reserve(self, cap: int) -> void - Pre-allocates storage for at least cap elements (grow-only: never shrinks, never changes length). Pushes up to cap perform zero reallocations.pub fn push(self, item: T) -> void - Appends an item to the end of the list, growing if needed.pub fn get(self, index: int) -> Option[T] - Returns the element at index, or None if out of bounds.pub fn pop(self) -> Option[T] - Removes and returns the last element, or None if empty.pub fn len(self) -> int - Returns the number of elements in the list.pub fn length(self) -> int - Returns the number of elements in the list (alias for len).pub fn is_empty(self) -> bool - Returns true if the list contains no elements.pub fn clear(self) -> void - Clears the list, setting length to 0 without freeing memory.Hash set implementation backed by a HashMap to integer markers.
pub fn new() -> Set[T] - Creates an empty set backed by an inner HashMap to marker bytes.pub fn add(self, v: T) -> void - Adds v to the set; adding a present value keeps size unchanged. Operates on a local alias of the inner map so only identifier receivers reach the map methods, then writes the alias back.pub fn contains(self, v: T) -> bool - Returns true when v is a member of the set.pub fn len(self) -> int - Returns the number of distinct members in the set.pub fn length(self) -> int - Returns the number of distinct members (alias for len).pub fn is_empty(self) -> bool - Returns true when the set holds no members. Delegates to len() so both struct-backed and native-backed sets answer correctly on every engine (len nodes dispatch per shape).Efficient string builder with region-backed buffer management.
pub unsafe fn null_ptr() -> ptr (@intrinsic("pie.null_ptr"))pub unsafe fn set_ptr_offset(p: ptr, offset: int, value: int) -> void (@intrinsic("pie.ptr_set_offset"))pub unsafe fn get_ptr_offset(p: ptr, offset: int) -> int (@intrinsic("pie.ptr_get_offset"))pub fn ptr_to_string(p: ptr) -> string (@intrinsic("pie.ptr_to_string")) - Copy a C NUL-terminated string into region memory.pub fn int_to_string(v: int) -> string (@intrinsic("pie.format_int")) - Render a signed integer as decimal (exact %d/%i).pub fn uint_to_string(v: uint) -> string (@intrinsic("pie.format_uint")) - Render an unsigned integer as decimal (exact %u, wraps).pub fn char_to_string(v: int) -> string (@intrinsic("pie.format_char")) - Render an integer as one character (exact %c).pub fn new() -> StringBuilder - Creates an empty builder with a null byte buffer.pub fn append_str(self, s: string) -> void - Appends every byte of s, growing the buffer as needed. Bytes are stored contiguously: each byte is written with an 8-byte offset store whose low byte lands at the target index, so the buffer always holds the exact byte sequence plus trailing zeros. Capacity keeps 8 bytes of slack for the widest store.pub fn append_int(self, v: int) -> void - Appends the decimal rendering of v (handles zero, negatives, and INT_MIN without negating it). Digits are extracted into a fixed array, then emitted most-significant first as ASCII bytes.pub fn to_string(self) -> string - Copies the buffered bytes into a fresh NUL-terminated string.pub fn len(self) -> int - Returns the number of buffered bytes.pub fn length(self) -> int - Returns the number of buffered bytes (alias for len).pub fn is_empty(self) -> bool - Returns true when no bytes have been appended. Delegates to len() so both struct-backed and native-backed builders answer correctly on every engine.Stack trace capture & debugging - zero-allocation, sub-microsecond.
pub unsafe fn null_ptr() -> ptr (@intrinsic("pie.null_ptr")) - Raw pointer access intrinsics (needed for C struct unpacking).pub unsafe fn get_ptr_offset(p: ptr, offset: int) -> int (@intrinsic("pie.ptr_get_offset"))pub fn ptr_to_string(p: ptr) -> string (@intrinsic("pie.ptr_to_string")) - Copy a C NUL-terminated string into region memory.pub fn debug_capture_stack_raw() -> ptr ![IO] (@intrinsic("pie.debug_capture_stack")) - Capture the current call stack (returns opaque C handle).pub fn debug_print_stack_raw(trace: ptr) -> void ![IO] (@intrinsic("pie.debug_print_stack")) - Print a captured stack trace to stderr.pub struct StackFrame - A single resolved stack frame.pub struct StackTrace - A captured stack trace containing multiple frames.pub fn capture_stack() -> StackTrace ![IO] - Capture the current call stack trace. Returns a StackTrace with resolved function names and source locations. C struct layout: PieDebugFrame { ip:8, fn_name:256, file_path:256, line:4, col:4, is_pure:1, is_io:1, pad:6 } Total frame size = 536 bytes. frame_count at offset 34304.pub fn print_stack(trace_ptr: ptr) -> void ![IO] - Print a stack trace to stderr with ANSI color formatting.pub fn dump_stack() -> void ![IO] - Capture and immediately print the current stack trace to stderr.Core I/O operations: printing and user input.
pub fn print_str(s: string) -> void ![IO] (@intrinsic("pie.print_str")) - Prints a string to stdout.pub fn input(prompt: string) -> string ![IO] (@intrinsic("pie.input")) - Reads a line of input from stdin, using prompt as the prompt string. Removes the line ending and returns an empty string at EOF. In the WASM playground, fill in the stdin box before running. Each call consumes one line; every run starts from the beginning of that text.pub fn print_int(val: int) -> void ![IO] (@intrinsic("pie.print_int")) - Prints an integer to stdout.pub fn println(val: int) -> void ![IO] (@intrinsic("pie.println")) - Prints an integer followed by a newline to stdout.pub fn print(val: int) -> void ![IO] (@intrinsic("pie.print")) - Prints an integer to stdout (no newline).Mathematical functions: floating-point, trigonometric, logarithmic, and bit operations.
pub fn sqrt(x: float<64>) -> float<64> (@intrinsic("llvm.sqrt.f64")) - Returns the square root of x.pub fn pow(base: float<64>, exp: float<64>) -> float<64> (@intrinsic("llvm.pow.f64")) - Returns base raised to the power exp.pub fn abs(x: float<64>) -> float<64> (@intrinsic("llvm.fabs.f64")) - Returns the absolute value of a float.pub fn ceil(x: float<64>) -> float<64> (@intrinsic("llvm.ceil.f64")) - Rounds x up to the nearest integer.pub fn floor(x: float<64>) -> float<64> (@intrinsic("llvm.floor.f64")) - Rounds x down to the nearest integer.pub fn fma(a: float<64>, b: float<64>, c: float<64>) -> float<64> (@intrinsic("llvm.fma.f64")) - Returns a*b + c (fused multiply-add).pub fn popcount(x: int) -> int (@intrinsic("llvm.ctpop.i64")) - Returns the number of set bits (population count).pub fn clz(x: int) -> int (@intrinsic("llvm.ctlz.i64")) - Returns the number of leading zeros.pub fn cttz(x: int) -> int (@intrinsic("llvm.cttz.i64")) - Returns the number of trailing zeros.pub fn sin(x: float<64>) -> float<64> (@intrinsic("llvm.sin.f64")) - Returns the sine of x (radians).pub fn cos(x: float<64>) -> float<64> (@intrinsic("llvm.cos.f64")) - Returns the cosine of x (radians).pub fn tan(x: float<64>) -> float<64> (@intrinsic("pie.math_tan_f64")) - Returns the tangent of x (radians).pub fn atan2(y: float<64>, x: float<64>) -> float<64> (@intrinsic("pie.math_atan2_f64")) - Returns the arctangent of y/x, using the signs to determine quadrant.pub fn asin(x: float<64>) -> float<64> (@intrinsic("pie.math_asin_f64")) - Returns the arcsine of x.pub fn acos(x: float<64>) -> float<64> (@intrinsic("pie.math_acos_f64")) - Returns the arccosine of x.pub fn atan(x: float<64>) -> float<64> (@intrinsic("pie.math_atan_f64")) - Returns the arctangent of x.pub fn log(x: float<64>) -> float<64> (@intrinsic("llvm.log.f64")) - Returns the natural logarithm of x.pub fn exp(x: float<64>) -> float<64> (@intrinsic("llvm.exp.f64")) - Returns e raised to the power x.pub fn log10(x: float<64>) -> float<64> (@intrinsic("llvm.log10.f64")) - Returns the base-10 logarithm of x.pub fn log2(x: float<64>) -> float<64> (@intrinsic("llvm.log2.f64")) - Returns the base-2 logarithm of x.pub fn round(x: float<64>) -> float<64> (@intrinsic("llvm.round.f64")) - Returns x rounded to the nearest integer.pub fn fmin(a: float<64>, b: float<64>) -> float<64> (@intrinsic("llvm.minnum.f64")) - Returns the smaller of a and b (NaN-tolerant).pub fn fmax(a: float<64>, b: float<64>) -> float<64> (@intrinsic("llvm.maxnum.f64")) - Returns the larger of a and b (NaN-tolerant).pub fn fclamp(val: float<64>, low: float<64>, high: float<64>) -> float<64> - Clamps val to the range [low, high].pub fn bit_lshr(x: int, n: int) -> int (@intrinsic("pie.bit_lshr_i64")) - Logical (unsigned) right shift with zero-fill.Low-level memory allocation: region-based alloc, realloc, promote, and pool.
pub fn alloc(size: int, align: int) -> ptr (@intrinsic("pie.region_alloc")) - Allocates `size` bytes with the given alignment in the current region.pub fn realloc_raw(p: ptr, old_sz: int, new_sz: int, align: int) -> ptr (@intrinsic("pie.region_realloc")) - Reallocates a region pointer from old_sz to new_sz bytes.pub fn promote(p: ptr, sz: int) -> ptr (@intrinsic("pie.region_promote")) - Promotes a region pointer to the parent scope, keeping it alive beyond the current region.pub fn leave() -> void (@intrinsic("pie.region_leave")) - Leaves the current region scope, releasing all non-promoted allocations.pub fn pool_alloc(elem_size: int, align: int) -> ptr (@intrinsic("pie.pool_alloc")) - Allocates an element from the object pool with the given size and alignment.pub fn pool_free(p: ptr) -> void (@intrinsic("pie.pool_free")) - Returns an element to the object pool.pub unsafe fn ptr_from_int(address: int) -> ptr (@intrinsic("pie.ptr_from_int")) - Converts a raw integer address to a pointer (unsafe: bypasses region system).pub unsafe fn transmute_bits(val: int) -> int (@intrinsic("pie.transmute_bits")) - Reinterprets the bit pattern of an integer value (unsafe: type punning).pub unsafe fn malloc_raw(size: int, align: int) -> ptr (@intrinsic("pie.malloc_raw")) - Raw malloc bypassing the Pie region system (unsafe: manual free required).pub unsafe fn free_raw(p: ptr) -> void (@intrinsic("pie.free_raw")) - Raw free bypassing the Pie region system (unsafe: only for pie_malloc_raw results).pub unsafe fn realloc_raw(p: ptr, new_sz: int) -> ptr (@intrinsic("pie.realloc_raw")) - Raw realloc bypassing the Pie region system (unsafe: NULL acts as malloc; size 0 yields a minimal live object, matching libc).pub unsafe fn static_cell(size: int, init: int[8]) -> ptr (@intrinsic("pie.static_cell")) - Static storage cell: zeroed program-lifetime memory for C-style file-scope state (unsafe: manual discipline required). The BINDING stays immutable (`->` declares it once); only the bytes mutate, through `unsafe:` raw stores. No `mut` keyword needed. Phase-2 initialized cells: `static_cell(SIZE, INIT)` pre-fills the home with INIT bytes instead of zeros (linkage/align/writability unchanged; only the initializer differs). INIT is an array literal of bytes (`len == SIZE`, elements `0..255`); that per-call length rule is enforced on the call AST (typecheck F2), so the `int[8]` capacity here is a syntactic placeholder, never consulted for calls. The capacity spelling is a fixed array (NOT `int[]`): a slice param would silently disable E003 arity checking entirely. There is deliberately NO default on INIT: defaults do not cross modules (importers would still E003 on the 1-arg form), and no fixed default could satisfy `len == SIZE` for every caller. The 1-arg zeroed form keeps working via an explicit 1..2 arity carve-out for the `pie.static_cell` intrinsic in the three E003 paths (typecheck.c).Optional value type: represents a value that may or may not be present.
pub enum Option[T] - An optional value: Some(value) when present, None when absent.pub fn is_some(self) -> bool - Returns true if this is a Some variant.pub fn is_none(self) -> bool - Returns true if this is a None variant.pub fn unwrap_or(self, default_val: T) -> T - Returns the inner value if Some, otherwise returns default_val.Core primitive operations: integer arithmetic, intrinsics, and utilities.
pub fn null_str() -> string (@intrinsic("pie.null_ptr")) - Returns the NULL string - a zero-length string with null pointer.pub fn size_of[T]() -> int ![Pure] (@intrinsic("pie.type_size")) - Returns the ABI byte size of type T at compile time.pub fn align_of[T]() -> int ![Pure] (@intrinsic("pie.type_align")) - Returns the ABI alignment of type T at compile time.pub fn black_box[T](val: T) -> T ![Pure] (@intrinsic("pie.black_box")) - Returns val unchanged; the optimizer cannot see through this call.pub fn min(a: int, b: int) -> int ![Pure] - Returns the smaller of two integers.pub fn max(a: int, b: int) -> int ![Pure] - Returns the larger of two integers.pub fn clamp(val: int, low: int, high: int) -> int ![Pure] - Clamps val to the range [low, high].pub fn abs_int(x: int) -> int ![Pure] - Returns the absolute value of an integer.pub fn is_even(x: int) -> bool ![Pure] - Returns true if x is even.pub fn is_odd(x: int) -> bool ![Pure] - Returns true if x is odd.Half-open range type: represents [start, end) intervals.
pub struct Range[T] (@builtin("range")) - A half-open range [start, end). Used for iteration and slicing.pub fn contains(self, val: int) -> bool ![Pure] - Returns true if val is within [start, end).pub fn len(self) -> int ![Pure] - Returns the number of integers in the range.pub fn is_empty(self) -> bool ![Pure] - Returns true if the range is empty.pub fn type_name_of[T]() -> string (@intrinsic("pie.reflect_type_name"))pub fn field_count_of[T]() -> int (@intrinsic("pie.reflect_field_count"))pub fn field_name_at[T](idx: int) -> string (@intrinsic("pie.reflect_field_name_at"))pub fn field_type_at[T](idx: int) -> string (@intrinsic("pie.reflect_field_type_at"))pub fn reflect_size_of[T]() -> int (@intrinsic("pie.reflect_size_of"))pub fn reflect_align_of[T]() -> int (@intrinsic("pie.reflect_align_of"))pub fn debug_dump[T]() -> int (@intrinsic("pie.reflect_debug_dump"))pub fn for_each_field[T](callback: fn(string, int) -> int) -> int (@intrinsic("pie.reflect_for_each_field"))Result type for error handling: Ok(value) on success, Err(error) on failure.
pub fn to_int(s: string) -> Result[int, int] (@intrinsic("pie.to_int")) - Parses a string to an integer, returning Ok(value) or Err(error_code).pub enum Result[T, E] - A result of an operation that may succeed or fail.pub fn is_ok(self) -> bool - Returns true if this is an Ok variant.pub fn is_err(self) -> bool - Returns true if this is an Err variant.pub fn unwrap_or(self, default_val: T) -> T - Returns the inner value if Ok, otherwise returns default_val.Slice operations: length checks, safe indexing, and sub-slicing.
pub fn len(self) -> int ![Pure] - Returns the number of elements in the slice.pub fn is_empty(self) -> bool ![Pure] - Returns true if the slice contains no elements.pub fn get(self, index: int) -> Option[T] ![Pure] - Returns the element at index, or None if out of bounds.pub fn subslice(self, start: int, stop: int) -> Slice[T] ![Pure] - Returns a sub-slice from start to stop (exclusive). Returns empty slice if out of bounds.Built-in testing and assertion suite.
pub fn assert_true(cond: bool) -> void ![IO] - Asserts that cond is true; aborts with an error message on failure.pub fn assert_eq(actual: int, expected: int) -> void ![IO] - Asserts that actual equals expected; aborts with details on mismatch.pub fn assert_ne(actual: int, expected: int) -> void ![IO] - Asserts that actual is not equal to expected; aborts with details on mismatch.Async task spawning, futures, and non-blocking I/O reactor.
pub struct Future[T] - A future that holds a computed result once ready.pub fn is_ready(self) -> bool ![Pure] - Returns true if the future has completed.pub fn async_scope_enter_c() -> ptr ![IO] (@intrinsic("pie.async_scope_enter"))pub fn async_scope_spawn_c(scope_ptr: ptr, task_fn: ptr) -> int ![IO] (@intrinsic("pie.async_scope_spawn"))pub fn async_scope_wait_c(scope_ptr: ptr) -> void ![IO] (@intrinsic("pie.async_scope_wait"))pub struct Scope - A structured concurrency scope that manages spawned tasks.pub fn wait_all(self) -> void ![IO] - Blocks until all tasks in this scope have completed.pub fn spawn(s: Scope, task_fn: ptr) -> Future[int] ![IO] - Spawns a task in the given scope, returning a ready Future.pub fn scope(scope_fn: ptr) -> void ![IO] - Creates a scope, runs scope_fn, then waits for all spawned tasks.pub fn async_reactor_init_c() -> int ![IO] (@intrinsic("pie.async_reactor_init"))pub fn async_reactor_register_c(epfd: int, fd: int, events: int) -> int ![IO] (@intrinsic("pie.async_reactor_register"))pub fn async_reactor_poll_c(epfd: int, timeout_ms: int) -> int ![IO] (@intrinsic("pie.async_reactor_poll"))pub struct Reactor - An I/O event reactor wrapping epoll/kqueue.pub fn create() -> Result[Reactor, int] ![IO] - Creates a new reactor. Returns Err(errno) on failure.pub fn register(self, fd: int, events: int) -> Result[int, int] ![IO] - Registers a file descriptor with the given event mask. Returns Err(errno) on failure.pub fn poll(self, timeout_ms: int) -> int ![IO] - Polls for events, blocking up to timeout_ms milliseconds. Returns number of ready events.Process environment: command-line arguments and environment variables.
pub fn env_argc() -> int ![IO] (@intrinsic("pie.env_argc"))pub fn env_argv(index: int) -> string ![IO] (@intrinsic("pie.env_argv"))pub fn env_argv_ptr() -> ptr ![IO] (@intrinsic("pie.env_argv_ptr"))pub fn env_get_var_c(key: string) -> Option[string] ![IO] (@intrinsic("pie.env_get_var"))pub fn env_set_var_c(key: string, value: string) -> int ![IO] (@intrinsic("pie.env_set_var"))pub fn env_remove_var_c(key: string) -> int ![IO] (@intrinsic("pie.env_remove_var"))pub fn env_has_var_c(key: string) -> int ![IO] (@intrinsic("pie.env_has_var"))pub fn env_current_dir_c() -> string ![IO] (@intrinsic("pie.env_current_dir"))pub fn args() -> List[string] ![IO] - Returns the command-line arguments (including argv[0]).pub fn args_int(index: int, default: int) -> int ![IO] - Returns argv[index] parsed as an integer, or default when the argument is missing or does not parse. Benchmark kernels must size their loops from this (never a fixed constant) and pass results through pie::core::primitive::black_box, so optimizers cannot constant-fold the workload away or delete it (methodology note: issue 02).pub fn var(key: string) -> Option[string] ![IO] - Reads an environment variable by key. Returns None if not set.pub fn set_var(key: string, value: string) -> Result[void, int] ![IO] - Creates or overwrites an environment variable. Returns Err(errno) on failure.pub fn remove_var(key: string) -> Result[void, int] ![IO] - Deletes an environment variable. Returns Err(errno) on failure.pub fn contains_var(key: string) -> int ![IO] - Returns 1 if the environment variable is set, 0 otherwise.pub fn set_current_dir(path: string) -> bool ![IO] - Changes the process working directory. True on success (false on missing/forsaken paths — and always false on WASI, which has no mutable process cwd).pub fn current_dir() -> Result[string, int] ![IO] - Returns the current working directory, or Err(-1) if undeterminable.pub fn exists(path: string) -> bool ![IO]pub fn read_bytes(path: string, out_len: ptr) -> ptr ![IO] - Read an entire file as NUL-transparent bytes into malloc'd memory. out_len receives the byte count (0 with null return on failure). The caller owns the buffer (free with free_raw from core::memory).pub fn write_bytes(path: string, data: ptr, len: int) -> int ![IO] - Write raw bytes (NUL-transparent). Returns bytes written, -1 on error.pub fn read_string(path: string) -> Result[string, int] ![IO]pub fn write_string(path: string, content: string) -> Result[void, int] ![IO]pub fn remove_file(path: string) -> Result[void, int] ![IO]pub fn create_dir(path: string) -> Result[void, int] ![IO]pub fn remove_dir(path: string) -> Result[void, int] ![IO]pub fn read_dir(path: string) -> Result[List[string], int] ![IO]pub fn response_ok(body: string) -> Response ![Pure]pub fn response_ok_with_headers(body: string, headers: string) -> Response ![Pure]pub fn response_not_found() -> Response ![Pure]pub fn response_error(status: int, body: string) -> Response ![Pure]pub fn get(url: string) -> Result[HttpResponse, string] ![IO]pub fn post(url: string, body: string) -> Result[HttpResponse, string] ![IO]pub fn get_with_headers(url: string, headers: string) -> Result[HttpResponse, string] ![IO]pub fn post_with_headers(url: string, body: string, headers: string) -> Result[HttpResponse, string] ![IO]pub fn client_builder() -> HttpClient ![Pure]pub fn client_with_connections(client: HttpClient, max_conn: int) -> HttpClient ![Pure]pub fn client_with_timeout(client: HttpClient, timeout: int) -> HttpClient ![Pure]pub fn server_bind(bind_addr: string, port: int) -> HttpServer ![Pure]pub fn server_with_threads(server: HttpServer, num_threads: int) -> HttpServer ![Pure]pub fn server_with_file(server: HttpServer, file_path: string) -> HttpServer ![IO]pub fn server_with_static_dir(server: HttpServer, dir_path: string) -> HttpServer ![IO]pub fn server_with_tls(server: HttpServer, cert_path: string, key_path: string) -> HttpServer ![IO]pub fn server_with_http2(server: HttpServer) -> HttpServer ![IO]pub fn h2_default_settings() -> int ![Pure] (@intrinsic("pie.h2_default_settings"))pub fn h2_connection_create(fd: int, ssl: int, server: int) -> int ![Pure] (@intrinsic("pie.h2_connection_create"))pub fn h2_connection_feed(conn: int, data: int, len: int) -> int ![IO] (@intrinsic("pie.h2_connection_feed"))pub fn h2_connection_flush(conn: int) -> int ![IO] (@intrinsic("pie.h2_connection_flush"))pub fn h2_connection_alive(conn: int) -> int ![Pure] (@intrinsic("pie.h2_connection_alive"))pub fn h2_connection_destroy(conn: int) -> int ![IO] (@intrinsic("pie.h2_connection_destroy"))pub fn h2_send_response(conn: int, stream_id: int, status: int, body: int, body_len: int, headers: int) -> int ![IO] (@intrinsic("pie.h2_send_response"))pub fn h2_server_push(conn: int, stream_id: int, path: int) -> int ![IO] (@intrinsic("pie.h2_server_push"))pub fn h3_is_available() -> int ![Pure] (@intrinsic("pie.h3_is_available"))pub fn h3_server_create(addr: int, port: int, cert: int, key: int, server: int) -> int ![Pure] (@intrinsic("pie.h3_server_create"))pub fn h3_server_run(server: int) -> int ![IO] (@intrinsic("pie.h3_server_run"))pub fn h3_server_stop(server: int) -> int ![IO] (@intrinsic("pie.h3_server_stop"))pub fn h3_server_destroy(server: int) -> int ![IO] (@intrinsic("pie.h3_server_destroy"))pub fn h3_send_response(server: int, stream_id: int, status: int, body: int, body_len: int, headers: int) -> int ![IO] (@intrinsic("pie.h3_send_response"))pub fn h3_connection_alive(server: int) -> int ![Pure] (@intrinsic("pie.h3_connection_alive"))pub fn h3_connection_destroy(server: int) -> int ![IO] (@intrinsic("pie.h3_connection_destroy"))File and stream I/O abstractions with standard stream handles.
pub fn open(p: Path) -> Result[File, int] ![IO] - Opens an existing file for reading. Returns Err(errno) on failure.pub fn create(p: Path) -> Result[File, int] ![IO] - Creates a new file (truncate) for writing. Returns Err(errno) on failure.pub fn write_string(self, s: string) -> Result[int, int] ![IO] - Writes a string to the file. Returns Ok(bytes_written) or Err(errno).pub fn read_to_string(self) -> Result[string, int] ![IO] - Reads the entire file content into a string. Returns Err(errno) on failure.pub fn close(self) -> void ![IO] - Closes the file handle.pub fn stdin() -> ptr ![IO] (@intrinsic("pie.io_stdin")) - Returns a handle to stdin (fd 0).pub fn stdout() -> ptr ![IO] (@intrinsic("pie.io_stdout")) - Returns a handle to stdout (fd 1).pub fn stderr() -> ptr ![IO] (@intrinsic("pie.io_stderr")) - Returns a handle to stderr (fd 2).pub fn flush_stdout() -> void ![IO] (@intrinsic("pie.io_flush")) - Flushes stdout. Needed when output has no trailing newline (TUI frames): the runtime line-buffers stdout with no other flush path.JSON format serialization: integer field parsing and string escaping.
pub fn parse_json_int_field(json_str: string, field_name: string) -> Option[int] ![Pure] - Parses a JSON integer field by name. Returns Some(value) or None.pub fn escape_json_string(raw: string) -> string ![Pure] (@intrinsic("pie.json_escape_str")) - Escapes a raw string for safe embedding in JSON.Process execution: subprocess spawning, pipe redirection, and exit status.
pub fn process_new_c(prog: string) -> int ![IO] (@intrinsic("pie.process_new"))pub fn process_add_arg_c(h: int, a: string) -> int ![IO] (@intrinsic("pie.process_add_arg"))pub fn process_spawn_h(h: int) -> int ![IO] (@intrinsic("pie.process_spawn"))pub fn process_wait_c(pid: int) -> int ![IO] (@intrinsic("pie.process_wait"))pub fn process_kill_c(pid: int) -> int ![IO] (@intrinsic("pie.process_kill"))pub fn process_output_h(h: int) -> ptr ![IO] (@intrinsic("pie.process_output"))pub fn process_config_stdio_c(h: int, which: int, cfg: Stdio) -> int ![IO] (@intrinsic("pie.process_config_stdio"))pub fn process_spawn_piped_c(h: int) -> int ![IO] (@intrinsic("pie.process_spawn_piped"))pub fn process_write_stdin_c(pid: int, data: string) -> int ![IO] (@intrinsic("pie.process_write_stdin"))pub fn process_read_stdout_c(pid: int) -> string ![IO] (@intrinsic("pie.process_read_stdout"))pub fn process_exit_status_c(pid: int) -> ptr ![IO] (@intrinsic("pie.process_exit_status"))pub enum Stdio - Stdio configuration for subprocess redirection.pub struct Command - A builder for configuring and spawning a subprocess.pub struct ChildProcess - A handle to a running child process.pub struct ExitStatus - The exit status of a terminated process.pub struct ProcessOutput - The captured output of a completed process.pub fn new(prog: string) -> Command - Creates a new Command for the given program.pub fn arg(self, a: string) -> Command - Appends an argument to the command.pub fn stdin(self, cfg: Stdio) -> Command - Configures stdin redirection.pub fn stdout(self, cfg: Stdio) -> Command - Configures stdout redirection.pub fn stderr(self, cfg: Stdio) -> Command - Configures stderr redirection.pub fn spawn(self) -> Result[ChildProcess, int] ![IO] - Spawns the process with piped stdio. Returns Err(-1) on failure.pub fn output(self) -> Result[ProcessOutput, int] ![IO] - Runs the process and captures its output. Returns Err(-1) on failure.pub fn write_stdin(self, data: string) -> Result[int, int] ![IO] - Writes data to the process stdin. Returns Err(errno) on failure.pub fn read_stdout(self) -> Result[string, int] ![IO] - Reads the process stdout. Returns Err(-1) on failure.pub fn exit_status(self) -> Result[ExitStatus, int] ![IO] - Returns the exit status after the process has terminated.pub fn wait(self) -> Result[int, int] ![IO] - Waits for the process to exit and returns its exit code.pub fn kill(self) -> Result[void, int] ![IO] - Kills the process. Returns Err(errno) on failure.Fast pseudo-random number generator (Xoshiro256**) and OS entropy.
pub struct Rng - State for the Xoshiro256** PRNG. Each Rng advances independently.pub fn rotl(x: int, k: int) -> int - Rotate-left using logical shift.pub fn seed(seed_val: int) -> Rng - Creates a new Rng seeded from a single integer.pub fn next_u64(self) -> int - Advances the generator and returns the raw 64-bit output word.pub fn next_int(self, min_val: int, max_val: int) -> int - Returns a uniform integer in [min_val, max_val).pub fn csprng_bytes_c(buf_ptr: ptr, len: int) -> int ![IO] (@intrinsic("pie.io_csprng_bytes")) - Fills a buffer with OS entropy bytes. Returns Err(reason) on failure.pub fn csprng_u64() -> int ![IO] - Draws one raw 64-bit word of OS entropy. Returns -1 on failure.pub fn csprng_fill(buf: int[]) -> Result[void, int] ![IO] - Fills a buffer with OS entropy. Returns Err(reason) on failure.pub fn sample_uniform_float(rng: Rng) -> float<64> - Returns one uniform double in [0.0, 1.0).pub fn sample_normal(rng: Rng, mean_val: float<64>, std_dev: float<64>) -> float<64> - Box-Muller transform: returns a normal-distributed sample.pub fn roll_dice(rng: Rng, count: int, sides: int) -> int - Returns the sum of `count` dice each with `sides` faces. Returns 0 for degenerate inputs.pub fn coin_flip(rng: Rng, probability: float<64>) -> bool - Bernoulli trial: returns true with the given probability.Serialization and deserialization traits for structured data.
pub trait Serialize - Trait for types that can serialize their fields into a StringBuilder.pub trait Deserialize - Trait for types that can be deserialized from external data.General-purpose graceful shutdown coordinator.
pub fn init() -> int (@intrinsic("pie.shutdown_init")) - Initialize the global shutdown coordinator. Must be called once at startup (from main thread).pub fn is_requested() -> int (@intrinsic("pie.shutdown_requested")) - Check if graceful shutdown has been requested. Returns 1 if shutdown was requested, 0 otherwise.pub fn request() -> int (@intrinsic("pie.shutdown_request")) - Request graceful shutdown. All threads calling requested() will see 1 after this.pub fn wait_for_completion() -> int (@intrinsic("pie.shutdown_wait")) - Wait for all registered workers to finish. Main thread calls this after request() to block until done.UTF-8 string conveniences.
pub fn find(self: string, needle: string) -> Option[int] ![Pure] - Returns the first matching byte offset, or None. An empty needle matches at 0.pub fn rfind(self: string, needle: string) -> Option[int] ![Pure] - Returns the last matching byte offset, or None. An empty needle matches at len().pub fn contains(self: string, needle: string) -> bool ![Pure] - Returns whether needle occurs anywhere. An empty needle is always contained.pub fn starts_with(self: string, prefix: string) -> bool ![Pure] - Returns whether self begins with prefix. An empty prefix always matches.pub fn ends_with(self: string, suffix: string) -> bool ![Pure] - Returns whether self ends with suffix. An empty suffix always matches.pub fn split(self: string, delimiter: string) -> List[string] ![Pure] - Splits at non-overlapping delimiter matches, retaining empty fields, including trailing ones. An empty delimiter splits at UTF-8 codepoint boundaries with an empty field at both ends (not grapheme boundaries).pub fn split_once(self: string, delimiter: string) -> Option[(string, string)] ![Pure] - Splits only at the first delimiter, returning Some((head, rest)), or None. With an empty delimiter, returns Some(("", self)). Substrings are copied.pub fn lines(self: string) -> List[string] ![Pure] - Splits LF and CRLF lines, removing the line ending. A trailing newline adds no extra line. Empty text gives an empty list; lone CR is retained.pub fn words(self: string) -> List[string] ![Pure] - Splits contiguous ASCII whitespace, discarding empty tokens. Unicode whitespace such as non-breaking space is retained in tokens.pub fn trim(self: string) -> string ![Pure] - Removes ASCII whitespace from both ends, returning a copied substring.pub fn trim_start(self: string) -> string ![Pure] - Removes leading ASCII whitespace, returning a copied substring.pub fn trim_end(self: string) -> string ![Pure] - Removes trailing ASCII whitespace, returning a copied substring.pub fn strip_prefix(self: string, prefix: string) -> Option[string] ![Pure] - Removes one matching prefix, returning Some(remainder), or None.pub fn strip_suffix(self: string, suffix: string) -> Option[string] ![Pure] - Removes one matching suffix, returning Some(remainder), or None.pub fn replace(self: string, from: string, to: string) -> string ![Pure] - Replaces all non-overlapping matches. An empty from inserts to at every UTF-8 codepoint boundary, including both ends. Returns a new string.pub fn repeat(self: string, n: int) -> string ![Pure] - Repeats self n times. Nonpositive counts return empty. Panics if the resulting byte length would overflow int; allocation limits still apply.pub fn join(items: List[string], separator: string) -> string ![Pure] - Joins items with separator using StringBuilder. Empty items give "".import pie::std::string
text: string -> " red,green,blue "
clean: string -> text.trim()
colors: List[string] -> clean.split(",")
println(join(colors, " / "))
Lock-free MPSC channel and hardware atomic primitives for inter-thread communication.
pub fn channel_create_c() -> ptr ![IO] (@intrinsic("pie.channel_create"))pub fn channel_send_c(chan: ptr, val: int) -> int ![IO] (@intrinsic("pie.channel_send"))pub fn channel_recv_c(chan: ptr, out_val: ptr) -> int ![IO] (@intrinsic("pie.channel_recv"))pub fn channel_destroy_c(chan: ptr) -> void ![IO] (@intrinsic("pie.channel_destroy"))pub fn channel() -> ptr ![IO] - Creates a new MPSC channel. The handle is heap-allocated and stays valid after the creating scope exits (and across threads). Release it with `destroy` when done; destroying twice (or destroying null) is a safe no-op.pub fn send(ch: ptr, val: int) -> void ![IO] - Sends an integer value through the channel.pub fn destroy(ch: ptr) -> void ![IO] - Destroys a channel created by `channel`. Must be sequenced after the last concurrent send/recv (join producers first). The handle must not be used afterwards.pub fn recv(ch: ptr) -> Option[int] ![IO] - Receives a value from the channel, or None if empty.pub struct AtomicInt - A thread-safe atomic 64-bit integer backed by hardware atomics.pub fn new(val: int) -> AtomicInt ![IO] - Creates a new atomic integer with the given value.pub fn load(self) -> int ![IO] - Atomically loads and returns the current value.pub fn store(self, val: int) -> void ![IO] - Atomically stores the given value.pub fn fetch_add(self, val: int) -> int ![IO] - Atomically adds val and returns the previous value.pub fn compare_exchange(self, expected: int, desired: int) -> bool ![IO] - Compare-and-swap: if current == expected, sets to desired. Returns true on success.pub fn free(self) -> void ![IO] - Releases the atomic cell created by `new`. The handle is heap-allocated and stays valid after the creating scope exits (and across threads). Must be sequenced after the last concurrent access; freeing twice (or freeing null) is a safe no-op. The handle must not be used afterwards.ANSI terminal styling: colors, bold, cursor movement, and raw mode.
pub fn is_tty(fd: int) -> bool ![IO] (@intrinsic("pie.io_isatty")) - Returns true if the given file descriptor is a TTY.pub fn red(s: string) -> string (@intrinsic("pie.terminal_red")) - Wraps the string in ANSI red color escapes.pub fn green(s: string) -> string (@intrinsic("pie.terminal_green")) - Wraps the string in ANSI green color escapes.pub fn yellow(s: string) -> string (@intrinsic("pie.terminal_yellow")) - Wraps the string in ANSI yellow color escapes.pub fn blue(s: string) -> string (@intrinsic("pie.terminal_blue")) - Wraps the string in ANSI blue color escapes.pub fn bold(s: string) -> string (@intrinsic("pie.terminal_bold")) - Wraps the string in ANSI bold escapes.pub fn strip_ansi(s: string) -> string (@intrinsic("pie.strip_ansi")) - Strips all ANSI escape sequences from the string.pub fn enable_raw_mode() -> void ![IO] (@intrinsic("pie.io_enable_raw_mode")) - Enables terminal raw mode (no line buffering).pub fn disable_raw_mode() -> void ![IO] (@intrinsic("pie.io_disable_raw_mode")) - Disables terminal raw mode, restoring normal buffering.pub fn read_char() -> int ![IO] (@intrinsic("pie.io_read_char")) - Reads a single keypress in raw mode, returning the character code. Returns -1 on EOF/error, -2 when a terminal resize interrupted the read (re-poll size and redraw).pub fn read_char_timeout(ms: int) -> int ![IO] (@intrinsic("pie.io_read_char_timeout")) - Reads a single keypress, waiting at most ms milliseconds. Returns the byte (0-255), -1 on EOF/error, -2 on terminal resize, -3 when the wait expired. Resize-aware loops poll size on -2/-3.pub fn term_cols() -> int ![IO] (@intrinsic("pie.io_term_cols")) - Terminal width in cells (80 when the platform query fails).pub fn term_rows() -> int ![IO] (@intrinsic("pie.io_term_rows")) - Terminal height in cells (24 when the platform query fails).pub fn move_cursor(line: int, col: int) -> void ![IO] - Moves the cursor to the given line and column.pub fn cursor_up(n: int) -> void ![IO] - Moves the cursor up by n lines.pub fn cursor_down(n: int) -> void ![IO] - Moves the cursor down by n lines.pub fn cursor_right(n: int) -> void ![IO] - Moves the cursor right by n columns.pub fn cursor_left(n: int) -> void ![IO] - Moves the cursor left by n columns.pub fn clear_screen() -> void ![IO] - Clears the entire screen and moves cursor to top-left.pub fn clear_line() -> void ![IO] - Clears the current line.pub fn hide_cursor() -> void ![IO] - Hides the terminal cursor.pub fn show_cursor() -> void ![IO] - Shows the terminal cursor.pub fn save_cursor() -> void ![IO] - Saves the current cursor position.pub fn restore_cursor() -> void ![IO] - Restores the previously saved cursor position.Thread spawning and joining via native OS threads.
pub fn thread_spawn_c(entry_fn: ptr, arg: ptr) -> ptr ![IO] (@intrinsic("pie.thread_spawn"))pub fn thread_join_c(handle: ptr) -> int ![IO] (@intrinsic("pie.thread_join"))pub struct ThreadHandle - A handle to a spawned OS thread.pub fn spawn(entry_fn: ptr) -> ThreadHandle ![IO] - Spawns a new OS thread running entry_fn.pub fn join(self) -> Result[int, int] ![IO] - Blocks until the thread finishes and returns its exit code.Time utilities: Unix timestamps, numeric UTC calendar dates, monotonic instants, durations, and thread sleep. Calendar names and formatting belong in application code; this module does not choose a language or locale.
pub fn time_now_nanos() -> int ![IO] (@intrinsic("pie.time_now")) - Returns the current time in nanoseconds since an arbitrary epoch.pub fn unix_now() -> int ![IO] (@intrinsic("pie.time_unix")) - Returns wall-clock seconds since 1970-01-01 00:00:00 UTC (Unix time). Use utc_from_unix() to split a timestamp into calendar fields, or utc_now() to read the clock and split it in one call. Use now() for elapsed timing.pub struct DateTime - Numeric Gregorian calendar fields. year is the full year (including year 0 and negative years); month is 1-12; day is 1-31 within that month; hour is 0-23; minute and second are 0-59. weekday is 1-7, starting with Monday; day_of_year is 1-366, starting at 1 on the first day of the year. utc_from_unix() and utc_now() return UTC, independent of the host timezone.pub fn is_leap_year(year: int) -> bool - Returns whether the Gregorian year has 366 days. Century years are leap years only when divisible by 400. The same rule applies to year 0 and BCE.pub fn days_in_month(year: int, month: int) -> int - Returns 28-31 for a valid month number (1-12), or 0 for an invalid month. Accounts for leap years; no month names are stored or returned.pub fn utc_from_unix(seconds: int) -> DateTime - Converts signed Unix seconds to numeric UTC fields without reading the clock. Accepts the full int range, including timestamps before 1970. Uses Gregorian rules for all years and 86400-second days (no leap seconds). Does not apply local timezone or daylight-saving rules. For a known fixed UTC offset, add its seconds before conversion, keeping the sum in int range. Define your own labels in Pie. Subtract 1 when indexing a zero-based array:import pie::std::time::*
fn main() -> int ![IO]:
months: string[12] -> ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
weekdays: string[7] -> ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
date: DateTime -> utc_from_unix(1709164800)
println(date.year) // 2024
println(months[date.month - 1]) // Feb (your label)
println(date.day) // 29
println(weekdays[date.weekday - 1]) // Thu (your label)
return 0
end
pub fn utc_now() -> DateTime ![IO] - Reads the wall clock once and returns its numeric UTC calendar fields. Equivalent to utc_from_unix(unix_now()); requires IO.import pie::std::time::*
fn main() -> int ![IO]:
date: DateTime -> utc_now()
println(date.year)
println(date.month) // 1-12; supply names in your own Pie code
println(date.day)
return 0
end
pub fn time_sleep_nanos(nanos: int) -> void ![IO] (@intrinsic("pie.time_sleep")) - Suspends the calling thread for the given number of nanoseconds.pub struct Instant - A monotonic timestamp measured in nanoseconds.pub struct Duration - A duration measured in nanoseconds.pub fn now() -> Instant ![IO] - Returns the current monotonic instant.pub fn duration_from_nanos(n: int) -> Duration - Creates a Duration from nanoseconds.pub fn duration_from_micros(m: int) -> Duration - Creates a Duration from microseconds.pub fn duration_from_millis(m: int) -> Duration - Creates a Duration from milliseconds.pub fn duration_from_secs(s: int) -> Duration - Creates a Duration from seconds.pub fn sub(self, other: Instant) -> Duration - Returns the duration between self and other.pub fn elapsed(self) -> Duration - Returns the duration elapsed since this instant.pub fn as_nanos(self) -> int - Returns the duration as nanoseconds.pub fn as_micros(self) -> int - Returns the duration as microseconds (truncated).pub fn as_millis(self) -> int - Returns the duration as milliseconds (truncated).pub fn as_secs(self) -> int - Returns the duration as seconds (truncated).pub fn add(self, other: Duration) -> Duration - Returns the sum of two durations.pub fn sub(self, other: Duration) -> Duration - Returns the difference of two durations.pub fn sleep(d: Duration) -> void ![IO] - Suspends the calling thread for the given duration.Unicode grapheme cluster segmentation and case mapping.
pub fn grapheme_count(s: string) -> int (@intrinsic("pie.unicode_grapheme_count")) - Returns the number of Unicode grapheme clusters in a UTF-8 string.pub fn graphemes(s: string) -> List[string] (@intrinsic("pie.unicode_graphemes")) - Splits a string into individual grapheme clusters.pub fn decode_codepoint(s: string, offset: int, next_off: ptr) -> int (@intrinsic("pie.unicode_decode")) - Decodes the code point at a byte offset. Writes next offset to next_off. Returns U+FFFD on malformed input.pub fn to_uppercase(s: string) -> string (@intrinsic("pie.unicode_uppercase")) - Converts a UTF-8 string to uppercase using Unicode case mapping.pub fn to_lowercase(s: string) -> string (@intrinsic("pie.unicode_lowercase")) - Converts a UTF-8 string to lowercase using Unicode case mapping.