Rak

Rak README.md

35.2 KB 923 lines Raw ↗ GitHub ↗

# RakA programming language for hackers, OSINT investigators, and systems programmers. Build desktop GUI apps, backend SQL servers, shareable packages, and self-host the compiler. All in Rak.Hex is a first-class type. The bytecode VM runs about 6x faster than the tree-walker. There's a SQL engine written in Rak itself, and a Rak interpreter written in Rak.## What's new in 0.7.2- **DAP debugger server** — `rakc dap <file>` speaks the Debug Adapter  Protocol over stdio (Content-Length framing). The VM runs the target on a  worker thread while a reader handles requests: `setBreakpoints`/`remove`,  `continue`, `next`, `stepIn`, `stepOut`, `stackTrace`, `scopes`/`variables`,  `setVariable`, and full `exceptionInfo` — line-granular breakpoint gating via  a `last-hit-line` guard. Wire it up from VS Code (the bundled `rak`  extension), Neovim (nvim-dap), or any DAP client.- **Stdlib batteries** — everyday data modules on both backends: time &  datetime (`time_now`, `time_fmt`, `time_parse`, `time_parts`, `time_add`,  `time_diff`, `date_today`), randomness (`rand_seed`, `rand_int`,  `rand_float`, `rand_bytes`, `rand_hex`, `rand_choice`, `rand_shuffle`), CSV  (`csv_parse`, `csv_stringify`), YAML (`yaml_parse`), and archives  (`gzip_compress`, `gzip_decompress`, `zip_list`, `zip_read`, `zip_write`).- **OSINT pack** — WHOIS lookups and parsing (`whois_lookup`/`whois_parse`),  certificate-transparency subdomain enumeration (`ct_subdomains`), a  hand-rolled **YARA-lite** scanning engine (`yara_scan`: hex wildcards,  `nocase`, `at`/`in`, `all-of`/`any-of`/`none-of`, boolean conditions), and  Markdown evidence reports (`report_markdown`). Docs: `docs/content/osint.md`,  demo: `examples/osint_demo.rak`.- **Language core: `in` operator** — membership checks work on strings  (substring/char), arrays, tuples, maps (key lookup), and byte sequences.- **Destructuring `let`** — `let (a, b) = pair`, `let [x, y, z] = list`,  `let Point { x, y } = obj`, nested and `let mut` forms; arity mismatches  raise a catchable error.- **Slice and negative indexing** — `a[1..3]`, `a[..2]`, `a[3..]`, `a[-2..]`  slices, `a[-1]` reads and `a[-1] = v` writes from the end, with  out-of-bounds raises on both backends.- **The VM caught up.** `rakc vm` now runs what the interpreter runs:  `try`/`catch` and `expr?` (structured errors, LIFO defers before the  handler), method dispatch on structs/enums (`obj.method(...)` via `impl`  blocks), struct literals and enum constructors, and the full pattern  language in `match` — struct patterns (`Point { x, y }`), enum variants,  binary bytes patterns, or-patterns, ranges, `Some`/`None`/`Ok`/`Err`, and  guards.- **Operator overloading** — `impl Add/Sub/Mul/Div/Rem/Eq/Compare/Neg for T`  with `fn add(self, o)`-style methods, dispatched on both backends before  the built-in arithmetic (`a + b`, `a == b`, `a < b`, `-a` on your types).- **Assignment on the VM** — `arr[i] = v`, `map[k] = v`, `s.field = v`,  `x += 1`, and multi-assign `a, b = x, y` (copy-on-write, mutability rules  enforced).- **Iterator builtins** — `zip`, `enumerate`, `skip`, `fold`, `reduce`,  `any`, `all`, `flat_map`, `take_while`, plus `keys`/`values`/`has`/`get`,  on both backends.- **`for (k, v) in map`** and indexed `for (i, x) in arr` work on the VM  (`Op::IterItems` materializes any iterable; maps always yield pairs).- **`if let` / `while let` / `do { } while` / labeled `break`/`continue`**  (`'outer: for ... { break 'outer }`) run on the VM.- **binstruct bitfields** — `u4`-style non-byte-aligned fields, packed  LSB-first and round-tripped through `decode`/`encode` on both backends.- **`rakc fmt`** — AST-based formatter (`--write`, `--check` for CI).- **`rakc lint`** — advisory checks (unused vars, shadowing, unreachable  code, missing `pub fn` return types, duplicate imports; `--deny` for CI).## InstallThe custom installer is an interactive TUI wizard that installs `rakc`, `rakpkg`, and the Rak IDE, edits PATH, sets `RAK_PATH`, creates shortcuts + `.rak` associations, and installs man pages + shell completions. It runs in net-install (downloads the latest release) or offline-bundle mode, and supports `--uninstall` / `--list` / `--yes` for scripting.**Linux:**```bashcurl -fsSL https://raw.githubusercontent.com/Louiml/Rak/main/dist/install.sh | bash# non-interactive:curl -fsSL https://raw.githubusercontent.com/Louiml/Rak/main/dist/install.sh | bash -s -- --yes --install rakc,rakpkg,ide --scope user```**Windows (PowerShell):**```powershelliwr -useb https://raw.githubusercontent.com/Louiml/Rak/main/dist/install.ps1 | iex```Or download the setup binary directly from the [latest release](https://github.com/Louiml/Rak/releases/latest) (`rak-setup-linux-x86_64` or `rak-setup-windows-x86_64.exe`) and run it.Menu items: `rakc → bin + PATH`, `rakpkg → bin + PATH`, `IDE → portable dir / system location`, `Set RAK_PATH`, `Shortcuts + .rak association`, `Man pages + shell completions`. Install scope: `user` (default, no privileges) or `system`. A `~/.rak/manifest.json` records every action for clean uninstall/upgrade.The Tauri installers (NSIS/MSI on Windows, `.deb`/AppImage on Linux) remain on the release page for IDE-only users who want the OS-native installer.## Quick start```rakdump "Hello, World"``````rakscan "127.0.0.1" {    range: [0x0016, 0x0050]} {    if open {        dump fmt("Port 0x{:04X}", port)    }}```## What you getThe language started as an OSINT scripting tool. It grew into something bigger.**Forensic Structs & evidence provenance.** Declare a binary wire format once with `binstruct` and get both a decoder and an encoder for free (round-trip). Every decoded value is wrapped in an `evidence<T>` provenance tag carrying where/when/how it was collected, so `report(...)` emits a chain-of-custody-cited findings report. No other language bakes provenance into the value model — this only makes sense in a hex-first, OSINT-first language.**Bytecode VM.** `rakc vm` runs bytecode. Benchmarks show about 6x speedup over the tree-walking interpreter. Run `rakc bench file.rak` to see both.**Data pipelines.** A `|>` pipeline operator, regex literals (`/\d+/g`) with method syntax, and binary pattern matching over byte slices — built for OSINT log and PCAP triage.**Type system.** Signed and unsigned ints (i8 through u64), floats (f32, f64),typed literals like `42i32` and `3.14f64`, a first-class `char`, base literals(`0b1010`/`0o755`/`0xFF`), tuples, Result/Option, modules, closures with lexicalscoping, generics, traits with method dispatch, pattern matching (includingbinary byte-pattern matching, plus user enum variants), and string interpolationwith `f"hello {name}"`. A static type checker behind `rakc check` catches badannotations and non-exhaustive matches before you run anything.**Concurrency.** `spawn` launches a thread, `thread_join` waits for it, `channel()` gives you a sender/receiver pair. TCP networking built in with `net_listen`, `net_accept`, `tcp_read`, `tcp_write`. Async I/O via a Tokio runtime: `async fn`/`await`, `http_get_async`, `tcp_probe`.**SQL server in Rak.** A full SQL engine, lexer through executor, written in the language itself. It serves queries over TCP. See `examples/sql_server.rak`.**Self-hosting.** `examples/self_host.rak` is a Rak interpreter written in Rak. It lexes, parses, and evaluates real Rak source code.**Error handling.** `try`/`catch`/`raise`, the `?` operator, Result and Option types. Lexer and parser errors report line and column. `rakc check file.rak` prints diagnostics in the format IDEs expect.**Lexical closures.** Free variables resolve at the definition site, not the call site. Recursive closures like `let f = fn(n) { if n < 2 { return n } return f(n-1) + f(n-2) }` just work.**Real JSON.** `json_parse` returns native arrays, maps, ints, floats, bools, nil. `json_stringify` serializes back to a string. No more hand-rolling JSON in your SQL server.**Build standalone executables.** `rakc build file.rak` produces a self-contained binary with the source embedded. On Windows it's a `.exe`. On Linux it gets `chmod 755`. No Rak installation needed on the target machine.**GUI windows (incomplete).** With `--features gui`, Rak scripts can open a native desktop window rendering HTML, CSS, and JS via WebView2 on Windows. Treat it as a display-only preview: `gui_update`/`gui_title`/`gui_close` do not affect the window yet, JavaScript cannot call back into Rak, closing the window ends the process, and Linux does not work. See [GUI windows](#gui-windows).**Package manager.** `rakpkg` is a CLI for Git-based shareable Rak packages. Initialize, add dependencies from GitHub repos, install, run, and build. The manifest is a Rak file with `let` bindings.**Foreign Function Interface (FFI).** Call native C functions in `.so`/`.dll`/`.dylib` libraries. Declare bindings with `extern "C" { ... }` (resolved against the platform default C library, or an explicit `from "path"`) or load dynamically with `ffi_load` and `lib.call`. Marshal raw memory with `ffi_alloc`/`ffi_write`/`ffi_read`/`ffi_cstr_to_string`/`ffi_string_to_cstr`/`ffi_free`. Works on both the interpreter and the bytecode VM.```rakextern "C" {    fn abs(n: i32) -> i32}dump abs(-42)                    // 42let libc = ffi_load("libc.so.6") // or "ucrtbase.dll" / "libSystem.dylib"dump libc.call("abs", [-9])      // 9libc.close()let buf = ffi_alloc(4)ffi_write(buf, 0, 0x41)dump ffi_cstr_to_string(buf)     // "A"ffi_free(buf)```**Memory-mapped files.** Map huge PCAP / log files into memory and inspect them zero-copy. `mmap_open` maps a file; `mmap_slice` returns a view that keeps the mapping alive and reads directly from the mapped pages. Single-byte indexing, byte search, and line scanning work on both the interpreter and the bytecode VM; range slicing and binary pattern matching over slices work on the interpreter.```raklet m = mmap_open("trace.pcap", "r")dump mmap_size(m)let hdr = mmap_slice(m, 0, 8)dump hdr[0]                       // first byte (zero-copy)dump mmap_find(m, "\xff\xd8\xff") // byte search -> offsetfor (off, len) in mmap_lines_off(m, "\n") {    dump string(mmap_slice(m, off, len))}```**Async event loop.** `async fn`, `await`, and Tokio-backed async I/O. `http_get_async` / `tcp_probe` / `tcp_connect_async` run on a lazily-started multi-thread Tokio runtime and return a `Future`; `await` blocks until it resolves. Works on both the interpreter (deferred `async fn` bodies) and the bytecode VM (`Op::Await`).```rakasync fn probe(host, port) {    let open = await tcp_probe(host, port, 200)    return open}dump await probe("127.0.0.1", 80)let body = await http_get_async("https://example.com")dump string(body)```**Raw sockets & packet forging.** Build IPv4/TCP/UDP headers with correct ones-complement checksums and send them on a raw socket. The packet builders are pure computation and run anywhere; `net_raw_send`/`recv` need `CAP_NET_RAW`/Administrator (unix) and return a `Result`.```raklet pkt = net_raw_tcp_syn("10.0.0.5", "10.0.0.10", 12345, 80)dump len(pkt)          // 40 bytesdump pkt[0]            // 0x45 (IPv4)dump pkt[33]           // 0x02 (SYN flag)dump net_raw_send(pkt) // Ok(40) on a privileged unix box, Err(...) otherwise```**Protocol parsers (DNS / TLS / PCAP).** Hand-rolled DNS wire-format builder/parser + UDP query (no external DNS crate — works air-gapped). TLS ClientHello SNI extraction and DER cert-chain parsing via `x509-parser`. PCAP offline capture behind the `pcap` cargo feature (libpcap/Npcap). All return `Result`s so they degrade gracefully offline / without the feature.```rakdump dns_query("example.com", "A")      // Ok({answers: [{name, type, ttl, rdata}, ...], truncated})let q = dns_build("example.com", "A")   // raw query bytes (offline)let info = tls_parse_client_hello(bytes) // {sni, ciphers}let certs = tls_parse_cert_chain(der)    // [{subject, issuer}, ...]dump pcap_open("capture.pcap")           // Ok(<pcap>) or Err(...)```**Compile-time macros.** `macro name($params) { body }` defines an AST-expanding template; `name!(args)` splices the argument expressions into the body's `$param` placeholders before evaluation. Expanded in the frontend, so both backends see the expanded code. `const NAME = expr` binds a compile-time constant.```rakmacro add1(x: expr) { $x + 1 }dump add1!(41)            // 42macro pair(a: expr, b: expr) { [$a, $b] }dump pair!(1, 2)          // [1, 2]const MAX_LEN = 256dump MAX_LEN```## Forensic Structs & evidence provenanceA declarative wire-format DSL (`binstruct`) plus a provenance-typed value(`evidence<T>`) — the OSINT differentiator. Declare a binary layout once andget both a **decoder** and an **encoder** for free (round-trip); every decodedvalue is wrapped in an evidence tag carrying where/when/how it was collected, so`report(...)` emits a chain-of-custody-cited findings report. No other languagebakes provenance into the value model — this only makes sense in a hex-first,OSINT-first language.```rakbinstruct DnsHeader {    id:      u16be    flags:   u16be    qdcount: u16be    ancount: u16be    nscount: u16be    arcount: u16be}let q = dns_build("example.com", "A")let h = DnsHeader.decode(q)        // -> evidence<struct> with provenancedump h.id                          // 0x1234dump h.qdcount                     // 1let back = DnsHeader.encode(h)     // round-trip back to bytes```Field types: `u8`/`u16`/`u32`/`u64` and signed `i8`..`i64`, each with an optional`be`/`le` endianness suffix (default big-endian); `bytes(n)` for a fixed run ofraw bytes; `rest` for the trailing remainder; and a nested binstruct name for a`Ref` field. Works on both the interpreter and the bytecode VM (compile-timecodegen to per-struct native-fn globals — no new VM opcodes).Evidence provenance:```raklet ip = evidence<string> from "93.184.216.34"          // root taglet answers = cite(dns_query("example.com", "A"), "dns_query", "example.com")dump report(ip, answers)   // numbered assertions + cited sources (tool/target/ts)dump provenance(ip)        // {tool, target, ts, raw_offset, raw_len, parent}dump strip_evidence(ip)    // 93.184.216.34```- `evidence<T> from expr` — wrap a value in a root provenance tag.- `cite(value, tool?, target?)` — wrap a value, chaining `parent` to any  existing evidence so provenance merges transitively.- `report(evidence, ...)` — render a Markdown-style report with numbered,  source-cited assertions (the chain-of-custody output an investigator needs).- `provenance(value)` — the provenance chain as a map.- `strip_evidence(value)` — drop the provenance wrapper, return the inner value.Field access and indexing transparently unwrap evidence, so`evidence<struct>.field` reads through to the inner struct.## Build a standalone executable```bashrakc build examples/hello.rak   # produces hello.exe on Windows, hello on Linux./hello                          # [DUMP] Hello, World```## GUI windowsIncomplete in 8.0.0. Requires `cargo build -p rakc --features gui`.```raklet html = "<h1 style='color:#22c55e;text-align:center;margin-top:40px'>Hello from Rak!</h1>"let win = gui_open("Rak GUI Demo", html, 600, 400)gui_wait()````gui_open` returns a window ID and `gui_wait()` blocks. That is all thatcurrently works. Specifically:- `gui_update`, `gui_title`, `gui_close` are declared but do nothing yet.  `gui.rs` stores `HashMap<i64, ()>` and throws away the `Window` and `WebView`  handles, so there is nothing to update.- `gui_callback` and `window.rak_call(fn, args)` do not work. The IPC handler  receives the message and discards it, so JavaScript cannot call into Rak yet.- Closing the window ends the process, because tao's `run` calls  `process::exit` when the last window closes. `gui_wait()` does not return and  code after it is unreachable.- Linux does not work: `gui_open` builds the event loop on a spawned thread,  which trips tao's main-thread assertion.- The VM has no GUI natives; use `rakc run`.Windows only, display only. The rewrite that fixes all of the above is trackedin `docs/V8-ROADMAP.md`.## Package manager```bashrakpkg init mylib           # creates package.rak + lib.rakrakpkg add user/repo        # git clone into .rak/packages/rakpkg install              # install all deps from package.rakrakpkg run                  # run the entry point via rakc runrakpkg build                # build to standalone executable via rakc buildrakpkg list                 # list installed packagesrakpkg remove mylib         # remove a package```The manifest is a Rak file:```raklet name = "mylib"let version = "0.1.0"let deps = { net: "user/rak-net", crypto: "user/rak-crypto" }let entry = "lib.rak"```Import installed packages by file path or by name (Python-style). See theImports & exports section below for the full syntax.```rakuse "./packages/mylib/lib.rak"   // file-path (back-compat)import mylib                     // name -> searches dir, ./packages/, RAK_PATH```## Imports & exportsRak has a Python-style module system with explicit `pub`/`export`, name-basedresolution, `from ... import`, directory packages, import-once caching, andcircular-import support. Works on both the interpreter and the bytecode VM.```rak// Whole-module import (binds the module; access via m.x)import "./math.rak"          // file path -> binds "math"import math                  // name: searches dir, ./packages/, RAK_PATH for math.rakimport math as m             // aliasuse math                     // back-compat: same as import// from-import (binds names directly)from math import addfrom math import add as plus, mul as timesfrom math import *           // all exports; local bindings win on clash// Directory packages: `import pkg` runs pkg/init.rak; `import pkg.sub`// runs pkg/init.rak + pkg/sub.rak (interpreter; use `from pkg.sub import x`// on the VM).import pkgimport pkg.sub// Exports — both `pub` and `export` mark an item as exported (let/fn/const/// struct/enum/macro):pub let PI = 3.14export fn add(a, b) { return a + b }pub const MAX = 256// Re-exportspub use math                 // re-export all of math from this modulepub use {add, mul} from math // re-export named```Module resolution for a name `m`: the importing file's directory, then`./packages/`, then the `RAK_PATH` env var (`;` on Windows, `:` on Unix),trying `m.rak` then `m/init.rak`. Modules are imported once (cached); acircular import returns the partially-initialized module (Python semantics).## SQL server```bashrakc run examples/sql_server.rak   # listens on 127.0.0.1:18393rakc run examples/sql_client.rak    # CREATE, INSERT, SELECT, UPDATE, DELETE```The engine supports CREATE TABLE, INSERT, SELECT with WHERE and column projection, UPDATE, DELETE, and DROP. Storage is file-backed with a simple line format. The server handles each connection inline, parsing SQL and returning JSON.## Self-hosting```bashrakc run examples/self_host.rak    # a Rak interpreter written in Rak```It reads Rak source, lexes it, parses it, and evaluates it. The output of `1 + 2 * 3` is 7. The output of `let x = 5; let y = 7; dump x * y - 1` is 34.## Language syntax### Variables```raklet target = "192.168.1.1"let port = 0x0050let mut counter = 0counter = counter + 1let pi = 3.14f64let n = 42i32```### Functions```rakfn add(a, b) {    return a + b}dump add(0x10, 0x20)```### Control flow```rakif port == 0x0050 {    dump "HTTP"} else {    dump "Other"}for x in [1, 2, 3] { dump x }while counter < 0x0A { counter = counter + 1 }loop { break }```### Hex arithmetic```raklet sig = 0xDEADBEEFlet mask = 0xFF00FF00dump fmt("0x{:08X}", sig & mask)```### Error handling```raklet v = Ok(42)?     // unwrap, propagate Errtry {    raise "boom"} catch e {    dump e}```### String interpolation```raklet name = "Rak"dump f"hello {name}!"```### Tuples and structs```raklet p = (1, 2)dump p.1struct Point { x: int, y: int }let o = Point { x: 1, y: 2 }dump o.x```### Pattern matching```rakmatch 2 {    1 => { dump "one" },    2 => { dump "two" },    _ => { dump "other" }}```### Pipeline operator`x |> f` desugars to `f(x)`, and `x |> f(a, b)` to `f(x, a, b)`. Chaining isleft-associative, so `data |> parse |> load` is `load(parse(data))`. Works onboth the interpreter and the bytecode VM.```rakfn inc(n) { return n + 1 }fn dbl(n) { return n * 2 }dump 5 |> inc |> dbl          // 12dump 3 |> add(10)             // 13```### Regex literals`/pattern/flags` with flags `i` (case-insensitive), `m` (multi-line), `s`(dotall), `x` (extended). A `/` after a value is division; a `/` in operandposition starts a regex, so `a / b` and `let r = /\d+/g` both work.```raklet re = /\d+/gdump re.is_match("abc123")            // truedump re.find_all("a1 b22 c333")       // [1, 22, 333]dump (/\s+/g).replace("a  b   c", "_") // a_b_c// Free-function form (also works on the VM):dump regex_find_all(/[a-z]+/g, "a1bc2def")   // [a, bc, def]```### Binary pattern matchingMatch a `bytes` value against byte literals (hex, int, or char) with atrailing `..` to match the rest. Useful for magic-number sniffing.```rakfn sniff(data: bytes) {    match data {        [0x89, 'P', 'N', 'G', ..] => { return "png" },        [0xFF, 0xD8, 0xFF, ..] => { return "jpeg" },        ['%', 'P', 'D', 'F', ..] => { return "pdf" },        _ => { return "unknown" },    }}dump sniff(b"\x89PNG\x0d\x0a\x1a\x0a")  // png```### Traits (Display, Iterable, Index, IndexMut)The receiver is passed as the first argument of each method. `Display::fmt`drives `dump`, `Iterable::iter` drives `for x in target`, `Index::index` /`IndexMut::set` drive `obj[key]` reads and writes.```rakstruct Point { x: int, y: int }impl Display for Point {    fn fmt(self) { return fmt("({}, {})", self.x, self.y) }}dump Point { x: 3, y: 4 }   // (3, 4)struct Range { lo: int, hi: int }impl Iterable for Range {    fn iter(self) {        let out = []; let i = self.lo        while i <= self.hi { out = push(out, i); i = i + 1 }        return out    }}let s = 0for n in Range { lo: 1, hi: 5 } { s = s + n }dump s   // 15```### Characters and base literals```raklet c: char = 'a'let hebrew: char = 'א'let alpha = '\u{03B1}'   // αlet bin = 0b1010          // 10let oct = 0o755           // 493dump 0xA == 10            // true```### Generic functions```rakfn identity<T>(value: T) -> T { return value }dump identity<int>(42)        // 42dump identity<string>("hi")   // hidump identity(99)             // inferred: 99```### Defer`defer f()` runs in LIFO order when the current function exits. The last oneregistered runs first. Same on the interpreter and the VM.```rakfn work() {    defer dump "cleanup-last"    defer dump "cleanup-first"}work()   // cleanup-first, then cleanup-last```### Tests and type checking```raktest "addition works" {    assert add(2, 3) == 5    assert_eq(add(2, 3), 5)    expect_error(fn() { raise "boom" })}``````bashrakc test tests/math.rak    # PASS/FAIL, exit non-zero on failurerakc check file.rak         # type mismatches, non-exhaustive matches```The full design and implementation plan for these plus FFI, memory-mappedfiles, macros, an async event loop, raw sockets, and DNS/TLS/PCAP parsers isin [`docs/rak-features-spec.md`](docs/rak-features-spec.md).## Standard library### TCP networking```raklet listener = net_listen("127.0.0.1:18392")let conn = net_accept(listener)let stream = conn.0tcp_write(stream, "hello\n")dump tcp_read_line(stream)tcp_close(stream)```### Concurrency```raklet h = spawn(fn() { return 42 })dump thread_join(h)let (tx, rx) = channel()chan_send(tx, "hi")dump chan_recv(rx)```### Strings, arrays, and math```rakdump replace("hello", "l", "L")      // heLLodump find("hello", "lo")             // 3, or -1 if not founddump starts_with("hello", "he")      // truedump ends_with("hello", "lo")        // truedump slice("hello", 1, 4)            // elldump repeat("ab", 3)                 // abababdump trim_start("  hi")              // hidump reverse("abc")                  // cbadump reverse([1, 2, 3])             // [3, 2, 1]dump sum([1, 2, 3, 4])              // 10dump max(3, 9, 2)                   // 9dump min(3, 9, 2)                   // 2dump abs(-5)                        // 5dump sqrt(16)                       // 4dump pow(2, 10)                     // 1024dump clamp(15, 0, 10)              // 10```### JSON```raklet j = json_parse("{\"user\": \"admin\", \"id\": 7}")dump j.user                         // admindump j.id                           // 7dump json_stringify(j)              // {"user":"admin","id":7}```### OSINT (where it started)```rakfor port in scan_ports("127.0.0.1", { range: [0x0016, 0x0050] }) {    dump fmt("Open: 0x{:04X}", port)}dump md5("password")dump sha256("secret")dump hex_encode("ABC")dump html_links(html)```### Cryptography (native — no FFI)`hmac_sha256`, AES-256-GCM (`aes_gcm_encrypt` / `aes_gcm_decrypt`), and Ed25519(`ed25519_keypair`, `ed25519_sign`, `ed25519_verify`). All take and return`bytes`/`string` and are available on both the interpreter and the VM.```rakdump hmac_sha256("key", "data")let key = b"\x00\x01...\x1f"         // 32 byteslet nonce = b"\x00\x01...\x0b"       // 12 byteslet ct = aes_gcm_encrypt(key, nonce, b"payload")dump aes_gcm_decrypt(key, nonce, ct) // b"payload"let pair = ed25519_keypair(seed)let sig = ed25519_sign(pair.1, b"msg")dump ed25519_verify(pair.0, sig, b"msg")   // true```### DNS toolkitBeyond `dns_query`/`dns_build`/`dns_parse`, the investigation API:`dns_resolve(host)`, `dns_reverse(ip)` (real PTR, v4 + v6), `dns_records(host)`(all record types), and `dns_walk(domain, prefixes)`.```rakdump dns_resolve("example.com")          // all A + AAAA addressesdump dns_reverse("8.8.8.8")              // [dns.google]for r in dns_records("example.com") { dump r.type }dump dns_walk("example.com", ["www", "mail", "api"])```### Process API`process_spawn(cmd, args)`, `process_wait(pid)`, `process_stdout(pid)`,`process_stderr(pid)`, `process_kill(pid)`.```raklet pid = process_spawn("cmd", ["/c", "echo", "hi"])process_wait(pid)dump process_stdout(pid)```### HTTP server (pull-based)A minimal HTTP/1.1 server. Requests are queued and read on the main thread, sohandlers can use arbitrary Rak logic (closures, etc.). Works on both backends.```rakhttp_server_start("127.0.0.1", 8080)loop {    let req = http_server_poll()          // nil when idle; never blocks    if req == nil { sleep(10) }    else {        if req.path == "/users" {            http_server_respond(req.id, 200, { "Content-Type": "application/json" }, "{\"ok\":true}")        } else {            http_server_respond(req.id, 404, {}, "not found")        }    }}````http_server_start(addr, port)` binds and queues parsed requests (returns thebound port); `http_server_poll()` returns`{id, method, path, query, headers, body}` or `nil`; `http_server_respond(id,status, headers, body)` writes the response; `http_server_stop()` cleans up.String-keyed map literals (`{ "Content-Type": "application/json" }`) are nowsupported for JSON-style maps.### WebSocketRFC 6455 framing + handshake built on the existing TCP stream handle.`ws_connect(url)` performs the client handshake; `ws_handshake(stream)` repliesto a client Upgrade request on a `net_accept` connection; `ws_send(stream, data,mask)` sends a text frame (client→server frames must be masked, servers pass`false`); `ws_recv(stream)` returns `{opcode, payload}` or `nil`; `ws_close(stream)`sends a close frame. Interpreter-only (the VM has no TCP layer).```rak// server: accept + handshake + echolet list = net_listen("127.0.0.1:19001")let (stream, _) = net_accept(list)ws_handshake(stream)loop {    let m = ws_recv(stream)    if m == nil { break }    if m.opcode == 1 { ws_send(stream, m.payload, false) }}// clientlet ws = ws_connect("ws://127.0.0.1:19001/echo")ws_send(ws, "hello", true)dump string(ws_recv(ws).payload)   // hello```### Structured logging (machine-readable)`log_level(level)`, `log_init(path?)`, and `log_info` / `log_warn` / `log_error`/ `log_debug`. Each call emits one JSON line (default stdout, or append-onlyfile) — greppable with jq.```raklog_level("debug")log_info("scan_start", { host: "127.0.0.1", ports: [80, 443] })```### Secrets API`secret_get(name)`, `secret_set(name, value)`, `secret_persist(name, value)`(0600 file), `secret_delete(name)`, `secret_ls()`. Resolution: session → envvar → durable store. Never logged.```raksecret_set("API_KEY", "abc123")dump secret_get("API_KEY")```## CLI```bashrakc run <file>     Run a Rak script on the interpreterrakc vm <file>      Run on the bytecode VMrakc build <file>   Build a standalone executablerakc bench <file>   Benchmark interpreter vs VMrakc check <file>   Static type check; print diagnostics with line/columnrakc test [file]    Run test blocks (--filter NAME, --verbose)rakc lex <file>     Print tokensrakc parse <file>   Print ASTrakc repl           Start an interactive REPLrakc lsp            Start the language server (stdio)rakc bindgen <h>    Generate Rak bindings from a C headerrakc --versionrakpkg init [name]       Create a new packagerakpkg add <user/repo>   Add a package from GitHubrakpkg install           Install all dependenciesrakpkg run               Run the entry pointrakpkg build             Build to a standalone executablerakpkg list              List installed packagesrakpkg remove <name>     Remove a package```## Tooling### REPL`rakc repl` starts an interactive session. State persists between lines, so variables and functions stay defined. Unclosed blocks continue on the next line. Commands start with `:`.```rak> let x = 10rak> dump x[DUMP] 10rak> fn add(a, b) { return a + b }rak> dump add(3, 4)[DUMP] 7rak> :ast 1 + 2rak> :help````:vars` shows defined variables. `:ast <expr>` prints the AST. `:bytecode <expr>` prints the compiled chunk. `:clear` resets state. `:quit` exits.### Language server`rakc lsp` is a stdio language server. It reports parser and lexer diagnostics, offers keyword, type, and builtin completion, shows hover text for identifiers, and jumps to `fn`, `let`, `struct`, and `enum` definitions.Build it with `cargo build --release --features lsp`. The `vscode-rak/` directory has a VS Code extension with a TextMate grammar that pairs with it. For Neovim, point `nvim-lspconfig` at `rakc lsp` for `.rak` files.### C header bindgen`rakc bindgen header.h -o bindings.rak` reads a C header and generates a Rak file with a function per C function (calling `extern_call`) and a struct per C struct. Pointers map to `u64`, `char*` maps to `string`, numeric types map to `i8` through `u64` and `f32`/`f64`.```bashcargo build --release --features bindgenrakc bindgen sdl.h -o sdl.rak```The generated functions call `extern_call`, which returns an error until a Rust wrapper is linked into the standard library. The wrapper is where the actual FFI linking happens.## Platform supportWindows and Linux. On Windows, the GUI uses WebView2 (ships with Edge) and is display-only; Linux GUI does not work in 8.0.0. Note that the feature is per-crate, so it needs `-p rakc --features gui`, not a workspace-wide `--features gui`. `rakc build` produces `.exe` on Windows and an executable with `chmod 755` on Linux. The IDE ships as NSIS/MSI on Windows and `.deb`/AppImage on Linux via GitHub Actions CI, alongside the custom `rak-setup` installer (net-install + offline bundle) on both.## Project structure```Rak/├── rakc/              Compiler, interpreter, VM, GUI│   └── src/│       ├── lexer.rs       Tokenizer (logos)│       ├── parser.rs      Recursive descent parser│       ├── ast.rs         AST definitions│       ├── interpreter.rs Tree-walking interpreter + stdlib builtins│       ├── bytecode.rs    Opcode set and chunk│       ├── compiler.rs    AST to bytecode│       ├── vm.rs          Stack-based bytecode VM│       ├── gui.rs         WebView2/WebKitGTK window management│       ├── repl.rs        Interactive REPL│       ├── lsp.rs         Language server│       └── bindgen.rs     C header bindgen├── stdlib/            Rust native stdlib (net, crypto, encoding, recon, web, file, json, log, process, secrets, http_server, websocket)├── rakpkg/            Package manager CLI├── rak-setup/        Custom interactive installer (TUI wizard: net-install + offline)├── dist/              One-liner bootstraps (install.sh / install.ps1), man pages, completions├── ide/               Tauri + Next.js IDE├── .github/workflows/  CI (Linux .deb + AppImage builds)├── examples/│   ├── hello.rak│   ├── quick.rak│   ├── osint_scan.rak│   ├── echo_server.rak     TCP echo server│   ├── sql_server.rak      SQL server in Rak│   ├── sql_client.rak│   ├── self_host.rak       Rak interpreter in Rak│   ├── bench.rak           VM benchmark│   ├── gui_demo.rak        GUI window demo│   ├── json_demo.rak       JSON parse and stringify│   ├── closures.rak        Lexical closures and recursion│   ├── vm_features.rak     Map, tuple, index, interp, match on the VM│   ├── pipeline.rak        Pipeline operator (|>)│   ├── regex.rak           Regex literals and matching│   ├── binary_patterns.rak Binary byte-pattern matching│   ├── traits.rak          Display/Iterable/Index trait protocols│   ├── ffi.rak             FFI: extern bindings + raw memory (interpreter + VM)│   ├── ffi_dynamic.rak     FFI dynamic loader (lib.call/lib.sym/lib.close)│   ├── mmap.rak            Memory-mapped files: zero-copy slice/search/lines│   ├── async.rak           Async event loop: async fn / await / tcp_probe│   ├── net_raw.rak         Raw sockets: forge IPv4/TCP/UDP packets│   ├── parsers.rak         DNS / TLS / PCAP wire-format parsers│   ├── macros.rak          Compile-time macros: macro / name! / const│   ├── import_demo.rak    Python-style import / from / export (with mymod/ package)│   ├── forensic_structs.rak  binstruct decode/encode round-trip + evidence provenance│   └── stdlib_demo.rak     String, array, and math builtins```## Build from source```bashgit clone https://github.com/Louiml/Rak.gitcd Rakcargo build --release                    # rakc + rakpkgcargo build --release -p rakc --features gui   # rakc with GUI supportcd ide && npm install && npx tauri build # IDE```Linux requires `libwebkit2gtk-4.1-dev`, `libgtk-3-dev`, `libayatana-appindicator3-dev`, and `librsvg2-dev`.## Tech stackThe compiler is Rust. Logos handles lexing. The parser is hand-written recursive descent. Two backends: a tree-walking interpreter and a stack-based bytecode VM.The standard library uses `ureq` for HTTP, `scraper` for HTML parsing, `md-5`/`sha1`/`sha2` for hashing, `std::net` for TCP, `std::thread` and `mpsc` for concurrency, `libloading` for FFI, `memmap2` for memory-mapped files, and `tokio` for the async event loop. Real JSON via `serde_json`.The IDE is Tauri v2, Next.js, TypeScript, and Tailwind CSS. It runs Rak scripts as child processes, streams output, and has an integrated terminal.## LicenseApache-2.0## AuthorLouiml (Ryuzaki)