#![allow(dead_code)] mod common; mod vm; use structopt::StructOpt; use snafu::Snafu; use std::{fs, process, path::PathBuf}; const DEFAULT_MAX_MEM: usize = 64 * 1024 * 1024; #[derive(Snafu, Debug, Clone, PartialEq)] enum ArgParseError<'a> { #[snafu(display("invalid specified size: {} (sizes may end in G, M, or K)", text))] InvalidSize { text: &'a str } } fn from_bytes_size<'a>(mut text: &'a str) -> std::result::Result> { if text.is_empty() { return Err(ArgParseError::InvalidSize { text }) } let multiplier = match text.chars().last().unwrap() { 'k' | 'K' => 1024, 'm' | 'M' => 1024 * 1024, 'g' | 'G' => 1024 * 1024 * 1024, _ => 1, }; // trim the last character if multiplier != 1 { text = &text[0 .. text.len() - 1]; } let value = text.parse::().map_err(|_| ArgParseError::InvalidSize { text })?; Ok(value * multiplier) } #[test] fn test_bytes_size() { assert_eq!(from_bytes_size("64G"), Ok(64 * 1024 * 1024 * 1024)); assert_eq!(from_bytes_size("64M"), Ok(64 * 1024 * 1024)); assert_eq!(from_bytes_size("64K"), Ok(64 * 1024)); assert_eq!(from_bytes_size("64g"), Ok(64 * 1024 * 1024 * 1024)); assert_eq!(from_bytes_size("64m"), Ok(64 * 1024 * 1024)); assert_eq!(from_bytes_size("64k"), Ok(64 * 1024)); assert_eq!(from_bytes_size("64"), Ok(64)); assert!(from_bytes_size("64B").is_err()); assert!(from_bytes_size("64MB").is_err()); assert!(from_bytes_size("64GB").is_err()); assert!(from_bytes_size("64KB").is_err()); assert!(from_bytes_size("64b").is_err()); assert!(from_bytes_size("64mb").is_err()); assert!(from_bytes_size("64gb").is_err()); assert!(from_bytes_size("64kb").is_err()); } #[derive(StructOpt, Debug)] struct Options { // maybe some other options: // * debug #[structopt(name = "FILE", parse(from_os_str))] input: PathBuf, #[structopt(short, long, parse(try_from_str = from_bytes_size))] max_mem: Option, } type Result = std::result::Result>; fn main() -> Result<()> { use vm::{ state::State, obj::{ assemble::{Asm, Assemble}, syn::{lexer, parser}, } }; let opt = Options::from_args(); let text = fs::read_to_string(&opt.input)?; let lexerdef = lexer::lexerdef(); let lexer = lexerdef.lexer(&text); let (res, errors) = parser::parse(&lexer); // print errors for err in errors.iter() { println!("{}", err.pp(&lexer, &parser::token_epp)); } if !errors.is_empty() { process::exit(1); } let res = res.unwrap(); let mut asm = Asm::default(); let object = res.assemble(&mut asm)?; let mut state = State::new(); state.load_object(object, opt.max_mem.unwrap_or(DEFAULT_MAX_MEM))?; let status = state.exec()?; process::exit((status & 0xffff_ffff) as i32); }