A general purpose .. programming language written in zig ijadux2.tngl.sh/Rinnescript
zig language
6.6 kB

std — core library #

The std namespace is built into every RinneScript program — no import required. You may still write @import = .{ std }; for clarity, but it is not necessary.

Other modules (c, ai, llm, net) must be explicitly imported:

@import = .{ c, ai, llm, net };

Unknown modules fail at compile time:

compile error: unknown module 'http' in @import (known modules: std, ai)

Printing #

std.print / std.stdout write to stdout; std.stderr and std.log to stderr. All of them take a format string plus a tuple — the tuple form is required:

std.print("x={}\n", .{42});
std.print("{} + {} = {}\n", .{1, 2, 3});
std.stderr("warn: {}\n", .{"disk almost full"});

{} is a placeholder; {{ and }} are literal braces.

Casting with @as #

@as(type, value) converts values explicitly:

Type name Meaning
int, i32, i64, u8, u32, u64, usize integer conversion
float, f32, f64 floating-point conversion
str, string render value as text
bool truthiness
const f = @as(float, 7);        // 7.0
const i = @as(int, 3.9);        // 3 (truncates)
const s = @as(str, 42);         // "42"
const b = @as(bool, 0);         // false

An unknown type name fails at runtime: unknown type 'complex' in @as.

Strings — std.strings #

All string builtins take and return immutable strings unless noted.

Builtin Description
len(s) length of string, array, or vector
slice(s, start, end) substring (negative indices count from the end)
split(s, sep), join(parts, sep) split on separator / join with separator
trim(s) strip leading/trailing whitespace
replace(s, from, to) replace all occurrences
contains(s, sub), starts_with(s, p), ends_with(s, p) substrings tests
to_lower(s), to_upper(s) case conversion
repeat(s, n) concatenate s n times
chars(s) array of single-character strings
reverse(s) reversed string
std.print("{} — {}\n", .{
    std.strings.repeat("ab", 3),        // ababab
    std.strings.reverse("hello"),       // olleh
});
std.print("{}\n", .{std.strings.chars("hi")});   // ["h", "i"]

Math — std.math #

Numeric helpers that keep integers as integers and widen to floats when the input is a float.

Builtin Description
abs(x) absolute value (int stays int)
floor(x), ceil(x), round(x) rounding (result is a float)
sqrt(x) square root (float)
pow(x, y) x raised to y (float)
min(a, b), max(a, b) extremum, ints stay ints
clamp(x, lo, hi) clamp x into [lo, hi] (int stays int)
std.print("{}\n", .{std.math.abs(-7)});        // 7
std.print("{}\n", .{std.math.floor(2.7)});     // 2
std.print("{}\n", .{std.math.sqrt(81)});       // 9
std.print("{}\n", .{std.math.clamp(15, 1, 10)}); // 10

File I/O — std.io #

std.io.stdout is a callable form of the @stdout directive. The file helpers operate on absolute or cwd-relative paths; parents of a target file must exist (make_dir_all creates an entire tree).

Builtin Description
read_file(path) contents as a string
write_file(path, data) write (truncating), true on success
append_file(path, data) append, true on success
file_exists(path) boolean
make_dir(path) create one directory, true if created
make_dir_all(path) create directory and any missing parents
remove_file(path) delete a file
remove_dir(path) delete an empty directory
rename_file(from, to) move a file, true on success
list_dir(path) array of entry names
std.io.make_dir_all("/tmp/rg_demo/sub");
std.io.write_file("/tmp/rg_demo/f.txt", "line1\n");
std.io.append_file("/tmp/rg_demo/f.txt", "line2\n");
std.print("{}", .{std.io.read_file("/tmp/rg_demo/f.txt")});
std.print("{}\n", .{std.io.list_dir("/tmp/rg_demo")});

JSON and data formats — std.json #

json_parse turns a JSON string into a value (map/array/scalar); the json_stringify and json_pretty functions serialize back. Map iteration order is unspecified, so treat serialized maps as unordered.

Builtin Description
json_parse(text) parse a JSON document
json_stringify(v) compact single-line JSON
json_pretty(v) indented, human-readable JSON
csv_parse(text), csv_format(rows) CSV text <-> array of arrays
base64_encode(data), base64_decode(text) base64 round trip
const doc = std.json.json_parse("{\"name\": \"rinne\"}");
std.print("{}\n", .{doc["name"]});                     // rinne
std.print("{}\n", .{std.json.json_pretty(doc)});
// {
//   "name": "rinne"
// }

Collections — std.collections #

Arrays are values, so "mutating" helpers return a new array.

Builtin Description
push(arr, v) new array with v appended
map_new(k0, v0, ...) build a string-keyed map from pairs
contains_val(coll, v) does the array hold v, or the map contain it as a value?
const xs = std.collections.push([1, 2], 3);
std.print("{}\n", .{std.collections.contains_val(xs, 3)}); // true
std.print("{}\n", .{std.collections.contains_val({"a": 1}, 1)}); // true

Type aliases (std/types.rg) #

std/types.rg documents the canonical aliases used across the standard library and examples (vec16f, byte, ...). The VM is dynamically typed, so annotations are documentation sugar — they parse today and read well, but do not change runtime behavior.

Runnable example #

pub fn main() int {
    const x = @int(3.9);
    const f = @as(float, 7);
    std.print("@int(3.9)={} @as(float,7)={} str(42)='{}'\n", .{x, f, @as(str, 42)});
    return 0;
}

Output:

@int(3.9)=3 @as(float,7)=7 str(42)='42'

Module gating #

std is implicitly imported — all std.* builtins are available immediately. Modules c, ai, llm, and net require an explicit import at the top of the file:

@import = .{ c, ai, llm, net };

Without the import, calling c.load_lib, ai.load_safetensors, ai.load_gguf, llm.llm_load, net.tcp_listen, or net.tcp_connect fails at compile time.