use std::str::FromStr; use argh::FromArgs; use args::WasmArg; use color_eyre::eyre::Result; use log::{debug, info}; use tinywasm::{self, types::WasmValue, Module}; use crate::args::to_wasm_args; mod args; mod util; #[cfg(feature = "wat")] mod wat; #[derive(FromArgs)] /// TinyWasm CLI struct TinyWasmCli { #[argh(subcommand)] nested: TinyWasmSubcommand, /// log level #[argh(option, short = 'l', default = "\"info\".to_string()")] log_level: String, } #[derive(FromArgs)] #[argh(subcommand)] enum TinyWasmSubcommand { Run(Run), } enum Engine { Main, } impl FromStr for Engine { type Err = String; fn from_str(s: &str) -> Result { match s { "main" => Ok(Self::Main), _ => Err(format!("unknown engine: {}", s)), } } } #[derive(FromArgs)] /// run a wasm file #[argh(subcommand, name = "run")] struct Run { /// wasm file to run #[argh(positional)] wasm_file: String, /// function to run #[argh(option, short = 'f')] func: Option, /// arguments to pass to the wasm file #[argh(option, short = 'a')] args: Vec, /// engine to use #[argh(option, short = 'e', default = "Engine::Main")] engine: Engine, } fn main() -> Result<()> { color_eyre::install()?; let args: TinyWasmCli = argh::from_env(); let level = match args.log_level.as_str() { "trace" => log::LevelFilter::Trace, "debug" => log::LevelFilter::Debug, "warn" => log::LevelFilter::Warn, "error" => log::LevelFilter::Error, "info" => log::LevelFilter::Info, _ => log::LevelFilter::Info, }; pretty_env_logger::formatted_builder().filter_level(level).init(); let cwd = std::env::current_dir()?; match args.nested { TinyWasmSubcommand::Run(Run { wasm_file, engine, args, func }) => { debug!("args: {:?}", args); let path = cwd.join(wasm_file.clone()); let module = match wasm_file.ends_with(".wat") { #[cfg(feature = "wat")] true => { let wat = std::fs::read_to_string(path)?; let wasm = wat::wat2wasm(&wat); tinywasm::Module::parse_bytes(&wasm)? } #[cfg(not(feature = "wat"))] true => return Err(color_eyre::eyre::eyre!("wat support is not enabled in this build")), false => tinywasm::Module::parse_file(path)?, }; match engine { Engine::Main => run(module, func, to_wasm_args(args)), } } } } fn run(module: Module, func: Option, args: Vec) -> Result<()> { let mut store = tinywasm::Store::default(); let instance = module.instantiate(&mut store, None)?; if let Some(func) = func { let func = instance.exported_func_by_name(&store, &func)?; let res = func.call(&mut store, &args)?; info!("{res:?}"); } Ok(()) }