Tooling Reference

Every tool shipped by the Resilient compiler binary and its surrounding scripts, in one place. This is a reference page — for introductions, see Getting Started or the Tutorial.

Table of contents

Compiler execution modes

The rz binary is a driver that can run a source file under three different backends.

Mode Flag Status Notes
Tree-walking interpreter (default) stable Fastest to iterate on. Accepts every language feature.
Bytecode VM --vm stable ~12x faster than the interpreter on fib(25). Stack-based.
Cranelift JIT --jit backend-limited stable subset Requires --features jit. ~12x faster than the VM.
rz prog.rz              # interpreter
rz --vm prog.rz         # bytecode VM
rz --jit prog.rz        # Cranelift JIT (built with --features jit)

The JIT backend only ships AST lowerings for the stable subset documented in Performance. Features outside the subset fall through to the interpreter at runtime rather than erroring.

Stability surface

Public behavior is grouped by the same stability classes printed by rz --help:

  • Stable: Supported for scripts and CI on the default build. Examples include --check, --typecheck, --typecheck-strict, --fmt, --lint, --examples, --audit (without SMT features), --run, and the default/interpreter execution path.
  • Backend-limited: Stable when the named backend/build feature is present; unavailable builds print a rebuild hint. This includes --jit (requires --features jit), --lsp (requires --features lsp), and SMT-enabled verification (--features z3 / --z3).
  • Experimental: User-facing, but policy/output may still evolve. Examples include --ai-threats and --dump-ast-json.

Inspection

--dump-tokens <file>

Prints the lexer’s token stream as line:col Kind("lexeme") and exits. Useful when a parser error points at a mystery token. Honours the logos-lexer feature flag — same output either way. Mutually exclusive with --lsp.

rz --dump-tokens resilient/examples/hello.rz

--dump-ast-json <file>

Prints a stable JSON view of the parsed AST and exits. This is mainly for the self-hosting parity harness, which compares Rust-side parse output against the self-hosted parser on a curated corpus.

rz --dump-ast-json self-host/parity_corpus/success/hello.rz

self-host-parity-report [DIR]

Publishes a grammar coverage / gap report for the curated self-host/parity_corpus/ harness instead of only surfacing a binary pass/fail outcome. The report summarizes token parity, AST parity, and parse-error location parity, then lists which grammar features are currently covered, missing from the corpus, or divergent.

Use --json-out <path> to persist a stable JSON artifact for CI or handoff notes.

rz self-host-parity-report --json-out artifacts/self-host-parity.json

--dump-chunks <file>

Compiles the program through the VM pipeline (including the RES-172 peephole pass) and prints a stable-format disassembly of every bytecode chunk — main plus each user function — with constants, offsets, lines, opnames, and resolved jump targets.

rz --dump-chunks resilient/examples/hello.rz

Mutually exclusive with --dump-tokens and --lsp. The column contract is documented at the top of resilient/src/disasm.rs; external tools may parse it.

Type checking

--typecheck <file> (also -t)

Runs the static type checker. Clauses (requires / ensures, array bounds, etc.) that are statically discharged are elided at runtime — no runtime check is emitted. Clauses that the checker cannot discharge fall through to their usual runtime enforcement.

rz --typecheck prog.rz
rz -t prog.rz

--typecheck is implied by --emit-certificate. --typecheck-strict keeps the same checker but turns any type error into a fatal exit instead of a soft diagnostic.

Verification

--audit <file>

Prints a human-readable report of which contract clauses were proven statically vs left to runtime. Useful for understanding what the verifier is (and isn’t) doing on a given program.

rz --audit resilient/examples/sensor_monitor.rz

--emit-certificate <dir>

For each contract obligation that Z3 discharges, writes a self- contained SMT-LIB2 file so a downstream consumer can re-verify the proof under their own solver without trusting the Resilient binary. One file per obligation, named <fn>__<kind>__<idx>.smt2. Implies --typecheck. Requires a --features z3 build; default builds report a Backend-limited: rebuild hint instead of silently ignoring the flag.

rz --emit-certificate ./certs resilient/examples/cert_demo.rz   # binary built with --features z3

Every run also writes a manifest.json index with per-obligation SHA-256 and (when signed) Ed25519 signatures.

--sign-cert <key.pem>

Signs the concatenated certificate payload with an Ed25519 private key, writing a 64-byte signature to <dir>/cert.sig. Only meaningful when paired with --emit-certificate. The PEM envelope format is documented in resilient/src/cert_sign.rs. Requires a --features z3 build.

rz verify-cert <dir>

Re-checks <dir>/cert.sig against the binary’s embedded public key (or a --pubkey <path> override). Exits 0 on match, 1 on tamper / wrong key, 2 on usage error. Requires a --features z3 build; default builds report a Backend-limited: rebuild hint.

rz verify-cert ./certs
rz verify-cert ./certs --pubkey ./trusted-pub.pem

rz verify-all <dir>

Walks <dir>/manifest.json and re-checks every obligation: SHA-256 of the .smt2 file, Ed25519 signature (if present), and optionally re-runs Z3 on each certificate when --z3 is passed (requires the z3 binary on PATH). Output is a one-row-per- obligation table; exit 0 iff every checked cell passes. Requires a --features z3 build; default builds report a Backend-limited: rebuild hint.

rz verify-all ./certs
rz verify-all ./certs --z3

REPL

Launched by running rz with no file argument, or explicitly via rz repl.

rz repl is an explicit alias for the same interactive REPL that starts when rz is invoked with no file argument.

rz                           # start REPL
rz repl                      # explicit alias for REPL
rz repl --examples-dir ./ex  # override the REPL examples directory

Built-in commands:

Command Purpose
help Show help message.
exit Exit the REPL.
clear Clear the screen.
examples List example snippets (or real files under --examples-dir).
typecheck Toggle static type checking on/off for the session.

History is persisted via rustyline. Multi-line input is supported.

Conditional Compilation

Use the CLI flags below to select #[cfg(...)] branches in examples and real projects:

rz --feature verbose resilient/examples/cfg_feature.rz
rz --target thumbv7em resilient/examples/cfg_target.rz
rz --cfg mode=demo resilient/examples/cfg_kv_demo.rz

The examples in resilient/examples/ show the expected stdout for each path and are covered by smoke tests.

Language Server (LSP)

Opt-in; requires building with --features lsp.

cargo build --features lsp --release
rz --lsp

Speaks LSP over stdio. Shipped features:

  • Diagnostics (parse errors, type errors, lint output)
  • Hover (types, contracts)
  • Go-to-definition (functions/structs across on-disk workspace imports, plus same-file type aliases)
  • Completion (builtins + top-level decls; RES-188)
  • Semantic tokens (keyword / function / variable / parameter / type / string / number / comment / operator; see sem_tok in resilient/src/lib.rs)

See LSP / Editor Integration for editor config examples.

Formatter

rz fmt <file> [--in-place]

Canonical source-code formatter. Parses the input, walks the AST, and pretty-prints it in canonical style:

  • 4-space indentation
  • One space around binary operators
  • Opening brace on the same line as the introducing construct
  • No trailing whitespace
  • Blank line between top-level declarations
  • requires / ensures clauses indented under the function signature
  • live blocks follow the same brace style
rz fmt resilient/examples/hello.rz         # print to stdout
rz fmt --in-place resilient/examples/hello.rz # overwrite the file

Exit codes: 0 = formatted, 1 = parse errors (formatter refuses to touch broken input), 2 = usage error.

Known limitation. The formatter is a structural round-trip, and the parser discards comments. Comments are not preserved today. Run fmt only on code you’re willing to re-attach comments to by hand; comment-preserving formatting is not available yet.

rz fmt --check <file>... (CI / pre-commit mode)

Checks whether one or more files are already canonically formatted without writing anything, mirroring cargo fmt --check / rustfmt --check:

rz fmt --check src/main.rz                  # single file
rz fmt --check resilient/examples/*.rz      # a whole set
  • Formats each file in memory and compares it to the on-disk source.
  • Prints nothing on success and never writes; exits 0 only when every file is already formatted.
  • A file that would be reformatted (or that fails to parse) gets a one-line diagnostic on stderr (<path>: would reformat), and the process exits 1.
  • --check cannot be combined with --in-place (usage error, exit 2).

Typical uses:

# CI gate
rz fmt --check $(git ls-files '*.rz')

# pre-commit hook
rz fmt --check $(git diff --cached --name-only -- '*.rz') || {
    echo "Run 'rz fmt --in-place' on the files above before committing."
    exit 1
}

The formatter’s idempotence (fmt(fmt(x)) == fmt(x)) and performance budget (10K LOC in under a second) are exercised as acceptance tests against the full resilient/examples/ corpus — see docs/TOOLING_QUALITY.md for the standards and resilient/src/formatter.rs’s fmt_idempotent_and_within_perf_budget_across_example_corpus test.

Package tooling

rz pkg init <name>

Creates a new Resilient project layout in the current directory:

<name>/
  src/
    main.rz
  README.md
  .gitignore
rz pkg init my-proj
cd my-proj
rz src/main.rz

rz pkg add <name> <spec>

Adds a dependency to [dependencies] in resilient.toml and records the resolved source in resilient.lock. The source specifier can point at a local package or a pinned Git source:

rz pkg add mylib path:../libs/mylib
rz pkg add netutil git:https://github.com/user/netutil --rev abc123

rz pkg remove <name>

Drops a dependency from [dependencies] in resilient.toml and rewrites resilient.lock to match the remaining dependencies. Errors cleanly if <name> isn’t declared:

rz pkg remove mylib

rz pkg search <query>

Searches dependencies that are already resolvable locally — the [dependencies] in the nearest resilient.toml, cross-referenced against resilient.lock to report whether each match is locked. There is no remote registry index yet, so results are limited to what the current project already declares; the command always prints a note that remote registry search is future work:

rz pkg search lib

rz pkg publish --dry-run

Packages the current project and prints the upload summary without contacting a registry. The real registry POST path is still future work, so --dry-run is required today:

rz pkg publish --dry-run

Fuzz testing

The fuzz/ sibling crate carries cargo-fuzz targets. Two are shipped:

  • lex — drives Lexer::new + next_token to EOF on arbitrary input. No panic paths in the lexer.
  • parse — drives parse(src) and asserts the parser never panics regardless of input.
cd fuzz
cargo +nightly fuzz run lex
cargo +nightly fuzz run parse

Nightly Rust is required by cargo-fuzz. Corpus and crash seeds live under fuzz/corpus/<target>/ and fuzz/artifacts/<target>/.

Benchmarking

Performance numbers are produced by the benchmark driver in benchmarks/.

benchmarks/run.sh

The script runs fib(25) across every backend (interpreter, VM, JIT, and the reference Rust / Python / Node / Lua / Ruby implementations in benchmarks/ref/) and writes a Markdown table to benchmarks/RESULTS.md. See Performance for the methodology and headline numbers.

For file-local microbenchmarks, use rz bench <file>. Add --summary-json <path> when CI needs a stable artifact with the per-benchmark stats and baseline deltas, and the CLI will also echo artifact.summary_json=<path> on stdout for log scraping.

rz bench resilient/examples/bench_simple.rz \
  --summary-json artifacts/bench-summary.json

Reproducibility

--seed <u64>

Pins the SplitMix64 PRNG used by random_int / random_float so the same seed replays the same sequence. When --seed is not passed the driver derives a seed from the monotonic clock and echoes seed=<N> to stderr so a failing run can be replayed.

rz --seed 42 prog.rz
rz --seed=42 prog.rz

Security note. SplitMix64 is not cryptographic. Do not use random_* for key material, nonces, or session tokens.

Debugger

rz debug <file>

Starts the Debug Adapter Protocol (DAP) server on stdin/stdout for an editor or debugger client. The file argument labels the session; the DAP launch request supplies the program path.

rz debug examples/hello.rz

For direct adapter launches, clients may also use rz --dap.

Other debugging aids are:

  • --dump-tokens — inspect the lexer output
  • --dump-chunks — inspect the compiled bytecode
  • println() / print() in user code
  • The LSP server’s hover and diagnostics

Breakpoints, stepping, and watch expressions are still maturing; keep bytecode-level inspection via --dump-chunks in the toolbox when debug-adapter behavior is not enough.

Profiler — future

There is no profiler today. Timing numbers come from the benchmark driver (above) and from --jit-cache-stats, which prints cumulative JIT cache (hits / misses / compiles) counters to stderr on exit. A sampling profiler with a flame-graph emitter is a future deliverable.

# What exists today:
rz --jit --jit-cache-stats prog.rz   # requires a --features jit build

Test framework

rz test [<file|dir>] [--filter <substring>]

Discovers and runs fn test_*() functions in .rz files. With no path argument, discovery starts from the current directory. Use --filter to run only tests whose function name contains a substring.

rz test
rz test resilient/examples/test_runner_demo.rz
rz test resilient/examples --filter smoke

Resilient programs can also express lightweight checks with ordinary assert() and assert(cond, msg) calls. The assertion failure path includes operand values, which keeps many failures easy to debug.

fn main() {
    assert(add(2, 2) == 4, "add is broken");
}
main();

For CI, the model is the compiler’s own test suite:

cd resilient
cargo test              # unit + integration tests
cargo test --doc        # public API doctests
cargo test --features z3  # also exercises the SMT layer

Parallel execution and JUnit output are still future test-runner extensions.

Lint

rz lint <file>

Parses the file and runs the starter linter (5 stable codes today; see resilient/src/lint.rs for the full list). Supports // resilient: allow <code> suppression comments.

rz lint resilient/examples/hello.rz
rz lint resilient/examples/hello.rz --deny L001
rz lint resilient/examples/hello.rz --allow L003

Exit codes: 0 = no diagnostics, 1 = warnings only, 2 = any errors (either promoted via --deny or pre-existing errors).


See also