Standard Library
Import stdlib modules from stdlib/:
import { Console }, * as stdio from "stdlib/stdio.nx"
I/O Ports
I/O is capability-gated via ports. Each port has a system_handler that declares require { PermX }, propagating the permission to the caller when injected. Mock handlers without require need no runtime permissions.
Console (stdio.nx)
Requires PermConsole. CLI flag: --allow-console.
port Console do
fn print(val: string) -> unit
fn println(val: string) -> unit
fn eprint(val: string) -> unit
fn eprintln(val: string) -> unit
fn read_line() -> string
fn getchar() -> string
end
let main = fn () -> unit require { PermConsole } do
inject stdio.system_handler do
Console.println(val: "Hello")
end
return ()
end
File System (fs.nx)
Requires PermFs. CLI flag: --allow-fs.
Types:
type Handle = Handle(id: i64) // linear file handle
Direct-call API (no inject required):
fn exists(path: string) -> bool require { PermFs }
fn is_file(path: string) -> bool require { PermFs }
fn read_to_string(path: string) -> string require { PermFs } throws { Exn }
fn write_string(path: string, content: string) -> unit require { PermFs } throws { Exn }
fn append_string(path: string, content: string) -> unit require { PermFs } throws { Exn }
fn remove_file(path: string) -> unit require { PermFs } throws { Exn }
fn create_dir_all(path: string) -> unit require { PermFs } throws { Exn }
fn list_dir(path: string) -> [ string ] require { PermFs } throws { Exn }
fn open_read(path: string) -> %Handle require { PermFs } throws { Exn }
fn open_write(path: string) -> %Handle require { PermFs } throws { Exn }
fn open_append(path: string) -> %Handle require { PermFs } throws { Exn }
fn read(handle: %Handle) -> { content: string, handle: %Handle } require { PermFs }
fn write(handle: %Handle, content: string) -> { ok: bool, handle: %Handle } require { PermFs }
fn handle_path(handle: %Handle) -> { path: string, handle: %Handle } require { PermFs }
fn close(handle: %Handle) -> unit require { PermFs }
Port methods (for DI / testing):
port Fs do
// Query
fn exists(path: string) -> bool
fn read_to_string(path: string) -> string throws { Exn }
// Mutating (raise on failure)
fn write_string(path: string, content: string) -> unit throws { Exn }
fn append_string(path: string, content: string) -> unit throws { Exn }
fn remove_file(path: string) -> unit throws { Exn }
fn create_dir_all(path: string) -> unit throws { Exn }
fn read_dir(path: string) -> %[ Handle ] throws { Exn }
// File descriptor operations (consume-and-return pattern)
fn open_read(path: string) -> %Handle throws { Exn }
fn open_write(path: string) -> %Handle throws { Exn }
fn open_append(path: string) -> %Handle throws { Exn }
fn read(handle: %Handle) -> { content: string, handle: %Handle }
fn write(handle: %Handle, content: string) -> { ok: bool, handle: %Handle }
fn handle_path(handle: %Handle) -> { path: string, handle: %Handle }
fn close(handle: %Handle) -> unit
end
The fd operations use a consume-and-return pattern: the linear handle is consumed and a fresh handle is returned in the result record, enabling stateless handlers.
let %h = Fs.open_read(path: "data.txt")
let %r = Fs.read(handle: %h)
match %r do
case { content: c, handle: %h2 } ->
Fs.close(handle: %h2)
end
Network (net.nx)
Requires PermNet. CLI flag: --allow-net.
Types:
type Header = Header(name: string, value: string)
type Response = Response(status: i64, headers: string, body: string)
opaque type Server = Server(id: i64) // linear server handle
type Request = Request(method: string, path: string, headers: string, body: string, req_id: i64)
Direct-call API (no inject required):
// HTTP client (all raise on failure)
// HTTP server
fn get(url: string) -> string require { PermNet } throws { Exn }
fn post(url: string, body: string) -> string require { PermNet } throws { Exn }
fn request_raw(method: string, url: string, headers: string, body: string) -> Response require { PermNet } throws { Exn }
fn request(method: string, url: string, headers: [ Header ], body: string) -> Response require { PermNet } throws { Exn }
fn listen(addr: string) -> %Server require { PermNet } throws { Exn }
fn accept(server: &Server) -> Request require { PermNet }
fn respond(req: Request, status: i64, body: string) -> unit require { PermNet } throws { Exn }
fn respond_with_headers(req: Request, status: i64, headers: [ Header ], body: string) -> unit require { PermNet } throws { Exn }
fn stop(server: %Server) -> unit require { PermNet }
Port methods (for DI / testing):
port Net do
// HTTP client (all raise on failure)
fn get(url: string) -> string throws { Exn }
fn request(method: string, url: string, headers: [ Header ], body: string) -> Response throws { Exn }
// HTTP server
fn listen(addr: string) -> %Server throws { Exn }
fn accept(server: &Server) -> Request
fn respond(req: Request, status: i64, body: string) -> unit throws { Exn }
fn respond_with_headers(req: Request, status: i64, headers: [ Header ], body: string) -> unit throws { Exn }
fn stop(server: %Server) -> unit
end
Helper functions:
fn header(name: string, value: string) -> Header
fn response_status(res: Response) -> i64
fn response_headers(res: Response) -> string
fn response_body(res: Response) -> string
fn request_method(req: &Request) -> string
fn request_path(req: &Request) -> string
fn request_body(req: &Request) -> string
Random (random.nx)
Requires PermRandom. CLI flag: --allow-random.
port Random do
fn next_i64() -> i64
fn range(min: i64, max: i64) -> i64
fn next_bool() -> bool
end
Clock (clock.nx)
Requires PermClock. CLI flag: --allow-clock.
port Clock do
fn sleep(ms: i64) -> unit
fn now() -> i64
end
Process (proc.nx)
Requires PermProc. CLI flag: --allow-proc.
Types:
type ExecResult = ExecResult(exit_code: i64, stdout: string, stderr: string)
Direct-call API:
fn argv() -> [ string ] require { PermProc }
Port methods:
port Proc do
fn exit(status: i64) -> unit
fn argv() -> [ string ]
fn exec(cmd: string, args: [ string ]) -> ExecResult
end
Environment (env.nx)
Requires PermEnv. CLI flag: --allow-env.
port Env do
fn get(key: string) -> Option<string>
fn set(key: string, value: string) -> unit
end
Env.get returns None when the variable is not set, avoiding exceptions for simple absence.
Data Structures
Option (option.nx)
type Option<T> = Some(val: T) | None
fn is_some<T>(opt: Option<T>) -> bool
fn is_none<T>(opt: Option<T>) -> bool
fn unwrap_or<T>(opt: Option<T>, default: T) -> T
fn map<T, U>(opt: Option<T>, f: (val: T) -> U) -> Option<U>
fn and_then<T, U>(opt: Option<T>, f: (val: T) -> Option<U>) -> Option<U>
fn or_else<T>(opt: Option<T>, other: Option<T>) -> Option<T>
fn unwrap<T>(opt: Option<T>) -> T throws { Exn }
fn expect<T>(opt: Option<T>, msg: string) -> T throws { Exn }
List (list.nx)
Immutable singly-linked list: type List<T> = Nil | Cons(v: T, rest: List<T>).
[ T ] is an alias for List<T> with literal syntax sugar.
type Partition<T> = Partition(matched: [ T ], rest: [ T ])
fn empty<T>() -> [ T ]
fn cons<T>(x: T, xs: [ T ]) -> [ T ]
fn is_empty<T>(xs: [ T ]) -> bool
fn length<T>(xs: [ T ]) -> i64
fn head<T>(xs: [ T ]) -> T
fn tail<T>(xs: [ T ]) -> [ T ]
fn last<T>(xs: [ T ]) -> T
fn reverse<T>(xs: [ T ]) -> [ T ]
fn concat<T>(xs: [ T ], ys: [ T ]) -> [ T ]
fn take<T>(xs: [ T ], n: i64) -> [ T ]
fn drop_n<T>(xs: [ T ], n: i64) -> [ T ]
fn nth<T>(xs: [ T ], n: i64) -> T
fn contains(xs: [ i64 ], val: i64) -> bool
fn fold_left<T, U>(xs: [ T ], init: U, f: (acc: U, val: T) -> U) -> U
fn map<T, U>(xs: [ T ], f: (val: T) -> U) -> [ U ]
fn map_rev<T, U>(xs: [ T ], f: (val: T) -> U) -> [ U ]
Tuple (tuple.nx)
type Pair<A, B> = Pair(left: A, right: B)
fn fst<A, B>(p: Pair<A, B>) -> A
fn snd<A, B>(p: Pair<A, B>) -> B
Array (array.nx)
Linear mutable array: [| T |]
fn length<T>(arr: &[| T |]) -> i64
fn is_empty<T>(arr: &[| T |]) -> bool
fn get<T>(arr: &[| T |], idx: i64) -> T
fn set<T>(arr: &[| T |], idx: i64, val: T) -> unit
fn head<T>(arr: &[| T |]) -> T
fn last<T>(arr: &[| T |]) -> T
fn fold_left<T, U>(arr: &[| T |], init: U, f: (acc: U, val: T) -> U) -> U
fn any<T>(arr: &[| T |], pred: (val: T) -> bool) -> bool
fn all<T>(arr: &[| T |], pred: (val: T) -> bool) -> bool
fn find_index<T>(arr: &[| T |], pred: (val: T) -> bool) -> i64
fn for_each<T>(arr: &[| T |], f: (val: T) -> unit) -> unit
fn map_in_place<T>(arr: &[| T |], f: (val: T) -> T) -> unit
fn filter<T>(arr: &[| T |], pred: (val: T) -> bool) -> [ T ]
fn partition<T>(arr: &[| T |], pred: (val: T) -> bool) -> Partition<T>
fn zip_with<A, B, C>(left: &[| A |], right: &[| B |], f: (left: A, right: B) -> C) -> [ C ]
fn zip<A, B>(left: &[| A |], right: &[| B |]) -> [ Pair<A, B> ]
fn consume<T>(%arr: [| T |], f: (val: %T) -> unit) -> unit
Set (set.nx)
FFI-backed hash set of i64 values. Uses opaque linear handles backed by Rust HashSet<i64>.
opaque type Set = Set(id: i64) // linear -- must be freed
fn empty() -> %Set
fn insert(set: %Set, val: i64) -> %Set
fn contains(set: &Set, val: i64) -> bool
fn remove(set: %Set, val: i64) -> %Set
fn size(set: &Set) -> i64
fn from_list(xs: [ i64 ]) -> %Set
fn to_list(set: &Set) -> [ i64 ]
fn union(left: &Set, right: &Set) -> %Set
fn intersection(left: &Set, right: &Set) -> %Set
fn difference(left: &Set, right: &Set) -> %Set
fn free(set: %Set) -> unit
HashMap (hashmap.nx)
FFI-backed hash map from i64 keys to i64 values. Uses opaque linear handles backed by Rust HashMap<i64, i64>.
opaque type HashMap = HashMap(id: i64) // linear -- must be freed
type Lookup = Found(value: i64) | Missing
fn empty() -> %HashMap
fn put(map: %HashMap, key: i64, value: i64) -> %HashMap
fn get(map: &HashMap, key: i64) -> Lookup
fn get_or(map: &HashMap, key: i64, default: i64) -> i64
fn contains_key(map: &HashMap, key: i64) -> bool
fn remove(map: %HashMap, key: i64) -> %HashMap
fn size(map: &HashMap) -> i64
fn keys(map: &HashMap) -> [ i64 ]
fn values(map: &HashMap) -> [ i64 ]
fn free(map: %HashMap) -> unit
StringMap (stringmap.nx)
FFI-backed hash map from string keys to i64 values. Uses opaque linear handles backed by Rust HashMap<String, i64>.
opaque type StringMap = StringMap(id: i64) // linear -- must be freed
type Lookup = Found(value: i64) | Missing
fn empty() -> %StringMap
fn put(map: %StringMap, key: string, value: i64) -> %StringMap
fn get(map: &StringMap, key: string) -> Lookup
fn get_or(map: &StringMap, key: string, default: i64) -> i64
fn contains_key(map: &StringMap, key: string) -> bool
fn remove(map: %StringMap, key: string) -> %StringMap
fn size(map: &StringMap) -> i64
fn keys(map: &StringMap) -> [ string ]
fn values(map: &StringMap) -> [ i64 ]
fn free(map: %StringMap) -> unit
ByteBuffer (bytebuffer.nx)
FFI-backed mutable byte buffer for binary data construction. Uses opaque linear handles backed by Rust Vec<u8>. Provides LEB128 encoding, little-endian integer writes, and raw byte/string/buffer append operations.
opaque type ByteBuffer = ByteBuffer(id: i64) // linear -- must be freed
fn empty() -> %ByteBuffer
fn push_byte(buf: %ByteBuffer, byte: i64) -> %ByteBuffer
fn push_i32_le(buf: %ByteBuffer, val: i64) -> %ByteBuffer
fn push_i64_le(buf: %ByteBuffer, val: i64) -> %ByteBuffer
fn push_uleb128(buf: %ByteBuffer, val: i64) -> %ByteBuffer
fn push_sleb128(buf: %ByteBuffer, val: i64) -> %ByteBuffer
fn push_string(buf: %ByteBuffer, s: string) -> %ByteBuffer
fn push_buf(dst: %ByteBuffer, src: &ByteBuffer) -> %ByteBuffer
fn length(buf: &ByteBuffer) -> i64
fn get_byte(buf: &ByteBuffer, idx: i64) -> i64
fn to_string(buf: &ByteBuffer) -> string
fn write_file(buf: &ByteBuffer, path: string) -> bool require { PermFs }
fn free(buf: %ByteBuffer) -> unit
All mutating operations consume the buffer and return a new handle (consume-and-return pattern).
Utilities
String (string.nx)
// Inspection
// Transformation
// Conversion
fn length(s: string) -> i64
fn contains(s: string, sub: string) -> bool
fn index_of(s: string, sub: string) -> i64
fn starts_with(s: string, prefix: string) -> bool
fn ends_with(s: string, suffix: string) -> bool
fn char_at(s: string, idx: i64) -> char
fn char_code(s: string, idx: i64) -> i64 // Unicode codepoint, -1 if OOB
fn substring(s: string, start: i64, len: i64) -> string
fn trim(s: string) -> string
fn to_upper(s: string) -> string
fn to_lower(s: string) -> string
fn replace(s: string, from_str: string, to_str: string) -> string
fn concat(a: string, b: string) -> string
fn repeat(s: string, n: i64) -> string
fn pad_left(s: string, width: i64, fill: string) -> string
fn pad_right(s: string, width: i64, fill: string) -> string
fn join(xs: [ string ], sep: string) -> string
fn split(s: string, sep: string) -> [ string ]
fn from_i64(val: i64) -> string
fn from_float(val: float) -> string
fn from_bool(val: bool) -> string
fn from_char(c: char) -> string
fn from_char_code(code: i64) -> string // Unicode codepoint → string
fn parse_i64(s: string) -> Option<i64>
fn parse_f64(s: string) -> Option<f64>
fn to_f64(s: string) -> f64 throws { Exn }
Math (math.nx)
fn abs(val: i64) -> i64
fn max(a: i64, b: i64) -> i64
fn min(a: i64, b: i64) -> i64
fn mod_i64(a: i64, b: i64) -> i64
fn abs_float(val: float) -> float
fn sqrt(val: float) -> float
fn floor(val: float) -> float
fn ceil(val: float) -> float
fn pow(base: float, exp: float) -> float
fn i64_to_float(val: i64) -> float
fn float_to_i64(val: float) -> i64
fn negate(val: bool) -> bool
Result (result.nx)
type Result<T, E> = Ok(val: T) | Err(err: E)
fn is_ok<T, E>(res: Result<T, E>) -> bool
fn is_err<T, E>(res: Result<T, E>) -> bool
fn unwrap_or<T, E>(res: Result<T, E>, default: T) -> T
fn map<T, U, E>(res: Result<T, E>, f: (val: T) -> U) -> Result<U, E>
fn map_err<T, E, F>(res: Result<T, E>, f: (val: E) -> F) -> Result<T, F>
fn and_then<T, U, E>(res: Result<T, E>, f: (val: T) -> Result<U, E>) -> Result<U, E>
fn from_exn<T>(exn: Exn) -> Result<T, Exn>
fn to_exn<T>(res: Result<T, Exn>) -> T throws { Exn }
Exception Utilities (exn.nx)
fn to_string(exn: Exn) -> string
fn backtrace(exn: Exn) -> [string]
backtrace returns call-stack frames (with source file and line info) captured at the raise point.
Char (char.nx)
Character classification functions for ASCII analysis:
fn ord(c: char) -> i64
fn is_upper(c: char) -> bool
fn is_lower(c: char) -> bool
fn is_alpha(c: char) -> bool
fn is_digit(c: char) -> bool
fn is_alnum(c: char) -> bool
fn is_hex_digit(c: char) -> bool
fn is_whitespace(c: char) -> bool
fn is_ident_start(c: char) -> bool
fn is_ident_char(c: char) -> bool
fn is_newline(c: char) -> bool
fn digit_value(c: char) -> i64
fn hex_digit_value(c: char) -> i64
Core (core.nx)
Legacy re-exports for backwards compatibility. Prefer tuple.nx, list.nx, math.nx for new code.
type Pair<A, B> = Pair(left: A, right: B)
type Partition<T> = Partition(matched: [ T ], rest: [ T ])
fn fst<A, B>(p: Pair<A, B>) -> A
fn snd<A, B>(p: Pair<A, B>) -> B
fn negate(val: bool) -> bool
fn id<T>(val: T) -> T