use crate::vm::{ VirtualMachineInterface, VirtualMachine, Word }; static MAX_VALUE_WIDTH: usize = 8; fn expects_n_args(args: &Vec<&str>, n: usize) -> Result<(), String> { if args.len() - 1 != n { Err(format!("Command '{}' expected {n} arguments, {} were given!", args[0], args.len() - 1)) } else { Ok(()) } } fn parse_location(arg: &str, assignment: bool) -> Result, String> { let nums_str = arg.to_string(); let nums = nums_str .split(&['.', ':']) .collect::>(); let start = nums[0].parse::() .map_err(|_| format!("Unknown command '{}'!", nums[0]))?; // Single location if nums.len() == 1 { Ok(vec![start]) } // Range location else { let end = nums[1].parse::() .map_err(|_| format!("Expected location!"))?; if assignment { Ok(vec![start, end]) } // Range addresses else { Ok(Vec::from_iter(start..=end)) } } } fn assign_location(locs: Vec, vm: &mut VirtualMachine) { print_locations(vec![locs[0]], vm); vm.set_word(locs[0], locs[1] as Word); } fn print_locations(locs: Vec, vm: &VirtualMachine) { let padding = format!("{}", locs.last().unwrap()).len(); for (i, loc) in locs.into_iter().enumerate() { if i % MAX_VALUE_WIDTH == 0 { if i > 0 { println!(); } print!("{:indent$}:", loc, indent=padding); } print!(" {:ident$}", vm.get_word(loc), ident=6); } println!(); } pub(super) fn parse_and_exec(input: String, vm: &mut VirtualMachine) -> Result<(), String> { let args = input .split(&[' ', '\t', '\n', '\r']) .filter(|x| !x.is_empty()) .collect::>(); if args.len() == 0 { println!(); return Ok(()); } match args[0] { /* Run mode */ "r" | "run" => { expects_n_args(&args, 1)?; if ! vm.is_halted() { return Err(format!("Machine already running!")); } vm.set_start(args[1].parse().unwrap()); }, /* Single step mode */ "s" | "single" => { expects_n_args(&args, 1)?; if ! vm.is_halted() { return Err(format!("Machine already running!")); } if vm.is_single_step() { return Err(format!("Machine already in single-step mode!")); } vm.set_single_step(true); vm.set_start(args[1].parse().unwrap()); }, "c" | "continue" => { expects_n_args(&args, 0)?; if ! vm.is_single_step() { return Err(format!("Machine not in single-step mode!")); } vm.set_single_step(false); vm.set_halt(false); }, "n" | "next" => { expects_n_args(&args, 0)?; if ! vm.is_single_step() { return Err(format!("Machine not in single-step mode!")); } vm.step(); }, /* Other */ "q" | "quit" | "e" | "exit" => return Err(String::new()), "h" | "?" | "help" => { print!("
is a usize constant is a Word (i64) constant Multiple 'Memory IO' commands may be put on a single line, when separated by spaces General commands: h, ?, help This menu q, e, quit, exit Stop and exit the virtual machine Normal execution: r, run
Start normal execution at ADDRESS Only applicable when 'HALTED' Single-step execution: s, single
Start single-step execution at ADDRESS c, continue Resume normal execution Only applicable when in 'STEP' mode n, next Execute next instruction Only applicable when in 'STEP' mode Memory IO:
Print the value at the location
.
Print the values between the locations (inclusive range)
: Set value at ADDRESS to VALUE "); }, _ => { for arg in args { let assignment = arg.contains(':'); let locs = parse_location(arg, assignment)?; if assignment { assign_location(locs, vm); } else { print_locations(locs, vm); } } }, } Ok(()) }