use std::str::FromStr;
use crate::debug::{BreakpointType, ReadMemoryExpr};
#[derive(Debug, Clone)]
pub enum ReplCommand {
Step,
StepN(usize),
Next,
NextLine,
Continue,
Finish,
Break(BreakpointType),
Breakpoints,
Delete(Option<u8>),
Stack,
Memory(ReadMemoryExpr),
Locals,
Vars(bool),
Where,
List,
Backtrace,
Reload,
Help,
Quit,
}
impl FromStr for ReplCommand {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.trim();
if s.is_empty() {
return Err("empty command".into());
}
let (cmd, args) = match s.split_once(char::is_whitespace) {
Some((cmd, args)) => (cmd, Some(args.trim())),
None => (s, None),
};
match cmd {
"s" | "step" => match args {
Some(n) => {
let n = n.parse::<usize>().map_err(|e| format!("invalid step count: {e}"))?;
Ok(ReplCommand::StepN(n))
}
None => Ok(ReplCommand::Step),
},
"n" | "next" => Ok(ReplCommand::Next),
"nl" | "next-line" | "nextline" => Ok(ReplCommand::NextLine),
"c" | "continue" => Ok(ReplCommand::Continue),
"e" | "finish" => Ok(ReplCommand::Finish),
"b" | "break" | "breakpoint" => {
let args = args.ok_or("breakpoint requires a specification")?;
let bp_type = args.parse::<BreakpointType>()?;
Ok(ReplCommand::Break(bp_type))
}
"bp" | "breakpoints" => Ok(ReplCommand::Breakpoints),
"d" | "delete" => match args {
Some(id) => {
let id = id.parse::<u8>().map_err(|e| format!("invalid breakpoint id: {e}"))?;
Ok(ReplCommand::Delete(Some(id)))
}
None => Ok(ReplCommand::Delete(None)),
},
"stack" => Ok(ReplCommand::Stack),
"mem" | "memory" => {
let args = args.ok_or("memory command requires an address")?;
let expr = args.parse::<ReadMemoryExpr>()?;
Ok(ReplCommand::Memory(expr))
}
"locals" => Ok(ReplCommand::Locals),
"vars" | "variables" => Ok(ReplCommand::Vars(args == Some("all"))),
"where" | "w" => Ok(ReplCommand::Where),
"l" | "list" => Ok(ReplCommand::List),
"bt" | "backtrace" => Ok(ReplCommand::Backtrace),
"reload" => Ok(ReplCommand::Reload),
"h" | "help" | "?" => Ok(ReplCommand::Help),
"q" | "quit" | "exit" => Ok(ReplCommand::Quit),
_ => Err(format!("unknown command: {cmd}")),
}
}
}
impl ReplCommand {
pub fn help_text() -> &'static str {
r#"Available commands:
Execution:
s, step [N] Execute one (or N) VM cycle(s)
n, next Execute until next instruction boundary
nl, next-line Execute until next source line
c, continue Run until breakpoint or end
e, finish Run until current function returns
reload Restart program execution
Breakpoints:
b, break <spec> Set a breakpoint
Specs: at <cycle>, after <N>, in <proc>, <file>:<line>, <file>
bp, breakpoints List all breakpoints
d, delete [id] Delete breakpoint by id, or all if no id given
Inspection:
stack Show operand stack
mem <addr> [type] Show memory at address (e.g., mem 0x100 u32)
locals Show local variables
vars [all] Show source variables; include compiler locals with `all`
where Show current source location
l, list Show recent instructions
bt, backtrace Show call stack
Other:
h, help Show this help
q, quit Exit debugger
"#
}
}