Language Guide (x07AST JSON)
IMPORTANT:
- Output ONLY one JSON object (no preamble).
- Do NOT wrap the JSON in Markdown code fences.
- Do NOT output extra prose.
- Must satisfy x07AST schema_version
x07.x07ast@0.1.0.
Program encoding: UTF-8 JSON text.
Entry program object fields:
schema_version:x07.x07ast@0.1.0kind:entrymodule_id:mainimports: array of module IDs (e.g.std.bytes)decls: array of decl objectssolve: expression (must evaluate to bytes)
Expression Encoding (json-sexpr)
- i32: JSON numbers in range -2147483648..2147483647
- atom: JSON strings with no whitespace
- list: JSON arrays:
["head", arg1, arg2, ...](head is an atom string; list must be non-empty)
Types
i32for integers and conditions (0=false, non-zero=true)bytesfor owned byte arrays (move-only; outputs and owned buffers)bytes_viewfor borrowed byte views (zero-copy scanning/slicing)vec_u8for mutable byte vectors (move-only; capacity-planned builders)option_i32,option_bytesfor typed optional valuesresult_i32,result_bytesfor typed results with deterministic error codesifacefor interface records (used for streaming readers)- Raw pointer types (standalone-only; require unsafe capability):
ptr_const_u8,ptr_mut_u8,ptr_const_void,ptr_mut_void,ptr_const_i32,ptr_mut_i32
Move rules (critical):
- Passing
bytes/vec_u8to a function that expectsbytes/vec_u8moves (consumes) the value. result_i32/result_bytesvalues are also move-only; consume them once (use*_err_code,*_unwrap_or, ortry).- Mutating APIs return the updated value; always bind it with
let/set(example:["set","b",["bytes.set_u8","b",0,65]]).
Builtins
inputis the input byte view (bytes_view); refer to it as the atom stringinputin expressions.iface.make_v1(data: i32, vtable: i32) -> ifaceconstructs an interface record value.
Core Forms
begin:["begin", e1, e2, ...]evaluates sequentially and returns the last expressionunsafe:["unsafe", e1, e2, ...]evaluates sequentially and returns the last expression; inside it, unsafe-only operations are allowed (standalone-only)let:["let", name, expr]bindsnamein the current scopeset:["set", name, expr]assigns an existing bindingif:["if", cond, then, else]branches on non-zerocondfor:["for", i, start, end, body]declaresi(i32) and runs it fromstarttoend-1bodyis a single expression; usebeginfor multiple steps.
return:["return", expr]returns early from the current function- In
solve, the return value must bebytes.
- In
Examples
Echo (returns input):
{"schema_version":"x07.x07ast@0.1.0","kind":"entry","module_id":"main","imports":[],"decls":[],"solve":["view.to_bytes","input"]}
Arity reminder:
ifis["if", cond, then, else]foris["for", i, start, end, body]beginis["begin", e1, e2, ...]
Modules
Top-level fields:
imports: array of module IDsdecls: array of declarations (objects)solve: expression (entry programs only)
Declaration objects:
{"kind":"defn","name":"main.f","params":[{"name":"x","ty":"bytes"}],"result":"bytes","body":<expr>}{"kind":"defasync",...}(returns awaited type; calling returns a task handle i32){"kind":"extern","abi":"C","name":"main.c_fn","link_name":"c_fn","params":[{"name":"x","ty":"i32"}],"result":"i32"}(standalone-only;resultmay also be"void"){"kind":"export","names":["std.foo.bar", ...]}(module files only)
Module IDs are dot-separated identifiers like app.rle or std.bytes.
Module resolution is deterministic:
- Built-in modules:
std.vec,std.slice,std.bytes,std.codec,std.parse,std.fmt,std.prng,std.bit,std.text.ascii,std.text.utf8,std.test,std.regex-lite,std.json,std.csv,std.map,std.set,std.u32,std.small_map,std.small_set,std.hash,std.hash_map,std.hash_set,std.btree_map,std.btree_set,std.deque_u32,std.heap_u32,std.bitset,std.slab,std.lru_cache,std.result,std.option,std.io,std.io.bufread,std.fs,std.world.fs,std.rr,std.kv,std.path - Filesystem modules (standalone):
x07c compile --module-root <dir>resolvesa.bto<dir>/a/b.x07.json
Standalone binding override:
- In standalone-only worlds (
run-os,run-os-sandboxed),std.world.*modules are resolved from--module-rootonly (no built-in fallback). - This keeps program source stable (
import std.fs) while the target world selects the adapter implementation.
Standalone OS builtins:
- These heads are only available when compiling with
--world run-osor--world run-os-sandboxed:os.fs.read_file(path: bytes) -> bytesos.fs.write_file(path: bytes, data: bytes) -> i32os.fs.read_all_v1(path: bytes, caps: bytes) -> result_bytesos.fs.write_all_v1(path: bytes, data: bytes, caps: bytes) -> result_i32os.fs.mkdirs_v1(path: bytes, caps: bytes) -> result_i32os.fs.remove_file_v1(path: bytes, caps: bytes) -> result_i32os.fs.remove_dir_all_v1(path: bytes, caps: bytes) -> result_i32os.fs.rename_v1(src: bytes, dst: bytes, caps: bytes) -> result_i32os.fs.list_dir_sorted_text_v1(path: bytes, caps: bytes) -> result_bytesos.fs.walk_glob_sorted_text_v1(root: bytes, glob: bytes, caps: bytes) -> result_bytesos.fs.stat_v1(path: bytes, caps: bytes) -> result_bytesos.env.get(key: bytes) -> bytesos.time.now_unix_ms() -> i32os.time.now_instant_v1() -> bytesos.time.sleep_ms_v1(ms: i32) -> i32os.time.local_tzid_v1() -> bytesos.process.exit(code: i32) -> neveros.process.spawn_capture_v1(req: bytes, caps: bytes) -> i32os.process.spawn_piped_v1(req: bytes, caps: bytes) -> i32os.process.try_join_capture_v1(handle: i32) -> option_bytesos.process.join_capture_v1(handle: i32) -> bytes(yield boundary)os.process.stdout_read_v1(handle: i32, max: i32) -> bytesos.process.stderr_read_v1(handle: i32, max: i32) -> bytesos.process.stdin_write_v1(handle: i32, chunk: bytes) -> i32os.process.stdin_close_v1(handle: i32) -> i32os.process.try_wait_v1(handle: i32) -> i32os.process.join_exit_v1(handle: i32) -> i32(yield boundary)os.process.take_exit_v1(handle: i32) -> i32os.process.kill_v1(handle: i32, sig: i32) -> i32os.process.drop_v1(handle: i32) -> i32os.process.run_capture_v1(req: bytes, caps: bytes) -> bytes- Note:
req/capsarebytes(move-only). To reuse, copy viastd.bytes.copy(req)/std.bytes.copy(caps).
- Note:
os.net.http_request(req: bytes) -> bytes(currently traps; reserved for later)
Standalone unsafe + FFI:
- Only available in
run-os/run-os-sandboxed. - Unsafe block:
["unsafe", ...]. - Pointer creation/casts:
bytes.as_ptr,bytes.as_mut_ptr,view.as_ptr,vec_u8.as_ptr,vec_u8.as_mut_ptr,ptr.null,ptr.as_const,ptr.cast,addr_of,addr_of_mut. - Unsafe-only ops (require
unsafeblock):ptr.add,ptr.sub,ptr.offset,ptr.read_u8,ptr.write_u8,ptr.read_i32,ptr.write_i32,memcpy,memmove,memset. externfunction calls requireunsafeblocks.
Functions
- Define with a
decls[]entry of kinddefn.bodyis a single expression; wrap multi-step bodies inbegin.tyandret_tyarei32,bytes,bytes_view,vec_u8,option_i32,option_bytes,result_i32,result_bytes,iface,ptr_const_u8,ptr_mut_u8,ptr_const_void,ptr_mut_void,ptr_const_i32, orptr_mut_i32.- Function names must be namespaced and start with the current module ID.
- In the entry file, use module
main(example:main.helper).
- In the entry file, use module
input(bytes_view) is available in all function bodies.
- Call:
["name", arg1, arg2, ...]
Concurrency
Async functions are defined with defasync.
Calling an async function returns an opaque i32 task handle.
To get concurrency, create multiple tasks before waiting on them (and avoid blocking operations outside tasks).
- Define with a
decls[]entry of kinddefasync.bodyis a single expression; wrap multi-step bodies inbegin.bytesis the awaited return type (currently onlybytesis supported).
- Call:
["name", arg1, arg2, ...]->i32(task handle) ["await", task_handle]->bytes(alias oftask.join.bytes)["task.spawn", task_handle]->i32["task.is_finished", task_handle]->i32(0/1)["task.try_join.bytes", task_handle]->result_bytes(err=1 not finished; err=2 canceled)["task.join.bytes", task_handle]->bytes["task.yield"]->i32["task.sleep", ticks_i32]->i32(virtual time ticks)["task.cancel", task_handle]->i32
Channels (bytes payloads):
["chan.bytes.new", cap_i32]->i32["chan.bytes.try_send", chan_handle, bytes_view]->i32(0 full; 1 sent; 2 closed)["chan.bytes.send", chan_handle, bytes]->i32["chan.bytes.try_recv", chan_handle]->result_bytes(err=1 empty; err=2 closed)["chan.bytes.recv", chan_handle]->bytes["chan.bytes.close", chan_handle]->i32
Built-in Modules (stdlib)
Call module functions using fully-qualified names (e.g. ["std.bytes.reverse","b"]).
-
std.bytes["std.bytes.len","b"]-> i32["std.bytes.get_u8","b","i"]-> i32 (0..255)["std.bytes.set_u8","b","i","v"]-> bytes (returnsb)["std.bytes.alloc","n"]-> bytes (lengthn)["std.bytes.eq","a","b"]-> i32 (1 if equal else 0)["std.bytes.find_u8","b","target"]-> i32 (index, or -1)["std.bytes.cmp_range","a","a_off","a_len","b","b_off","b_len"]-> i32 (-1/0/1)["std.bytes.max_u8","v"]-> i32 (vis bytes_view; returns 0 if empty)["std.bytes.sum_u8","v"]-> i32 (vis bytes_view; wraps mod 2^32)["std.bytes.count_u8","v","target"]-> i32 (vis bytes_view)["std.bytes.starts_with","a","prefix"]-> i32 (both bytes_view)["std.bytes.ends_with","a","suffix"]-> i32 (both bytes_view)["std.bytes.reverse","b"]-> bytes["std.bytes.concat","a","b"]-> bytes["std.bytes.take","b","n"]-> bytes["std.bytes.drop","b","n"]-> bytes["std.bytes.copy","b"]-> bytes["std.bytes.slice","b","start","len"]-> bytes (copy; clamps within bounds)
-
std.codec["std.codec.read_u32_le","b","off"]-> i32 (bis bytes_view)["std.codec.write_u32_le","x"]-> bytes
-
std.vec["std.vec.with_capacity","cap"]-> vec_u8["std.vec.len","v"]-> i32["std.vec.get","v","i"]-> i32 (0..255)["std.vec.push","v","x"]-> vec_u8["std.vec.reserve_exact","v","additional"]-> vec_u8["std.vec.extend_bytes","v","b"]-> vec_u8["std.vec.as_bytes","v"]-> bytes
-
std.slice["std.slice.clamp","b","start","len"]-> bytes["std.slice.cmp_bytes","a","b"]-> i32 (-1/0/1)
-
std.parse["std.parse.u32_dec","b"]-> i32["std.parse.u32_dec_at","b","off"]-> i32["std.parse.i32_status_le","b"]-> bytes (tag byte 1 + i32_le, or tag byte 0)["std.parse.i32_status_le_at","b","off"]-> bytes (tag byte 1 + i32_le + next_off_u32_le, or tag byte 0)
-
std.fmt["std.fmt.u32_to_dec","x"]-> bytes["std.fmt.s32_to_dec","x"]-> bytes
-
std.prng["std.prng.lcg_next_u32","state"]-> i32["std.prng.x07rand32_v1_stream","b"]-> bytes
-
std.bit["std.bit.popcount_u32","x"]-> i32
-
std.text.ascii["std.text.ascii.normalize_lines","b"]-> bytes["std.text.ascii.tokenize_words_lower","b"]-> bytes["std.text.ascii.split_u8","b","sep_u8"]-> bytes (X7SL v1 slice list)["std.text.ascii.split_lines_view","b"]-> bytes (X7SL v1 slice list; splits on\n, strips trailing\r, omits trailing empty line after final\n)
-
std.text.slices["std.text.slices.builder_new_v1","cap_hint"]-> vec_u8["std.text.slices.builder_push_v1","out","start","len"]-> vec_u8["std.text.slices.builder_finish_v1","out","count"]-> bytes (X7SL v1)["std.text.slices.validate_v1","x7sl"]-> result_i32 (OK(count) or ERR(code); seedocs/text/x7sl-v1.md)["std.text.slices.count_v1","x7sl"]-> i32 (count or -1)["std.text.slices.start_v1","x7sl","idx"]-> i32["std.text.slices.len_v1","x7sl","idx"]-> i32["std.text.slices.view_at_v1","base_view","x7sl","idx"]-> bytes_view["std.text.slices.copy_at_v1","base_view","x7sl","idx"]-> bytes
-
std.text.utf8["std.text.utf8.validate_or_empty","b"]-> bytes
-
std.regex-lite["std.regex-lite.find_literal","hay","needle"]-> i32 (index, or -1)["std.regex-lite.is_match_literal","hay","needle"]-> i32 (0/1)["std.regex-lite.count_matches_u32le","b"]-> bytes
-
std.json["std.json.canonicalize_small","json_bytes"]-> bytes (orERR)["std.json.extract_path_canon_or_err","b"]-> bytes
-
std.csv["std.csv.sum_second_col_i32_status_le","csv_bytes"]-> bytes (tag byte 1 + i32_le, or tag byte 0)["std.csv.sum_second_col_i32le_or_err","csv_bytes"]-> bytes (i32_le, orERR)
-
std.map["std.map.word_freq_sorted_ascii","b"]-> bytes
-
std.set["std.set.unique_lines_sorted","b"]-> bytes
-
std.u32["std.u32.read_le_at","b","off"]-> i32["std.u32.write_le_at","b","off","x"]-> bytes["std.u32.push_le","v","x"]-> vec_u8["std.u32.pow2_ceil","x"]-> i32
-
std.small_map["std.small_map.empty_bytes_u32"]-> bytes["std.small_map.len_bytes_u32","m"]-> i32["std.small_map.get_bytes_u32","m","key"]-> i32 (0 if missing)["std.small_map.put_bytes_u32","m","key","val"]-> bytes["std.small_map.remove_bytes_u32","m","key"]-> bytes
-
std.small_set["std.small_set.empty_bytes"]-> bytes["std.small_set.len_bytes","s"]-> i32["std.small_set.contains_bytes","s","key"]-> i32["std.small_set.insert_bytes","s","key"]-> bytes
-
std.hash["std.hash.fnv1a32_bytes","b"]-> i32["std.hash.fnv1a32_range","b","start","len"]-> i32["std.hash.fnv1a32_view","v"]-> i32["std.hash.mix32","x"]-> i32
-
std.hash_map(u32 keys/values)["std.hash_map.with_capacity_u32","expected_len"]-> i32["std.hash_map.len_u32","m"]-> i32["std.hash_map.contains_u32","m","key"]-> i32["std.hash_map.get_u32_or","m","key","default"]-> i32["std.hash_map.set_u32","m","key","val"]-> i32
-
std.hash_set- u32 set:
["std.hash_set.new_u32","cap_pow2"]-> i32,["std.hash_set.add_u32","s","key"]-> i32 - view-key set:
["std.hash_set.view_new","expected_len"]-> vec_u8,["std.hash_set.view_insert","set","base","start","len"]-> vec_u8
- u32 set:
-
std.btree_map(ordered u32->u32)["std.btree_map.empty_u32_u32"]-> bytes["std.btree_map.len_u32_u32","m"]-> i32["std.btree_map.get_u32_u32_or","m","key","default"]-> i32["std.btree_map.put_u32_u32","m","key","val"]-> bytes
-
std.btree_set(ordered u32)["std.btree_set.empty_u32"]-> bytes["std.btree_set.len_u32","s"]-> i32["std.btree_set.contains_u32","s","key"]-> i32["std.btree_set.insert_u32","s","key"]-> bytes
-
std.deque_u32["std.deque_u32.with_capacity","cap"]-> bytes["std.deque_u32.len","dq"]-> i32["std.deque_u32.push_back","dq","x"]-> bytes["std.deque_u32.front_or","dq","default"]-> i32["std.deque_u32.pop_front","dq"]-> bytes["std.deque_u32.emit_u32le","dq"]-> bytes
-
std.heap_u32["std.heap_u32.with_capacity","cap"]-> bytes["std.heap_u32.len","h"]-> i32["std.heap_u32.push","h","x"]-> bytes["std.heap_u32.min_or","h","default"]-> i32["std.heap_u32.pop_min","h"]-> bytes["std.heap_u32.emit_u32le","h"]-> bytes
-
std.bitset["std.bitset.new","bit_len"]-> bytes["std.bitset.set","bs","bit"]-> bytes["std.bitset.test","bs","bit"]-> i32["std.bitset.intersection_count","a","b"]-> i32
-
std.slab(u32 values)["std.slab.new_u32","cap"]-> bytes["std.slab.free_head_u32","slab"]-> i32 (-1 if none)["std.slab.alloc_u32","slab"]-> bytes["std.slab.free_u32","slab","handle"]-> bytes["std.slab.get_u32","slab","handle","default"]-> i32["std.slab.set_u32","slab","handle","val"]-> bytes
-
std.lru_cache(u32 keys/values)["std.lru_cache.new_u32","cap"]-> bytes["std.lru_cache.len_u32","cache"]-> i32["std.lru_cache.peek_u32_opt","cache","key"]-> option_i32["std.lru_cache.peek_u32_or","cache","key","default"]-> i32["std.lru_cache.touch_u32","cache","key"]-> bytes["std.lru_cache.put_u32","cache","key","val"]-> bytes
-
std.test["std.test.pass"]-> result_i32["std.test.fail","code"]-> result_i32["std.test.assert_true","cond","code"]-> result_i32["std.test.assert_i32_eq","a","b","code"]-> result_i32["std.test.assert_bytes_eq","a","b","code"]-> result_i32["std.test.code_assert_true"]-> i32["std.test.code_assert_i32_eq"]-> i32["std.test.code_assert_bytes_eq"]-> i32["std.test.status_from_result_i32","r"]-> bytes (5-byte X7TEST_STATUS_V1)
-
std.result["std.result.ok_i32_le","x"]-> bytes["std.result.err0"]-> bytes["std.result.chain_sum_csv_i32","b"]-> bytes
-
std.option["std.option.some_i32_le","x"]-> bytes["std.option.none"]-> bytes
-
std.io["std.io.read","reader","max"]-> bytes (readerisiface)
-
std.io.bufread["std.io.bufread.new","reader","cap"]-> i32 (readerisiface)["std.io.bufread.fill","br"]-> bytes_view["std.io.bufread.consume","br","n"]-> i32
-
std.fs(world-bound viastd.world.fs)["std.fs.read","path_bytes"]-> bytes["std.fs.read_async","path_bytes"]-> bytes["std.fs.open_read","path_bytes"]-> iface["std.fs.list_dir","path_bytes"]-> bytes["std.fs.list_dir_sorted","path_bytes"]-> bytes
-
std.world.fs(adapter module; world-selected)["std.world.fs.read_file","path_bytes"]-> bytes["std.world.fs.read_file_async","path_bytes"]-> bytes
-
std.rr(solve-rr only)["std.rr.send_request","req_bytes"]-> bytes["std.rr.fetch","key_bytes"]-> bytes["std.rr.send","key_bytes"]-> iface
-
std.kv(solve-kv only)["std.kv.get","key_bytes"]-> bytes["std.kv.get_async","key_bytes"]-> bytes["std.kv.set","key_bytes","val_bytes"]-> i32["std.kv.get_stream","key_bytes"]-> iface
-
std.path["std.path.join","a","b"]-> bytes["std.path.basename","p"]-> bytes["std.path.extname","p"]-> bytes
Operators (i32)
["+","a","b"]["-","a","b"]["*","a","b"]["/","a","b"]["%","a","b"]["=","a","b"]["!=","a","b"]- Signed comparisons (two’s complement):
["<","a","b"]["<=","a","b"][">","a","b"][">=","a","b"] - Unsigned comparisons:
["<u","a","b"][">=u","a","b"] - Shifts:
["<<u","a","b"][">>u","a","b"](shift amount masked by 31) - Bitwise:
["&","a","b"]["|","a","b"]["^","a","b"]
Integer Semantics
- Integers are 32-bit and arithmetic wraps modulo 2^32.
- Beware underflow/overflow:
["-",0,1]becomes-1(wrap-around). /and%are unsigned u32 ops:/by 0 yields 0, and%by 0 yields the numerator.["<u","x",0]is always false and[">=u","x",0]is always true.- For negative checks, use signed comparisons like
["<","x",0]. - For "can’t go below zero" counters, guard before decrementing.
Bytes Ops
Use std.bytes.* functions (import std.bytes):
["std.bytes.len","b"]-> i32["std.bytes.get_u8","b","i"]-> i32 (0..255)["std.bytes.set_u8","b","i","v"]-> bytes (returnsb)["std.bytes.alloc","n"]-> bytes (lengthn)
Additional bytes ops:
-
["std.bytes.eq","a","b"]-> i32 (1 if equal else 0) -
["std.bytes.find_u8","b","target"]-> i32 (index, or -1) -
["std.bytes.cmp_range","a","a_off","a_len","b","b_off","b_len"]-> i32 (-1/0/1) -
["std.bytes.max_u8","v"]-> i32 (vis bytes_view; returns 0 if empty) -
["std.bytes.sum_u8","v"]-> i32 (vis bytes_view; wraps mod 2^32) -
["std.bytes.count_u8","v","target"]-> i32 (vis bytes_view) -
["std.bytes.starts_with","a","prefix"]-> i32 (both bytes_view) -
["std.bytes.ends_with","a","suffix"]-> i32 (both bytes_view)
For copy/slice/concat/reverse/take/drop helpers, use std.bytes.* module functions (see Modules).
Bytes literals:
["bytes.lit","token"]-> bytes (UTF-8 of the atom string; no whitespace)- Example:
["bytes.lit","config.bin"]producesb"config.bin".
- Example:
Views
Views are explicit, borrowed slices used for scan/trim/split without copying.
["bytes.view","b"]-> bytes_view["bytes.subview","b","start","len"]-> bytes_view["view.len","v"]-> i32["view.get_u8","v","i"]-> i32["view.slice","v","start","len"]-> bytes_view["view.to_bytes","v"]-> bytes (copy)["view.eq","a","b"]-> i32 (1 if equal else 0)["view.cmp_range","a","a_off","a_len","b","b_off","b_len"]-> i32 (-1/0/1)
Filesystem (solve-fs only)
["fs.read","path_bytes"]-> bytes["fs.read_async","path_bytes"]-> bytes["fs.open_read","path_bytes"]-> iface- Returns an
ifacereader for streaming reads.
- Returns an
["fs.list_dir","path_bytes"]-> bytes (newline-separated names, sorted, trailing\n)path_bytesmust be a safe relative path (no absolute paths, no.., no empty segments).- The fixture directory is the current working directory (
.).
Request/Response (solve-rr only)
["rr.send_request","req_bytes"]-> bytes- Fixture-backed request/response (no real network).
req_bytesare hashed assha256(req_bytes)and mapped to a response blob under./.x07_rr/.
["rr.fetch","key_bytes"]-> bytes- Fixture-backed request/response with deterministic latency modeling.
["rr.send","key_bytes"]-> iface- Returns an
ifacereader for streaming reads.
- Returns an
Key/Value (solve-kv only)
["kv.get","key_bytes"]-> bytes- Returns empty bytes if missing.
["kv.get_async","key_bytes"]-> bytes- Same as
kv.getbut explicitly uses the async/latency-aware path.
- Same as
["kv.get_stream","key_bytes"]-> iface- Returns an
ifacereader for streaming reads.
- Returns an
["kv.set","key_bytes","val_bytes"]-> i32- Returns 1 if inserted, 0 if updated.
- Store is seeded per case from
./.x07_kv/seed.evkvand reset per case.
Streaming I/O
Readers are iface values returned by world adapters.
["io.open_read_bytes","b"]-> iface (bis bytes/bytes_view/vec_u8)["io.read","reader_iface","max_i32"]-> bytes["bufread.new","reader_iface","cap_i32"]-> i32["bufread.fill","br"]-> bytes_view["bufread.consume","br","n_i32"]-> i32
Vectors
vec_u8 is a mutable byte vector value used for building outputs efficiently.
Use std.vec.* to create and manipulate vec_u8 values:
["std.vec.with_capacity","cap"]-> vec_u8["std.vec.push","v","x"]-> vec_u8["std.vec.reserve_exact","v","additional"]-> vec_u8["std.vec.extend_bytes","v","b"]-> vec_u8["std.vec.as_bytes","v"]-> bytes
Additional vec_u8 builtins:
["vec_u8.extend_bytes_range","v","b","start","len"]-> vec_u8 (append subrange ofb)["vec_u8.as_view","v"]-> bytes_view (borrowed view of current vec contents)
Option / Result
Typed options:
-
["option_i32.none"]-> option_i32 -
["option_i32.some","x"]-> option_i32 -
["option_i32.is_some","o"]-> i32 -
["option_i32.unwrap_or","o","default"]-> i32 -
["option_bytes.none"]-> option_bytes -
["option_bytes.some","b"]-> option_bytes -
["option_bytes.is_some","o"]-> i32 -
["option_bytes.unwrap_or","o","default"]-> bytes
Typed results:
-
["result_i32.ok","x"]-> result_i32 -
["result_i32.err","code"]-> result_i32 -
["result_i32.is_ok","r"]-> i32 -
["result_i32.err_code","r"]-> i32 -
["result_i32.unwrap_or","r","default"]-> i32 -
["result_bytes.ok","b"]-> result_bytes -
["result_bytes.err","code"]-> result_bytes -
["result_bytes.is_ok","r"]-> i32 -
["result_bytes.err_code","r"]-> i32 -
["result_bytes.unwrap_or","r","default"]-> bytes
Propagation sugar:
["try","r"]->i32orbytes(requires the currentdefnreturn type isresult_i32orresult_bytes)
Memory / Performance Tips
-
Deterministic suite gates may enforce
mem_stats: reducerealloc_calls,memcpy_bytes, andpeak_live_bytes. -
Prefer building output with
std.vecinstead of repeated concatenation in a loop. -
If you can estimate the final size, start with
["std.vec.with_capacity","n"]to avoid reallocations. -
When appending many bytes, prefer
["std.vec.extend_bytes","v","chunk"]over per-byte["std.vec.push",...]. -
Convert once at the end:
["std.vec.as_bytes","v"]returns bytes without copying. -
Use
bytes_view+view.*builtins for scanning/slicing without copying. -
For streaming parsing, use
["bufread.fill","br"]to get abytes_viewwindow, scan it, then["bufread.consume","br","n"].
Maps / Sets
Open-addressing hash tables with fixed capacity.
-
capacity must be a non-zero power of two
-
key
-1is reserved and will trap -
["map_u32.new","cap_pow2"]-> i32 -
["map_u32.len","m"]-> i32 -
["map_u32.contains","m","key"]-> i32 (0/1) -
["map_u32.get","m","key","default"]-> i32 -
["map_u32.set","m","key","value"]-> i32 (1 if inserted, 0 if updated) -
["map_u32.remove","m","key"]-> i32 (1 if removed, 0 if missing) -
["set_u32.new","cap_pow2"]-> i32 -
["set_u32.contains","s","key"]-> i32 (0/1) -
["set_u32.add","s","key"]-> i32 (1 if inserted, 0 if already present) -
["set_u32.remove","s","key"]-> i32 (1 if removed, 0 if missing)
Collection emitters
Use emit_* stdlib functions to produce canonical deterministic encodings:
std.hash_set.emit_u32le(set_u32_handle)-> bytes (sorted ascending u32le)std.hash_map.emit_kv_u32le_u32le(map_u32_handle)-> bytes ((k u32le)(v u32le)... sorted by key)std.btree_set.emit_u32le(btree_set_bytes)-> bytes (already sorted)std.btree_map.emit_kv_u32le_u32le(btree_map_bytes)-> bytes (already sorted)std.deque_u32.emit_u32le(dq_bytes)-> bytes (front-to-back)std.heap_u32.emit_u32le(heap_bytes)-> bytes (non-decreasing pop-min order; consumes heap_bytes)
Stdlib (pure)
Prefer calling stdlib helpers through their module namespaces (and include the module in imports):
-
std.codec:["std.codec.read_u32_le","b","off"](bis bytes_view),["std.codec.write_u32_le","x"] -
std.parse:["std.parse.u32_dec","b"],["std.parse.u32_dec_at","b","off"],["std.parse.i32_status_le","b"] -
std.fmt:["std.fmt.u32_to_dec","x"],["std.fmt.s32_to_dec","x"] -
std.prng:["std.prng.lcg_next_u32","state"] -
std.bit:["std.bit.popcount_u32","x"]
Common Templates
- 1-byte output:
["begin",["let","out",["bytes.alloc",1]],["set","out",["bytes.set_u8","out",0,"x"]],"out"] - Empty output:
["bytes.alloc",0] - Looping: use
bytes.lenonce, then["for","i",0,"n",body].
Header + tail pattern
Many tasks use input[0..k] as parameters and the remaining bytes as data.
Example (k=1):
["begin",["let","x",["std.bytes.get_u8","input",0]],["let","n",["std.bytes.len","input"]],["let","v",["std.vec.with_capacity",["-","n",1]]],["for","i",1,"n",["std.vec.push","v",["std.bytes.get_u8","input","i"]]],["std.vec.as_bytes","v"]]