Something went wrong. Try again.
A general purpose .. programming language written in zig ijadux2.tngl.sh/Rinnescript
zig language
Something went wrong. Try again.
24 kB · 571 lines
HTML
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Docs · RinneScript</title><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;800&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet"><link rel="stylesheet" href="assets/styles.css"><script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/components/prism-core.min.js" defer></script><script src="assets/prism-lang.js" defer></script><script src="assets/main.js" defer></script></head><body><nav class="nav"> <a class="brand" href="./index.html">RinneScript</a> <div class="nlinks"> <a class="nl" href="./index.html">Home</a> <a class="nl" href="./api.html">API</a> <a class="nl on" href="./docs.html">Docs</a> <a class="nl" href="./examples.html">Examples</a> </div></nav><main class="wrap"><div class="doclayout"><nav class="rail"><a href="#std">Standard Library</a><a href="#tensor">Tensors</a><a href="#ai">AI Models</a><a href="#llm">LLM Inference</a><a href="#pkg">Marketplace (@fetch)</a><a href="#net">Networking</a><a href="#c">C FFI</a></nav><div class="apigroups"><section class="chapter" id="std"><h1>Standard Library</h1><h1 id="std--core-library">std — core library</h1><p>The <code>std</code> namespace is built into every RinneScript program. Import it at the top of your file:</p><pre class="rinne"><code>@import = .{ std };</code></pre><p>Unknown modules fail at compile time:</p><pre><code>compile error: unknown module 'http' in @import (known modules: std, ai)</code></pre><h2 id="printing">Printing</h2><p><code>std.print</code> / <code>std.stdout</code> write to stdout; <code>std.stderr</code> and <code>std.log</code> to stderr. All of them take a format string plus a <strong>tuple</strong> — the tuple form is required:</p><pre class="rinne"><code>@import = .{ std };std.print("x={}\n", .{42});std.print("{} + {} = {}\n", .{1, 2, 3});std.stderr("warn: {}\n", .{"disk almost full"});</code></pre><p><code>{}</code> is a placeholder; <code>{{</code> and <code>}}</code> are literal braces.</p><h2 id="casting-with-as">Casting with @as</h2><p><code>@as(type, value)</code> converts values explicitly:</p><table><thead><tr><th>Type name</th><th>Meaning</th></tr></thead><tbody><tr><td><code>int</code>, <code>i32</code>, <code>i64</code>, <code>u8</code>, <code>u32</code>, <code>u64</code>, <code>usize</code></td><td>integer conversion</td></tr><tr><td><code>float</code>, <code>f32</code>, <code>f64</code></td><td>floating-point conversion</td></tr><tr><td><code>str</code>, <code>string</code></td><td>render value as text</td></tr><tr><td><code>bool</code></td><td>truthiness</td></tr></tbody></table><pre class="rinne"><code>const f = @as(float, 7); // 7.0const i = @as(int, 3.9); // 3 (truncates)const s = @as(str, 42); // "42"const b = @as(bool, 0); // false</code></pre><p>An unknown type name fails at runtime: <code>unknown type 'complex' in @as</code>.</p><h2 id="type-aliases-stdtypesrg">Type aliases (std/types.rg)</h2><p><code>std/types.rg</code> documents the canonical aliases used across the standard library and examples (<code>vec16f</code>, <code>byte</code>, ...). The VM is dynamically typed, so annotations are documentation sugar — they parse today and read well, but do not change runtime behavior.</p><h2 id="runnable-example">Runnable example</h2><pre class="rinne"><code>@import = .{ std };
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;}</code></pre><p>Output:</p><pre><code>int(3.9)=3 @as(float,7)=7 str(42)='42'</code></pre><h2 id="module-gating">Module gating</h2><p>Namespaced calls and module-owned builtins only work after importing their module. <code>std.print(...)</code> fails at compile time until you write <code>@import = .{ std };</code> at the top of the file. Gated builtins: <code>load_safetensors</code>/<code>load_gguf</code> need <code>ai</code>, <code>llm_load</code> needs <code>llm</code>, <code>tcp_listen</code>/<code>tcp_connect</code> need <code>net</code>, and <code>load_lib</code> needs <code>c</code>. The legacy <code>rinne.log(...)</code> prefix stays available without imports.</p><p class="docback"><a href="api.html">← Full API reference</a> · <a href="index.html">Home</a></p></section><section class="chapter" id="tensor"><h1>Tensors</h1><h1 id="tensor--n-dimensional-arrays-with-simd-kernels">tensor — n-dimensional arrays with SIMD kernels</h1><p>Tensors are contiguous, row-major, CPU-resident arrays with typed elements.</p><h2 id="construction">Construction</h2><pre class="rinne"><code>@import = .{ std };const t = @tensor(f32, [2, 3], .{ .device = .cpu, .fill = 1.5 });</code></pre><ul><li>First argument: element dtype (<code>f32</code>, <code>f64</code>, <code>i32</code>, <code>i64</code>, <code>u8</code>, <code>bool</code>).</li><li>Second: shape array (1..8 dimensions, positive).</li><li>Optional options struct:<ul><li><code>.device = .cpu</code> (default). <code>.cuda</code> / <code>.rocm</code> are <strong>not available in v1</strong> and fail at runtime with a clear degrade error.</li><li><code>.fill = value</code> — initialize every element (coerced to the dtype).</li></ul></li></ul><h2 id="methods-and-indexing">Methods and indexing</h2><table><thead><tr><th>Method</th><th>Returns / effect</th></tr></thead><tbody><tr><td><code>t.shape()</code></td><td>array of dimension sizes</td></tr><tr><td><code>t.numel()</code></td><td>total element count</td></tr><tr><td><code>t.dtype()</code></td><td>dtype name string</td></tr><tr><td><code>t.fill(v)</code></td><td>overwrite every element with <code>v</code></td></tr><tr><td><code>t.data()</code></td><td>copy-out as a plain array</td></tr><tr><td><code>t[i]</code>, <code>t[i] = v</code></td><td>linear indexing (row-major order)</td></tr><tr><td><code>t.deinit()</code></td><td>free the tensor; idempotent, further use is an error</td></tr></tbody></table><pre class="rinne"><code>@import = .{ std };const t = @tensor(f32, [6], .{ .device = .cpu, .fill = -1.5 });std.print("{} {} {}\n", .{t.shape(), t.numel(), t.dtype()});</code></pre><blockquote><p><strong>Note:</strong> <code>defer t.deinit()</code> does <strong>not</strong> work in v1 — deferred blocks cannot see enclosing locals. Call <code>deinit()</code> explicitly before returning.</p></blockquote><h2 id="apply_simd--element-wise-kernels">apply_simd — element-wise kernels</h2><p>Anonymous function literals are only allowed as the kernel of <code>apply_simd</code>. The kernel runs once per element; the parameter annotation <code>@vector(N, T)</code> is a lane-width hint for the future native backend (the VM interprets it scalar-wise today; tails are padded automatically):</p><p><code>apply_simd</code> transforms the tensor <strong>in place</strong> (the kernel's return value is written back to each element) and returns nothing:</p><pre class="rinne"><code>@import = .{ std };t.apply_simd(fn(x: @vector(8, f32)) f32 { if x < 0.0 { return 0.0; } return x;});// t now holds the ReLU'd values</code></pre><h2 id="native-backend">Native backend</h2><p>The C11 codegen path (<code>rinne build</code>) rejects tensors, method calls, kernels, and the ai/llm builtins with explicit errors — they are VM-only features.</p><h2 id="runnable-example">Runnable example</h2><pre class="rinne"><code>@import = .{ std };
pub fn main() int { const t = @tensor(f32, [6], .{ .device = .cpu, .fill = -1.5 }); t[1] = 2.0; t[3] = 4.25; t.apply_simd(fn(x: @vector(8, f32)) f32 { if x < 0.0 { return 0.0; } return x; }); std.print("relu={}\n", .{t.data()}); t.deinit(); return 0;}</code></pre><p class="docback"><a href="api.html">← Full API reference</a> · <a href="index.html">Home</a></p></section><section class="chapter" id="ai"><h1>AI Models</h1><h1 id="ai--zero-copy-model-file-readers">ai — zero-copy model file readers</h1><p>The <code>ai</code> namespace loads weight files as <strong>read-only tensor views</strong> over a memory-mapped file — no data is copied, load time is O(header parse).</p><pre class="rinne"><code>@import = .{ std, ai };</code></pre><h2 id="loading">Loading</h2><pre class="rinne"><code>@import = .{ ai };const ts = ai.load_safetensors("model.safetensors");const gs = ai.load_gguf("model.gguf");</code></pre><p>Both return an <strong>array of tensors</strong>. Each element supports:</p><table><thead><tr><th>Field / method</th><th>Meaning</th></tr></thead><tbody><tr><td><code>.name</code></td><td>tensor name from the file header</td></tr><tr><td><code>.shape()</code></td><td>dimension array</td></tr><tr><td><code>.dtype()</code></td><td>dtype name (<code>f32</code>, <code>i32</code>, ...)</td></tr><tr><td><code>.data()</code></td><td>copy-out as a plain array</td></tr><tr><td><code>t[i]</code></td><td>linear element read (read-only)</td></tr><tr><td><code>t.fill(v)</code></td><td><strong>rejected</strong> — mapped memory is immutable</td></tr><tr><td><code>t.deinit()</code></td><td>release this view's reference</td></tr></tbody></table><h2 id="format-support">Format support</h2><ul><li><strong>SafeTensors</strong>: standard 8-byte header + JSON + aligned blob.</li><li><strong>GGUF</strong>: versions 2 and 3, alignment via <code>general.alignment</code> (default 32).</li><li>dtypes: <code>F32</code>, <code>F64</code>, <code>I32</code>, <code>I64</code> only (quantized formats are future work).</li><li>Hostile headers are bounded: header size ≤ 64 MiB, tensor count ≤ 1M, overflow-checked offsets.</li><li>Windows: mmap loaders report a clear unsupported-platform error.</li></ul><h2 id="runnable-example">Runnable example</h2><p>Build a fixture with any safetensors writer (python: <code>safetensors.numpy.save_file</code>), then:</p><pre class="rinne"><code>@import = .{ std, ai };
pub fn main() int { const ts = ai.load_safetensors("/tmp/opencode/rg/m4_fix.safetensors"); const w = ts[0]; std.print("{} {} {}\n", .{w.name, w.shape(), w.dtype()}); std.print("data={}\n", .{w.data()}); return 0;}</code></pre><h2 id="more-examples">More examples</h2><p>See <code>examples/ai_demo.rg</code> — loads a SafeTensors file and a GGUF model, iterating the returned tensor views.</p><p class="docback"><a href="api.html">← Full API reference</a> · <a href="index.html">Home</a></p></section><section class="chapter" id="llm"><h1>LLM Inference</h1><h1 id="llm--transformer-inference-on-the-cpu">llm — transformer inference on the CPU</h1><p><code>llm_load(path)</code> opens a GGUF model file (zero-copy, F32 weights) and gives you a decoder-only transformer you can run forward passes on. The architecture follows llama2.c: RMSNorm → RoPE → grouped-query attention with KV cache → SwiGLU MLP.</p><pre class="rinne"><code>@import = .{ llm };const m = llm_load("/models/tiny.rguf");</code></pre><h2 id="gguf-convention">GGUF convention</h2><p>RinneScript reads its own metadata keys and tensor names — a documented, self-contained convention so models can be exported from any training pipeline without depending on llama.cpp's name mapping.</p><p><strong>Metadata (integer kvs):</strong></p><table><thead><tr><th>Key</th><th>Meaning</th></tr></thead><tbody><tr><td><code>rinne.llm.dim</code></td><td>model width</td></tr><tr><td><code>rinne.llm.hidden_dim</code></td><td>MLP hidden width</td></tr><tr><td><code>rinne.llm.n_layers</code></td><td>transformer blocks</td></tr><tr><td><code>rinne.llm.n_heads</code></td><td>attention heads</td></tr><tr><td><code>rinne.llm.n_kv_heads</code></td><td>KV heads (GQA; ≤ n_heads)</td></tr><tr><td><code>rinne.llm.vocab_size</code></td><td>vocabulary size</td></tr><tr><td><code>rinne.llm.seq_len</code></td><td>maximum sequence length</td></tr></tbody></table><p><strong>Tensors (all must be F32):</strong></p><pre><code>tok_embd [vocab, dim]output_norm [dim]output [vocab, dim]blk.{i}.attn_norm [dim]blk.{i}.attn_q [dim, dim] blk.{i}.ffn_norm [dim]blk.{i}.attn_k [kv_dim, dim] blk.{i}.ffn_gate [hidden, dim]blk.{i}.attn_v [kv_dim, dim] blk.{i}.ffn_down [dim, hidden]blk.{i}.attn_o [dim, dim] blk.{i}.ffn_up [hidden, dim]</code></pre><p>Missing keys or mismatched shapes fail with an error pointing at <code>docs/libs/llm.md</code>.</p><h2 id="methods">Methods</h2><table><thead><tr><th>Method</th><th>Effect</th></tr></thead><tbody><tr><td><code>m.forward(ids)</code></td><td>run token ids through the network; returns the <strong>last-token logits</strong> as an f32 array of length <code>vocab_size</code>. Ids must be ints in <code>[0, vocab_size)</code>; at most <code>seq_len</code> of them. The KV cache resets each call.</td></tr><tr><td><code>m.deinit()</code></td><td>free the model; idempotent, further use is an error</td></tr></tbody></table><h2 id="tokenizer-note">Tokenizer note</h2><p>Text-level generation needs a tokenizer, which is <strong>future work</strong> — v1 exposes token-id-level forward passes. Feed ids from your own tokenizer and pick <code>argmax(logits)</code> for greedy sampling.</p><h2 id="runnable-example">Runnable example</h2><p>A deterministic test model can be produced by the test-suite fixture builder; real models come from training pipelines:</p><pre class="rinne"><code>@import = .{ llm };pub fn main() int { const m = llm_load("/tmp/opencode/rg/m7_fix.gguf"); std.print("{}\n", .{m}); const lg = m.forward(.{0, 1}); std.print("logits({}) = {}\n", .{len(lg), lg}); m.deinit(); return 0;}</code></pre><h2 id="more-examples">More examples</h2><p>See <code>examples/llm_demo.rg</code> — loads a GGUF transformer and runs a forward pass.</p><p class="docback"><a href="api.html">← Full API reference</a> · <a href="index.html">Home</a></p></section><section class="chapter" id="pkg"><h1>Marketplace (@fetch)</h1><h1 id="pkg--the-fetch-package-system">pkg — the @fetch package system</h1><p><code>@fetch</code> downloads versioned dependencies at <strong>compile time</strong> (it is a module-level directive, resolved before compilation — never inside function bodies) and splices their functions into your program.</p><pre class="rinne"><code>@import = .{ std };@fetch("https://example.com/math.rg");@fetch("github.com/user/lib", .{ .version = "v1.2.0" });</code></pre><h2 id="accepted-targets">Accepted targets</h2><table><thead><tr><th>Form</th><th>Behavior</th></tr></thead><tbody><tr><td><code>https://.../pkg.rg</code></td><td>direct source file</td></tr><tr><td><code>http(s)://.../pkg.tar.gz</code> / <code>.tgz</code></td><td>archive; entry = <code>main.rg</code>, or the only <code>*.rg</code></td></tr><tr><td><code>github.com/u/r</code> / <code>gitlab.com/g/sub/r</code> / <code>codeberg.org/u/r</code></td><td>repo shorthand — <strong>requires</strong> <code>.version</code>; rewritten to the host's tag archive URL</td></tr></tbody></table><p>Options struct:</p><ul><li><code>.version = "v1.2.0"</code> — required for shorthands, optional (but recommended) for direct URLs; it also keys the cache.</li><li><code>.sha256 = "<64 hex>"</code> — pin content; mismatch aborts with both digests printed.</li></ul><h2 id="caching--offline-mode">Caching & offline mode</h2><ul><li>Cache root: <code>$RINNE_CACHE_HOME</code> else <code>$HOME/.cache/rinne/pkg</code>.</li><li>Each package lands in a content-keyed directory with a <code>manifest.json</code> (<code>url</code>, <code>version</code>, <code>final_url</code>, <code>entry</code>, <code>sha256</code>). Repeat builds are pure cache hits.</li><li><code>RINNE_OFFLINE=1</code> refuses uncached packages instead of hitting the network.</li></ul><h2 id="rules">Rules</h2><ul><li>Package files may contain <strong>only function declarations</strong> (no global statements, no nested <code>@fetch</code>).</li><li>Name collisions are reported as <code>'<name>' ... conflicts</code> naming both sides.</li><li>The old spelling is retired:</li></ul><pre><code>@import = .{ std };compile error: '@fetch_pkg' was renamed to '@fetch'</code></pre><h2 id="runnable-example">Runnable example</h2><p>Serve a file locally to try it without touching the network:</p><div class="sourceCode" id="cb3"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="fu">mkdir</span> <span class="at">-p</span> /tmp/mysrv <span class="kw">&&</span> <span class="bu">printf</span> <span class="st">'fn add(a: int, b: int) int {\n return a + b;\n}\n'</span> <span class="op">></span> /tmp/mysrv/util.rg</span><span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">(</span><span class="bu">cd</span> /tmp/mysrv <span class="kw">&&</span> <span class="ex">python3</span> <span class="at">-m</span> http.server 8901 <span class="kw">&)</span></span></code></pre></div><pre class="rinne"><code>@import = .{ std };@fetch("http://127.0.0.1:8901/util.rg", .{ .version = "v1", .sha256 = "..." });
pub fn main() int { std.print("{}\n", .{add(2, 3)}); return 0;}</code></pre><h2 id="more-examples">More examples</h2><p>See <code>examples/pkg_demo.rg</code> — fetches a package from a local server and calls into it.</p><p class="docback"><a href="api.html">← Full API reference</a> · <a href="index.html">Home</a></p></section><section class="chapter" id="net"><h1>Networking</h1><h1 id="net--tcp-clientserver-builtins">net — TCP client/server builtins</h1><p>Blocking, cross-platform TCP over the runtime's Io engine.</p><h2 id="listening">Listening</h2><pre class="rinne"><code>@import = .{ net };const l = tcp_listen(0); // port 0 = ephemeral; pick with l.port()std.print("listening on {}\n", .{l.port()});</code></pre><table><thead><tr><th>Listener method</th><th>Effect</th></tr></thead><tbody><tr><td><code>l.port()</code></td><td>bound port (resolves ephemeral port 0)</td></tr><tr><td><code>l.accept()</code></td><td>block until a client arrives → stream</td></tr><tr><td><code>l.close()</code></td><td>stop listening</td></tr></tbody></table><h2 id="connecting">Connecting</h2><pre class="rinne"><code>@import = .{ net };const c = tcp_connect("127.0.0.1", 8080);</code></pre><h2 id="streams">Streams</h2><table><thead><tr><th>Stream method</th><th>Effect</th></tr></thead><tbody><tr><td><code>s.read(max)</code></td><td>up to <code>max</code> bytes as a string; <strong>returns early at EOF</strong>, otherwise waits for bytes</td></tr><tr><td><code>s.write(data)</code></td><td>send a string (flushed before returning); returns length</td></tr><tr><td><code>s.shutdown(how)</code></td><td>half-close; <code>how</code> = <code>"send"</code>, <code>"recv"</code>, <code>"both"</code> (default <code>"send"</code>)</td></tr><tr><td><code>s.close()</code></td><td>close the socket</td></tr></tbody></table><blockquote><p><strong>Message framing:</strong> on blocking platforms <code>read(max)</code> cannot know where your message ends. Half-close the sender (<code>c.shutdown()</code>) after writing a complete message — the peer's <code>read</code> then returns immediately at EOF while the reverse direction stays open for the reply.</p></blockquote><p>Errors surface as runtime errors: cannot listen / cannot resolve host / cannot connect / accept failed / read or write failed.</p><h2 id="runnable-example-both-roles-in-one-script">Runnable example (both roles in one script)</h2><pre class="rinne"><code>@import = .{ std };
pub fn main() int { const l = tcp_listen(0); const p = l.port(); std.print("listening on 127.0.0.1:{}\n", .{p});
const c = tcp_connect("127.0.0.1", p); c.write("ping"); c.shutdown();
const s = l.accept(); const got = s.read(64); std.print("server got: {}\n", .{got});
s.write("pong"); s.shutdown(); const back = c.read(64); std.print("client got: {}\n", .{back});
c.close(); s.close(); l.close(); return 0;}</code></pre><h2 id="more-examples">More examples</h2><p>See <code>examples/net_demo.rg</code> — dual-role TCP loopback echo with half-close framing.</p><p class="docback"><a href="api.html">← Full API reference</a> · <a href="index.html">Home</a></p></section><section class="chapter" id="c"><h1>C FFI</h1><h1 id="c--calling-shared-libraries-ffi">c — calling shared libraries (FFI)</h1><p>RinneScript v1 talks to C through <code>dlopen</code>/<code>dlsym</code> — no C compiler, no headers, no generated bindings:</p><pre class="rinne"><code>@import = .{ c };const libc = load_lib("libc.so.6"); // soname: resolved by the // system dynamic loaderconst m = load_lib("/lib64/libm.so.6"); // full paths work too
libc.call_int("abs", .{-42}); // → 42m.call_float("fabs", .{-2.5}); // → 2.5
libc.deinit();m.deinit();</code></pre><h2 id="api">API</h2><table><thead><tr><th>Call</th><th>Meaning</th></tr></thead><tbody><tr><td><code>load_lib(path)</code></td><td>open a shared library (<code>RTLD_NOW</code>). Sonames like <code>libc.so.6</code> resolve through the normal loader search path; absolute paths are equally fine.</td></tr><tr><td><code>lib.call_int(sym, args)</code></td><td>call a C function returning <code>long long</code>; 0..4 integer arguments</td></tr><tr><td><code>lib.call_float(sym, args)</code></td><td>call a C function returning <code>double</code>; 0..4 numeric arguments</td></tr><tr><td><code>lib.deinit()</code></td><td>close the library (<code>dlclose</code>); idempotent</td></tr></tbody></table><p>Missing symbols fail with <code>library '...' has no symbol '...' with the expected C signature</code>; use after <code>deinit</code> fails with <code>use of deinitialized library</code>.</p><h2 id="notes--limits">Notes & limits</h2><ul><li>Integer args only for <code>call_int</code>, numerics for <code>call_float</code> — no pointers, strings, or structs in v1.</li><li>Know where your symbols live: <code>abs</code> is in <strong>libc</strong>, <code>fabs</code> in <strong>libm</strong>.</li><li>POSIX-focused; Windows loader support is future work.</li></ul><h2 id="import_c-native-backend-status">@import_c (native backend) status</h2><p><code>@import_c</code> — declaring C headers for the native C11 codegen path — remains <strong>gated</strong> in v1 by design: it requires full C declaration parsing in the emitter. The dlopen-based <code>load_lib</code> surface above is the supported way to reach C from RinneScript scripts.</p><h2 id="runnable-example">Runnable example</h2><pre class="rinne"><code>@import = .{ std };
pub fn main() int { const libc = load_lib("libc.so.6"); std.print("abs(-42)={}\n", .{libc.call_int("abs", .{-42})}); libc.deinit(); return 0;}</code></pre><h2 id="more-examples">More examples</h2><p>See <code>examples/c_demo.rg</code> — calls abs from libc and fabs from libm via dlopen.</p><p class="docback"><a href="api.html">← Full API reference</a> · <a href="index.html">Home</a></p></section></div></div></main><footer><div class="wrap">RinneScript — write scripts, ship native binaries. Hand-built site, vanilla JS only.</div></footer></body></html>