mrubyedge_cli/subcommands/
run.rs

1use clap::Args;
2use std::{fs::File, io::Read, path::PathBuf};
3
4use mruby_compiler2_sys as mrbc;
5use mrubyedge;
6
7#[derive(Args)]
8pub struct RunArgs {
9    /// Dump instruction sequences
10    #[arg(long)]
11    pub dump_insns: bool,
12
13    /// Execute the given Ruby code string
14    #[arg(short = 'e', long = "eval", value_name = "CODE")]
15    pub eval: Option<String>,
16
17    /// Ruby source file or mrb binary to run
18    pub file: Option<PathBuf>,
19}
20
21pub fn execute(args: RunArgs) -> Result<(), Box<dyn std::error::Error>> {
22    let buf = if let Some(code) = &args.eval {
23        // Execute code from -e option
24        code.clone().into_bytes()
25    } else if let Some(file) = args.file {
26        // Read from file
27        let mut buf = Vec::new();
28        File::open(&file)?.read_to_end(&mut buf)?;
29        buf
30    } else {
31        return Err("Either -e option or file path must be provided".into());
32    };
33
34    let is_mrb_direct =
35        args.eval.is_none() && buf.len() >= 4 && buf[0..4] == [b'R', b'I', b'T', b'E'][..];
36    unsafe {
37        let mrb_bin = if is_mrb_direct {
38            buf.to_vec()
39        } else {
40            let buf = String::from_utf8(buf)?;
41            let mut ctx = mrbc::MRubyCompiler2Context::new();
42            if args.dump_insns {
43                ctx.dump_bytecode(&buf)?;
44            }
45            ctx.compile(&buf)?
46        };
47        let mut rite = mrubyedge::rite::load(&mrb_bin)?;
48        let mut vm = mrubyedge::yamrb::vm::VM::open(&mut rite);
49        vm.run()?;
50    }
51
52    Ok(())
53}