01 / Toolchain
Commands
Build the tools with make. The build/bin/ziran dispatcher accepts check, ir, build, bundle, run, and fmt. Direct binaries are listed below.
zi2zir --check-only --root DIR file.ziCheck source and imports without writing IR. Use --diagnostics=json for machine-readable diagnostics.
zi2zir --root DIR -o DIR file.zi|file.zir ...Check and write versioned .zir modules.
zi2c --root DIR -o DIR file.zi|file.zir ...Generate C. Optional --no-main, --plan9, and --include-dir DIR.
zi2cpp --root DIR -o DIR file.zi|file.zir ...Generate C++. Optional --no-main.
zi2go --root DIR -o DIR file.zi|file.zir ...Generate native Go. Optional --no-main, --pkg NAME, and --minify.
zi2zib bundle --root DIR --entry module:function -o FILE file.zi|file.zir ...Link supported programs into a versioned .zib bundle. zi2zib run FILE validates and runs a bundle without host bindings.
zi-fmt [--check] file.zi ...Format source with stable indentation and spacing cleanup; --check reports files that need formatting.
Repeat --module-path DIR to search for imported modules outside the root. Native tools also accept --diagnostics=text|json. The toolchain rejects --no-strict.
02 / Standard library
Text and UTF-8
Import with #import "text" or #import "utf8" and pass --module-path std. Strings are immutable UTF-8 byte sequences; .length and indexes use bytes.
std/text.zi
LowerASCII(value: u8) -> u8Convert ASCII A–Z to lowercase; other bytes are unchanged.
StartsWithFoldASCII(value: string, prefix: string) -> boolTest a prefix with ASCII-only case folding.
ContainsFoldASCII(value: string, needle: string) -> boolFind a byte substring with ASCII-only case folding. Empty needle matches.
std/utf8.zi
Continuation(byte: u8) -> boolTest whether a byte is in the UTF-8 continuation range.
Next(value: string, at: s32) -> s32Advance to the next scalar boundary. Negative offsets return zero; offsets at or beyond the end return the length. Invalid bytes advance one byte.
Count(value: string) -> s32Count scalars using Next; invalid bytes each count as one step.
03 / Standard library
Generic value records
These are ordinary copyable records with explicit status fields. They have no hidden active variant and do not allocate.
Option($T: Type) { has_value: bool; value: T; }Apply as Number :: Option(s32). Check has_value before reading value.
Result($T: Type, $E: Type) { is_ok: bool; value: T; error: E; }Apply as Outcome :: Result(s32, string). Check is_ok and read the corresponding field.
Pair($A: Type, $B: Type) { first: A; second: B; }Two-field value record. Apply as Pair(s32, string).
Owned growable Vec and a string builder are planned; they are not shipped APIs.
04 / Standard library
JSON scanner
std/json_scan.zi scans without allocating. All positions are UTF-8 byte offsets in the original input. A JsonSpan has start, end, after, and valid; a JsonNumber has value: float64, after, and valid. String spans retain their escape bytes.
Space(text: string, at: s32) -> s32Skip ASCII JSON whitespace.
Digit(ch: u8) -> boolTest ASCII decimal digit.
Hex(ch: u8) -> boolTest ASCII hexadecimal digit.
ReadString(text: string, at: s32) -> JsonSpanValidate a quoted JSON string at at and return its content span.
SpanEqualsASCII(text: string, span: JsonSpan, expected: string) -> boolCompare a valid span to exact ASCII bytes.
SpanContainsFoldASCII(text: string, span: JsonSpan, needle: string) -> boolSearch inside a valid span with ASCII-only case folding.
ReadNumber(text: string, at: s32) -> JsonNumberParse a JSON decimal number into float64.
MatchLiteral(text: string, at: s32, literal: string) -> boolCompare exact bytes at an offset.
ValueEnd(text: string, at: s32, depth: s32) -> s32Return the offset after a valid JSON value or -1. Recursion deeper than 64 fails.
FieldAt(text: string, object_at: s32, name: string) -> s32Find an object member’s value offset or -1. Member names match unescaped ASCII bytes.
ElementAt(text: string, array_at: s32, index: s32) -> s32Find an array element’s value offset or -1.
05 / Host capability
HTTP
std/net_http.zi specifies an HTTP request/response contract; transport and TLS are supplied by the host. SendHost is a declared host_api foreign capability, while Send is the public wrapper.
HttpRequestFields: method, url, token, accept, content_type, body (all strings). The host adds a Bearer authorization header when token is nonempty and must not log it.
HttpResponseFields: status: s32, body: string, error: string.
SendHost(request: HttpRequest) -> HttpResponseForeign host_api capability. Bind net_http:SendHost when running a bundle that imports it.
Send(request: HttpRequest) -> HttpResponsePublic wrapper that forwards the request to the host capability.
06 / Host capability
Processes
std/process.zi defines a line-oriented child-process contract. The host owns handles and performs isolation and process I/O. The Ziran wrapper rejects more than 32 arguments.
ProcessRequestexecutable, cwd, stdin, credential_name, credential_value (strings), isolate_desktop: bool, timeout_ms: s64.
ProcessStarthandle: s32, error: string.
ProcessLinetext: string, eof: bool, error: string.
ProcessExitcode: s32, stderr: string, error: string.
StartHost(request: ProcessRequest, args: []string) -> ProcessStartForeign host_api capability that starts the child.
NextLineHost(handle: s32) -> ProcessLineForeign host_api capability that reads the next output line.
WaitHost(handle: s32) -> ProcessExitForeign host_api capability that waits for completion.
Start(request: ProcessRequest, args: []string) -> ProcessStartStart a child with explicit arguments. The host must honor isolate_desktop before starting it.
NextLine(handle: s32) -> ProcessLineRead the next output line.
Wait(handle: s32) -> ProcessExitWait for completion; callers consume lines and wait exactly once.
Bind process:StartHost, process:NextLineHost, and process:WaitHost for bundles that import this module. Ziran source repository ↗
07 / Embedding
Portable C host API
Include ziran_host.h and link build/libziran.a. The host API validates version 7 bundles and requires every linked capability to be bound before execution.
Bundle *BundleOpen(const char *path)Open and validate a bundle. Returns an opaque handle or failure.
void BundleClose(Bundle *bundle)Release a bundle and its names.
size_t BundleCapabilityCount(const Bundle *bundle)Number of required host capabilities.
const char *BundleCapabilityModule(const Bundle *bundle, size_t index)Module name for a required capability.
const char *BundleCapabilityFunction(const Bundle *bundle, size_t index)Function name for a required capability.
int BundleRun(const Bundle *bundle, const HostBinding *bindings, size_t count, long long *result, int *has_result)Run with fresh globals. Integer and boolean entry values populate result; a void entry sets has_result to zero.
BundleInstance *BundleInstantiate(const Bundle *bundle, const HostBinding *bindings, size_t count)Create an instance whose module globals persist between runs. Keep the bundle and binding contexts alive until close.
int BundleInstanceRun(BundleInstance *instance, long long *result, int *has_result)Run one entry call. A runtime failure makes that instance unusable.
void BundleInstanceClose(BundleInstance *instance)Release the instance.
Host values and callbacks
HostBinding contains module, function, a VmHostCall callback, and context. The callback receives typed arguments and writes a typed result. The value kinds are VM_HOST_VOID, VM_HOST_INTEGER, VM_HOST_UNSIGNED, VM_HOST_REAL, VM_HOST_STRING, VM_HOST_RECORD, and VM_HOST_SLICE.
typedef int (*VmHostCall)(void *context, const char *module,
const char *function, const VmHostValue *args,
int arg_count, VmHostValue *result);
typedef struct HostBinding {
const char *module;
const char *function;
VmHostCall call;
void *context;
} HostBinding;VmHostValue has kind: VmHostValueKind, type: const char *, integer: int64_t, bits: uint64_t, real: double, data: const unsigned char *, length: size_t, fields: const VmHostField *, field_count: size_t, and elements: VmHostValue *. Each VmHostField has name and value.
Record fields are in declaration order and include names and types. Synchronous numeric, boolean, and string slice arguments may be edited in place; keep the element pointer and length unchanged. The VM validates and copies edits back. Host pointer, array, and slot calls are unsupported. Returned string bytes and record fields must remain valid until BundleRun returns.