rhai 1.27.0

Embedded scripting for Rust
Documentation
//! Print the disassembly of a Grain bytecode program.
//!
//! `grain-dump script.rgrn`

use rhai::grain::Program;

fn dump(program: &Program, code: &[u8], name: &str, chunk: &rhai::grain::bytecode::Chunk) {
    println!(
        "\n{name}  [{}..{}]  max_stack {}",
        chunk.entry(),
        chunk.end(),
        chunk.max_stack()
    );

    for (at, op) in chunk.ops(code) {
        let pos = program.position(at);
        let where_ = match (pos.line(), pos.position()) {
            (Some(line), Some(col)) => format!("{line}:{col}"),
            _ => String::new(),
        };
        println!("  {at:>5}  {where_:<8}  {}", op.disassemble(program));
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let path = std::env::args()
        .nth(1)
        .ok_or("usage: grain-dump <script.rgrn>")?;
    let source = std::fs::read(&path)?;
    let program = Program::read(&source).map_err(|e| format!("failed to read program: {e}"))?;

    println!("{program:?}");

    let code = program.code();
    dump(&program, code, "main", program.main());

    for f in program.functions() {
        let access = match f.access {
            rhai::FnAccess::Public => "",
            rhai::FnAccess::Private => "private ",
            _ => unreachable!(),
        };
        let label = format!(
            "{access}fn {} : #{} ({} params)",
            f.disassemble(&program),
            f.name,
            f.params.len(),
        );
        dump(&program, code, &label, &f.chunk);
    }

    match program.write_stripped() {
        Ok(s) => println!(
            "\nartifact {} bytes, sidecar {} positions",
            s.artifact.len(),
            s.sidecar.num_positions()
        ),
        Err(e) => println!("\nnot writable: {e:?}"),
    }

    Ok(())
}