A general purpose .. programming language written in zig ijadux2.tngl.sh/Rinnescript
zig language
Zig 63%
C 20%
HTML 6%
Rouge 6%
CSS 1%
JavaScript 1%
C++ <1%
Roff <1%
Shell <1%
Vim Script <1%
Emacs Lisp <1%
Lua <1%
Tree-sitter Query <1%
YASnippet <1%

README.md

RinneScript (.rg) #

A dual-mode systems and AI programming language written in pure Zig — zero third-party dependencies.

RinneScript pairs an instant-start bytecode VM for scripting and prototyping with native compilation backends — C11 for a broad subset, plus a linked native backend (--native, x86-64 or AArch64 for the build host; libc + -l/-L libs and @libcall bindings) and a freestanding --no-libc static ELF — for dependency-free binaries, and ships a first-class AI/tensor ecosystem: tensors with SIMD-style kernels, zero-copy GGUF/SafeTensors readers, a CPU transformer forward pass, a package manager, TCP networking, and dlopen-based C FFI.

@import = .{ std };

fn fib(n: int) int {
    if n < 2 { return n; }
    return fib(n - 1) + fib(n - 2);
}

pub fn main(args: []str) int {
    std.print("fib(20) = {}\n", .{fib(20)});
    return 0;
}

Quick start #

zig build
./zig-out/bin/rinne run examples/basics.rg        # variables, control flow, functions
./zig-out/bin/rinne run examples/types_demo.rg    # std import + @as casts
./zig-out/bin/rinne run examples/utilities.rg    # std.math/strings/io/json/collections
./zig-out/bin/rinne run examples/tensor_simd.rg   # @tensor + apply_simd ReLU
./zig-out/bin/rinne build --native examples/native.rg  # -> a native binary (host arch)
# manifest project mode (file:// fetch + use + lock + offline reuse):
cd examples/project_demo
../../zig-out/bin/rinne run                # fetch (relative file:// dep) → 42 / hello, rinne / 7
../../zig-out/bin/rinne lock               # write rinne.lock pins
RINNE_OFFLINE=1 ../../zig-out/bin/rinne run  # cache-only reuse, no network
cd ../..
./zig-out/bin/rinne version
zig build test                              # full test suite

CLI #

Command Description
rinne run <script.rg> [args...] Execute a script on the bytecode VM
rinne check <file.rg>... Parse + compile without running (CI-friendly); -q/--quiet
rinne test [path] Run the test suite (tests/**/*.rg, or one file/dir); std.test asserts never abort a script
rinne lock Resolve manifest.rg fetches and write rinne.lock (kind/url/ref/commit/entry/sha256 pins)
rinne count <file.rg>... Source metrics: lines / code / comments / functions
rinne build <entry.rg> [-o out] Native compilation → <name>.rgx (C11 default, or --native host-arch linked against libc, --native --no-libc freestanding, -l/-L link libs, @libcall bindings)
rinne fmt [--check] <file.rg> Format a script (or check with --check)
rinne lint <file.rg>... Static analysis
rinne init <name> Scaffold main.rg + manifest.rg + .gitignore into a new directory
rinne repl Interactive read-eval-print loop (each snippet runs standalone)
rinne completions bash|zsh|fish Emit a shell completion script
rinne help [topic] Per-command help topics
rinne version Version + target triple

With no file argument, rinne run/build/check operate in project mode: they walk up to find manifest.rg, fetch its packages (file:// and git, sha256 pinned), inject them into the target, and — from rinne lock onward — reuse pins and the package cache.

Global options: --quiet (suppress non-essential output), --offline (resolve packages from the cache only; refuse uncached ones instead of reaching the network), and --color auto|always|never (diagnostics coloring; auto keys off $TERM). Global options may appear before or after the command. RINNE_OFFLINE=1 is the environment equivalent of --offline.

Exit codes: 0 success · 64 usage error · 69 not implemented · 70 parse/compile/runtime failure. A script's exit code is the value its pub fn main returns.

Language tour #

@import = .{ std };

// Functions with typed params and return types.
fn sum_to(n: int) int {
    var total: int = 0;
    var i: int = 1;
    while i <= n {
        total = total + i;
        i = i + 1;
    }
    return total;
}

// Explicit casts with @as; type annotations accept std/types.rg aliases.
const x: float = @as(float, 7);          // 7.0
const label: str = @as(str, x);          // "7"
var v: vec16f = std.vec.splat(16, 1.5);         // vec16f is an alias from std/types.rg

pub fn main(args: []str) int {
    std.print("{} {} {}\n", .{sum_to(100), x, label});
    return 0;
}

Notes on the surface:

  • Formatted output: std.print("x={}\n", .{x}) — the format string plus a tuple of values ({{/}} are literal-brace escapes). The tuple form is required.
  • Imports register namespaces: @import = .{ std }; enables std.print, std.stderr, etc. Unknown modules fail at compile time.
  • Casts go through @as(int|float|str|bool, value) (aliases like i32, u64, f32 map onto those four paths).
  • defer runs LIFO at scope exit. In v1 a deferred body cannot capture enclosing locals — call globals/builtins only, or deinit explicitly.
  • Records: .{ .x = 1 } is an unordered map you can read by name — r.x reads the field (missing keys yield null), var r = .{...} lets you write r.x = 2, and a const root rejects field writes at compile time. .{ .x } is shorthand for .{ .x = x } by the same name. See examples/structs.rg.

Libraries #

Every library has a runnable-example guide under docs/libs/:

Library Entry points Guide
std @import = .{std}, @as, std.print/std.stderr; std.strings.*, std.math.*, std.io.* (fs), std.json.*, std.collections.* docs/libs/std.md
tensor @tensor(f32,[6],.{.device=.cpu,.fill=0}), .apply_simd(kernel), indexing, deinit/shape/numel/dtype/fill/data docs/libs/tensor.md
ai ai.load_safetensors(path), ai.load_gguf(path) → named read-only tensor views (mmap, zero-copy) docs/libs/ai.md
llm llm.llm_load(path) → transformer model; model.forward(ids) → last-token logits (CPU) docs/libs/llm.md
pkg module-level @fetch(url_or_repo, .{ .version, .sha256 }) → cached, checksum-pinned dependencies docs/libs/pkg.md
net net.tcp_listen(port), net.tcp_connect(host, port); accept/read/write/shutdown/close docs/libs/net.md
c c.load_lib("libc.so.6") → dlopen handle; lib.call_int(sym, args), lib.call_float(sym, args), lib.deinit() docs/libs/c.md
build std.build.* manifest.rg build-plan namespace (targets, fetches, use, lock, typed options, imports, overlays) for project mode docs/libs/build.md

A taste of each:

// tensor: element-wise kernel over every cell (in place)
@import = .{ std };
var t: []f32 = @tensor(f32, [6], .{ .device = .cpu, .fill = -1.5 });
t[3] = 4.25;
t.apply_simd(fn(x: @vector(8, f32)) f32 {
    if x < 0.0 { return 0.0; }
    return x;
});                                       // relu in place
std.print("{}\n", .{t.data()});           // [0, 0, 0, 4.25, 0, 0]
t.deinit();
@import = .{ std, net };
// net: loopback echo — half-close (shutdown) frames messages
const l = net.tcp_listen(0);
const c = net.tcp_connect("127.0.0.1", l.port());
c.write("ping");
c.shutdown();                             // signals end-of-message
const s = l.accept();
std.print("{}\n", .{s.read(64)});         // "ping" (read returns early at EOF)
s.write("pong");
s.shutdown();
std.print("{}\n", .{c.read(64)});         // "pong"
@import = .{ std };
// pkg: fetch a dependency (module level), then call it
@fetch("github.com/user/lib", .{ .version = "v1.2.0", .sha256 = "..." });

pub fn main(args: []str) int {
    std.print("{}\n", .{lib_add(2, 3)});
    return 0;
}

Platform notes:

  • c.load_lib accepts sonames or full paths — resolution goes through the system loader (libc.so.6 works; note fabs lives in libm).
  • AI loaders memory-map model files (Windows unsupported for mmap loaders).
  • @import_c stays gated in v1 by design — dlopen FFI via c.load_lib is the supported C interop story.
  • Tensor devices other than .cpu degrade with a clear runtime error in this build (no CUDA linking yet).

Development #

zig build                              # build the rinne binary
zig build test                         # unit + end-to-end tests (184)
zig build -Doptimize=ReleaseFast       # optimized binary

The docs site under site/ is hand-maintained vanilla HTML (no generator).

Layout:

src/
  main.zig              # CLI entry (run/build/check/test/lock/count/init/repl/fmt/lint/lsp/completions)
  root.zig              # module exports + aggregate tests
  lsp.zig               # language server (LSP over stdio)
  script/
    lexer.zig           # O(1) tokenizer (@directives, escapes)
    parser.zig          # AST + recursive-descent parser
    compiler.zig        # bytecode emitter, phase-gated directives
    vm.zig              # stack VM, frames, defers, builtins, e2e tests
    value.zig           # dynamic values, TensorObj/LlmModel/LibObj/NetObj
    type_checker.zig    # dormant static checker (tooling phases)
    mmap.zig            # cross-platform file mapping (std.Io)
    ai_safetensors.zig  # SafeTensors header parser -> tensor views
    ai_gguf.zig         # GGUF v2/v3 parser (+ numeric kv capture)
    llm.zig             # transformer forward pass (RMSNorm/RoPE/GQA/SwiGLU)
    pkg.zig             # @fetch package manager (cache/sha256/tar.gz)
    loader.zig          # resolves module-level @fetch before compile
  codegen/
    c_emitter.zig       # C11 emitter powering `rinne build`
  tools/
    fmt.zig             # formatter core (rinne fmt)
    lint.zig            # linter (rinne lint)
examples/               # runnable .rg programs
selfhost/               # RinneScript lexer/parser/eval written in .rg
std/types.rg            # core type aliases
editors/                # Neovim / VS Code / Emacs integrations (+ tree-sitter)
test/                   # test corpus
docs/libs/*.md          # library guides with runnable examples
docs/man/               # rinne(1), rinne-libs(7)
site/                   # hand-maintained vanilla HTML/JS website
PIVOT.md                # pivot spec & phase roadmap
v1.md                   # v1.0 release execution plan
vision.md               # the project north star: mission, principles, roadmap

Roadmap #

From vision.md (mission & roadmap) and PIVOT.md / v1.md:

Remaining / future work: CUDA/ROCm allocators (devices currently degrade), LLVM backend, tokenizer for end-to-end text generation, @import_c native decls (kept gated), first-class function values, utility libraries (crypto/log/test; csv + shell-completion CLI helpers landed in std.json and rinne completions).

Design principles #

  1. Dual-mode: prototype on the VM (<10 ms startup), ship native via codegen — same language, same semantics.
  2. Explicit over implicit: manual memory with defer, explicit types, no hidden control flow.
  3. AI-native: tensors and SIMD as first-class intrinsics, not libraries.
  4. Small, auditable core: pure Zig, zero third-party dependencies.