tinywasm-cli 0.9.0-alpha.1

Minimal command-line interface for TinyWasm
Documentation
use anstream::println;
use eyre::Result;
use owo_colors::OwoColorize;
use tinywasm::types::{ExternalKind, ImportKind};

use crate::cli::ModuleInputArgs;
use crate::load::load_module;

pub fn run(args: ModuleInputArgs) -> Result<()> {
    let loaded = load_module(&args.module)?;
    let module = loaded.module;

    let imported_func_count =
        module.imports.iter().filter(|import| matches!(import.kind, ImportKind::Function(_))).count() as u32;

    for (func_idx, func) in module.funcs.iter().enumerate() {
        let global_idx = imported_func_count + func_idx as u32;

        let exports = module
            .exports
            .iter()
            .filter(|export| export.kind == ExternalKind::Func && export.index == global_idx)
            .map(|export| export.name.as_ref())
            .collect::<Vec<_>>();

        let header = format!("func[{func_idx}]").blue().bold().to_string();
        if exports.is_empty() {
            println!("{header}");
        } else {
            println!("{header} {}", format!("exports={}", format!("{exports:?}").cyan()).bright_black());
        }

        for (ip, instr) in func.instructions.iter().enumerate() {
            let instr = print_instr(instr);
            println!("  {}: {}", print_ip(ip), instr);
        }
        println!();
    }

    Ok(())
}

fn print_ip(ip: usize) -> String {
    let s = format!("{ip:04}");
    let first_non_zero = s.find(|c| c != '0').unwrap_or(s.len() - 1);

    format!(
        "{}{}",
        &s[..first_non_zero].to_string().bright_black().dimmed(),
        &s[first_non_zero..].to_string().bright_black()
    )
}

fn print_instr(instr: &tinywasm::types::Instruction) -> String {
    let instr = format!("{instr:?}");
    let Some(split) = instr.find(['(', ' ', '{']) else {
        return instr.bold().to_string();
    };

    let (name, rest) = instr.split_at(split);

    let rest = rest
        .replace('(', &"(".bright_black().to_string())
        .replace(')', &")".bright_black().to_string())
        .replace('{', &"{".bright_black().to_string())
        .replace('}', &"}".bright_black().to_string())
        .replace(',', &",".bright_black().to_string())
        .replace(':', &":".bright_black().to_string());

    format!("{}{}", name.bold(), rest)
}