Improve debug repl parsing :)
This commit is contained in:
parent
e5d93f689f
commit
fc400ace5f
270
src/debugger.rs
270
src/debugger.rs
|
@ -1,270 +0,0 @@
|
|||
use rustyline::error::ReadlineError;
|
||||
use rustyline::Editor;
|
||||
|
||||
use colored::*;
|
||||
|
||||
use nom;
|
||||
use nom::IResult;
|
||||
use nom::bytes::complete::{tag, take_till1, take_till, take_while_m_n, take_while1};
|
||||
use nom::combinator::map_res;
|
||||
|
||||
use hexdump;
|
||||
|
||||
use super::arm7tdmi::cpu;
|
||||
use super::sysbus::SysBus;
|
||||
|
||||
use crate::disass::Disassembler;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Debugger {
|
||||
cpu: cpu::Core,
|
||||
sysbus: SysBus,
|
||||
running: bool,
|
||||
breakpoints: Vec<u32>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum DebuggerError {
|
||||
ParsingError(String),
|
||||
CpuError(cpu::CpuError),
|
||||
InvalidCommand(String)
|
||||
}
|
||||
|
||||
impl From<cpu::CpuError> for DebuggerError {
|
||||
fn from(e: cpu::CpuError) -> DebuggerError {
|
||||
DebuggerError::CpuError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nom::Err<(&str, nom::error::ErrorKind)>> for DebuggerError {
|
||||
fn from(e: nom::Err<(&str, nom::error::ErrorKind)>) -> DebuggerError {
|
||||
DebuggerError::ParsingError("parsing of command failed".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
type DebuggerResult<T> = Result<T, DebuggerError>;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum DebuggerCommand {
|
||||
Info,
|
||||
SingleStep,
|
||||
Continue,
|
||||
HexDump(u32, usize),
|
||||
Disass { addr: u32, num_opcodes: usize },
|
||||
AddBreakpoint(u32),
|
||||
ListBreakpoints,
|
||||
Reset,
|
||||
Quit,
|
||||
Nop,
|
||||
}
|
||||
use DebuggerCommand::*;
|
||||
|
||||
fn from_hex(input: &str) -> Result<u32, std::num::ParseIntError> {
|
||||
u32::from_str_radix(input, 16)
|
||||
}
|
||||
|
||||
fn from_dec(input: &str) -> Result<u32, std::num::ParseIntError> {
|
||||
u32::from_str_radix(input, 10)
|
||||
}
|
||||
|
||||
fn whitespace(input: &str) -> IResult<&str, ()> {
|
||||
let (input, _) = take_while1(char::is_whitespace)(input)?;
|
||||
Ok((input, ()))
|
||||
}
|
||||
|
||||
fn parse_hex_num(input: &str) -> IResult<&str, u32> {
|
||||
let (input, _) = tag("0x")(input)?;
|
||||
map_res(take_while_m_n(1, 8, |c: char| c.is_digit(16)), from_hex)(input)
|
||||
}
|
||||
|
||||
fn parse_num(input: &str) -> IResult<&str, u32> {
|
||||
map_res(take_while1(|c: char| c.is_digit(10)), from_dec)(input)
|
||||
}
|
||||
|
||||
fn parse_word(input: &str) -> IResult<&str, &str> {
|
||||
take_till(char::is_whitespace)(input)
|
||||
}
|
||||
|
||||
fn parse_debugger_command(input: &str) -> DebuggerResult<DebuggerCommand> {
|
||||
// TODO this code is shit!
|
||||
let (input, command_name) = parse_word(input)?;
|
||||
match command_name {
|
||||
"i" | "info" => Ok(Info),
|
||||
"s" | "step" => Ok(SingleStep),
|
||||
"c" | "continue" => Ok(Continue),
|
||||
"xxd" => {
|
||||
let (input, _) = whitespace(input).map_err(|_| DebuggerError::ParsingError("argument missing".to_string()))?;
|
||||
let (input, addr) = parse_hex_num(input)?;
|
||||
let (input, _) = whitespace(input).map_err(|_| DebuggerError::ParsingError("argument missing".to_string()))?;
|
||||
let (_, nbytes) = parse_num(input)?;
|
||||
let nbytes = nbytes as usize;
|
||||
Ok(HexDump(addr, nbytes))
|
||||
}
|
||||
"d" | "disass" => {
|
||||
let (input, _) = whitespace(input).map_err(|_| DebuggerError::ParsingError("argument missing".to_string()))?;
|
||||
let (input, addr) = parse_hex_num(input)?;
|
||||
let (input, _) = whitespace(input).map_err(|_| DebuggerError::ParsingError("argument missing".to_string()))?;
|
||||
let (_, num_opcodes) = parse_num(input)?;
|
||||
let num_opcodes = num_opcodes as usize;
|
||||
Ok(Disass{ addr, num_opcodes })
|
||||
}
|
||||
"b" | "break" => {
|
||||
let (input, _) = whitespace(input).map_err(|_| DebuggerError::ParsingError("argument missing".to_string()))?;
|
||||
let (_, addr) = parse_hex_num(input)?;
|
||||
Ok(AddBreakpoint(addr))
|
||||
}
|
||||
"bl" => Ok(ListBreakpoints),
|
||||
"q" | "quit" => Ok(Quit),
|
||||
"r" | "reset" => Ok(Reset),
|
||||
"" => Ok(Nop),
|
||||
_ => Err(DebuggerError::InvalidCommand(command_name.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debugger {
|
||||
pub fn new(cpu: cpu::Core, sysbus: SysBus) -> Debugger {
|
||||
Debugger {
|
||||
cpu: cpu,
|
||||
sysbus: sysbus,
|
||||
breakpoints: Vec::new(),
|
||||
running: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_breakpoint_reached(&self) -> bool {
|
||||
let pc = self.cpu.pc;
|
||||
for b in &self.breakpoints {
|
||||
if *b == pc {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn command(&mut self, cmd: DebuggerCommand) {
|
||||
match cmd {
|
||||
Nop => (),
|
||||
Info => {
|
||||
println!("cpu info: {:#x?}", self.cpu)
|
||||
}
|
||||
SingleStep => {
|
||||
;
|
||||
match self.cpu.step(&mut self.sysbus) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
println!("{}: {}", "cpu encountered an error".red(), e);
|
||||
println!("cpu: {:#x?}", self.cpu);
|
||||
}
|
||||
};
|
||||
if self.is_breakpoint_reached() {
|
||||
println!("breakpoint 0x{:08x} reached!", self.cpu.pc)
|
||||
}
|
||||
},
|
||||
Continue => {
|
||||
loop {
|
||||
match self.cpu.step(&mut self.sysbus) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
println!("{}: {}", "cpu encountered an error".red(), e);
|
||||
println!("cpu: {:#x?}", self.cpu);
|
||||
break
|
||||
}
|
||||
};
|
||||
if self.is_breakpoint_reached() {
|
||||
println!("breakpoint 0x{:08x} reached!", self.cpu.pc)
|
||||
}
|
||||
}
|
||||
},
|
||||
HexDump(addr, nbytes) => {
|
||||
let bytes = match self.sysbus.get_bytes(addr, nbytes) {
|
||||
Some(bytes) => bytes,
|
||||
None => {
|
||||
println!("requested content out of bounds");
|
||||
return
|
||||
}
|
||||
};
|
||||
hexdump::hexdump(bytes);
|
||||
}
|
||||
Disass{ addr, num_opcodes } => {
|
||||
let bytes = match self.sysbus.get_bytes(addr, 4*num_opcodes) {
|
||||
Some(bytes) => bytes,
|
||||
None => {
|
||||
println!("requested content out of bounds");
|
||||
return
|
||||
}
|
||||
};
|
||||
let disass = Disassembler::new(addr, bytes);
|
||||
|
||||
for line in disass {
|
||||
println!("{}", line)
|
||||
}
|
||||
}
|
||||
Quit => {
|
||||
print!("Quitting!");
|
||||
self.running = false;
|
||||
},
|
||||
AddBreakpoint(addr) => {
|
||||
if !self.breakpoints.contains(&addr) {
|
||||
let new_index = self.breakpoints.len();
|
||||
self.breakpoints.push(addr);
|
||||
println!("added breakpoint [{}] 0x{:08x}", new_index, addr);
|
||||
} else {
|
||||
println!("breakpoint already exists!")
|
||||
}
|
||||
}
|
||||
ListBreakpoints => {
|
||||
println!("breakpoint list:");
|
||||
for (i, b) in self.breakpoints.iter().enumerate() {
|
||||
println!("[{}] 0x{:08x}", i, b)
|
||||
}
|
||||
}
|
||||
Reset => {
|
||||
println!("resetting cpu...");
|
||||
self.cpu.reset();
|
||||
println!("cpu is restarted!")
|
||||
},
|
||||
_ => panic!("command {:?} not implemented", cmd)
|
||||
}
|
||||
}
|
||||
pub fn repl(&mut self) -> DebuggerResult<()> {
|
||||
self.running = true;
|
||||
let mut rl = Editor::<()>::new();
|
||||
while self.running {
|
||||
let readline = rl.readline(&format!("({}) >> ", "rustboyadvance-dbg".cyan()));
|
||||
match readline {
|
||||
Ok(line) => {
|
||||
let command = parse_debugger_command(&line);
|
||||
match command {
|
||||
Ok(cmd) => {
|
||||
self.command(cmd)
|
||||
}
|
||||
Err(DebuggerError::InvalidCommand(command)) => {
|
||||
println!("invalid command: {}", command)
|
||||
}
|
||||
Err(DebuggerError::ParsingError(msg)) => {
|
||||
println!("Parsing error: {:?}", msg)
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(ReadlineError::Interrupted) => {
|
||||
println!("CTRL-C");
|
||||
break;
|
||||
}
|
||||
Err(ReadlineError::Eof) => {
|
||||
println!("CTRL-D");
|
||||
break;
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error: {:?}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
260
src/debugger/mod.rs
Normal file
260
src/debugger/mod.rs
Normal file
|
@ -0,0 +1,260 @@
|
|||
use std::convert::TryFrom;
|
||||
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::Editor;
|
||||
|
||||
use colored::*;
|
||||
|
||||
use hexdump;
|
||||
|
||||
use super::arm7tdmi::cpu;
|
||||
use super::sysbus::SysBus;
|
||||
|
||||
use crate::disass::Disassembler;
|
||||
|
||||
mod parser;
|
||||
use parser::{parse_command_line, ParsedLine, Argument};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Debugger {
|
||||
cpu: cpu::Core,
|
||||
sysbus: SysBus,
|
||||
running: bool,
|
||||
breakpoints: Vec<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum DebuggerError {
|
||||
ParsingError(String),
|
||||
CpuError(cpu::CpuError),
|
||||
InvalidCommand(String),
|
||||
InvalidArgument(String)
|
||||
}
|
||||
|
||||
impl From<cpu::CpuError> for DebuggerError {
|
||||
fn from(e: cpu::CpuError) -> DebuggerError {
|
||||
DebuggerError::CpuError(e)
|
||||
}
|
||||
}
|
||||
|
||||
type DebuggerResult<T> = Result<T, DebuggerError>;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum DebuggerCommand {
|
||||
Info,
|
||||
SingleStep,
|
||||
Continue,
|
||||
HexDump(u32, usize),
|
||||
Disass { addr: u32, num_opcodes: usize },
|
||||
AddBreakpoint(u32),
|
||||
ListBreakpoints,
|
||||
Reset,
|
||||
Quit,
|
||||
}
|
||||
use DebuggerCommand::*;
|
||||
|
||||
impl TryFrom<ParsedLine> for DebuggerCommand {
|
||||
type Error = DebuggerError;
|
||||
|
||||
fn try_from(value: ParsedLine) -> Result<Self, Self::Error> {
|
||||
match value.command.as_ref() {
|
||||
"i" | "info" => {
|
||||
Ok(Info)
|
||||
},
|
||||
"s" | "step" => Ok(SingleStep),
|
||||
"c" | "continue" => Ok(Continue),
|
||||
"xxd" => {
|
||||
let mut args = value.args.into_iter();
|
||||
let addr = match args.next() {
|
||||
Some(Argument::Num(n)) => n,
|
||||
_ => {
|
||||
return Err(DebuggerError::InvalidArgument(format!("expected a number")));
|
||||
}
|
||||
};
|
||||
let nbytes = match args.next() {
|
||||
Some(Argument::Num(n)) => n,
|
||||
_ => {
|
||||
return Err(DebuggerError::InvalidArgument(format!("expected a number")));
|
||||
}
|
||||
};
|
||||
let nbytes = nbytes as usize;
|
||||
Ok(HexDump(addr, nbytes))
|
||||
}
|
||||
"d" | "disass" => {
|
||||
let mut args = value.args.into_iter();
|
||||
let addr = match args.next() {
|
||||
Some(Argument::Num(n)) => n,
|
||||
_ => {
|
||||
return Err(DebuggerError::InvalidArgument(format!("expected a number")));
|
||||
}
|
||||
};
|
||||
let num_opcodes = match args.next() {
|
||||
Some(Argument::Num(n)) => n,
|
||||
_ => {
|
||||
return Err(DebuggerError::InvalidArgument(format!("expected a number")));
|
||||
}
|
||||
};
|
||||
let num_opcodes = num_opcodes as usize;
|
||||
Ok(Disass { addr, num_opcodes })
|
||||
}
|
||||
"b" | "break" => {
|
||||
let mut args = value.args.into_iter();
|
||||
let addr = match args.next() {
|
||||
Some(Argument::Num(n)) => n,
|
||||
_ => {
|
||||
return Err(DebuggerError::InvalidArgument(format!("expected a number")));
|
||||
}
|
||||
};
|
||||
Ok(AddBreakpoint(addr))
|
||||
}
|
||||
"bl" => Ok(ListBreakpoints),
|
||||
"q" | "quit" => Ok(Quit),
|
||||
"r" | "reset" => Ok(Reset),
|
||||
_ => Err(DebuggerError::InvalidCommand(value.command)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debugger {
|
||||
pub fn new(cpu: cpu::Core, sysbus: SysBus) -> Debugger {
|
||||
Debugger {
|
||||
cpu: cpu,
|
||||
sysbus: sysbus,
|
||||
breakpoints: Vec::new(),
|
||||
running: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_breakpoint_reached(&self) -> bool {
|
||||
let pc = self.cpu.pc;
|
||||
for b in &self.breakpoints {
|
||||
if *b == pc {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn command(&mut self, cmd: DebuggerCommand) {
|
||||
match cmd {
|
||||
Info => println!("cpu info: {:#x?}", self.cpu),
|
||||
SingleStep => {
|
||||
match self.cpu.step(&mut self.sysbus) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
println!("{}: {}", "cpu encountered an error".red(), e);
|
||||
println!("cpu: {:#x?}", self.cpu);
|
||||
}
|
||||
};
|
||||
if self.is_breakpoint_reached() {
|
||||
println!("breakpoint 0x{:08x} reached!", self.cpu.pc)
|
||||
}
|
||||
}
|
||||
Continue => loop {
|
||||
match self.cpu.step(&mut self.sysbus) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
println!("{}: {}", "cpu encountered an error".red(), e);
|
||||
println!("cpu: {:#x?}", self.cpu);
|
||||
break;
|
||||
}
|
||||
};
|
||||
if self.is_breakpoint_reached() {
|
||||
println!("breakpoint 0x{:08x} reached!", self.cpu.pc)
|
||||
}
|
||||
},
|
||||
HexDump(addr, nbytes) => {
|
||||
let bytes = match self.sysbus.get_bytes(addr, nbytes) {
|
||||
Some(bytes) => bytes,
|
||||
None => {
|
||||
println!("requested content out of bounds");
|
||||
return;
|
||||
}
|
||||
};
|
||||
hexdump::hexdump(bytes);
|
||||
}
|
||||
Disass { addr, num_opcodes } => {
|
||||
let bytes = match self.sysbus.get_bytes(addr, 4 * num_opcodes) {
|
||||
Some(bytes) => bytes,
|
||||
None => {
|
||||
println!("requested content out of bounds");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let disass = Disassembler::new(addr, bytes);
|
||||
|
||||
for line in disass {
|
||||
println!("{}", line)
|
||||
}
|
||||
}
|
||||
Quit => {
|
||||
print!("Quitting!");
|
||||
self.running = false;
|
||||
}
|
||||
AddBreakpoint(addr) => {
|
||||
if !self.breakpoints.contains(&addr) {
|
||||
let new_index = self.breakpoints.len();
|
||||
self.breakpoints.push(addr);
|
||||
println!("added breakpoint [{}] 0x{:08x}", new_index, addr);
|
||||
} else {
|
||||
println!("breakpoint already exists!")
|
||||
}
|
||||
}
|
||||
ListBreakpoints => {
|
||||
println!("breakpoint list:");
|
||||
for (i, b) in self.breakpoints.iter().enumerate() {
|
||||
println!("[{}] 0x{:08x}", i, b)
|
||||
}
|
||||
}
|
||||
Reset => {
|
||||
println!("resetting cpu...");
|
||||
self.cpu.reset();
|
||||
println!("cpu is restarted!")
|
||||
}
|
||||
_ => panic!("command {:?} not implemented", cmd),
|
||||
}
|
||||
}
|
||||
pub fn repl(&mut self) -> DebuggerResult<()> {
|
||||
self.running = true;
|
||||
let mut rl = Editor::<()>::new();
|
||||
while self.running {
|
||||
let readline = rl.readline(&format!("({}) >> ", "rustboyadvance-dbg".cyan()));
|
||||
match readline {
|
||||
Ok(line) => {
|
||||
if line.is_empty() {
|
||||
continue
|
||||
}
|
||||
let line = parse_command_line(&line);
|
||||
match line {
|
||||
Ok(line) => {
|
||||
match DebuggerCommand::try_from(line) {
|
||||
Ok(cmd) => self.command(cmd),
|
||||
Err(DebuggerError::InvalidCommand(c)) => println!("{}: {:?}", "invalid command".red(), c),
|
||||
Err(DebuggerError::InvalidArgument(m)) => println!("{}: {}", "invalid argument".red(), m),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
Err(DebuggerError::ParsingError(msg)) => {
|
||||
println!("Parsing error: {}", msg)
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
Err(ReadlineError::Interrupted) => {
|
||||
println!("CTRL-C");
|
||||
break;
|
||||
}
|
||||
Err(ReadlineError::Eof) => {
|
||||
println!("CTRL-D");
|
||||
break;
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error: {:?}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
101
src/debugger/parser.rs
Normal file
101
src/debugger/parser.rs
Normal file
|
@ -0,0 +1,101 @@
|
|||
use std::fmt;
|
||||
|
||||
use nom;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::{tag, take_while_m_n};
|
||||
use nom::character::complete::{alphanumeric0, digit1, multispace0, multispace1};
|
||||
use nom::combinator::{cut, map, map_res};
|
||||
use nom::error::{context, convert_error, ParseError, VerboseError};
|
||||
use nom::multi::separated_list;
|
||||
use nom::sequence::{preceded, terminated};
|
||||
use nom::IResult;
|
||||
|
||||
use super::{DebuggerError, DebuggerResult};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum Argument {
|
||||
Num(u32),
|
||||
Boolean(bool),
|
||||
}
|
||||
|
||||
impl fmt::Display for Argument {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Argument::Num(_) => write!(f, "number"),
|
||||
Argument::Boolean(_) => write!(f, "boolean"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParsedLine {
|
||||
pub command: String,
|
||||
pub args: Vec<Argument>,
|
||||
}
|
||||
|
||||
fn parse_u32_hex<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, u32, E> {
|
||||
let (i, _) = context("hex", tag("0x"))(i)?;
|
||||
map_res(take_while_m_n(1, 8, |c: char| c.is_digit(16)), |s| {
|
||||
u32::from_str_radix(s, 16)
|
||||
})(i)
|
||||
}
|
||||
|
||||
fn parse_u32<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, u32, E> {
|
||||
context("u32", map_res(digit1, |s| u32::from_str_radix(s, 10)))(i)
|
||||
}
|
||||
|
||||
fn parse_num<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, Argument, E> {
|
||||
map(alt((parse_u32_hex, parse_u32)), |n| Argument::Num(n))(i)
|
||||
}
|
||||
|
||||
fn parse_boolean<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, Argument, E> {
|
||||
context(
|
||||
"bool",
|
||||
alt((
|
||||
map(tag("true"), |_| Argument::Boolean(true)),
|
||||
map(tag("false"), |_| Argument::Boolean(false)),
|
||||
)),
|
||||
)(i)
|
||||
}
|
||||
|
||||
fn parse_argument<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, Argument, E> {
|
||||
context("argument", alt((parse_num, parse_boolean)))(i)
|
||||
}
|
||||
|
||||
fn parse_argument_list<'a, E: ParseError<&'a str>>(
|
||||
i: &'a str,
|
||||
) -> IResult<&'a str, Vec<Argument>, E> {
|
||||
context(
|
||||
"argument list",
|
||||
preceded(multispace0, terminated(separated_list(multispace1, parse_argument), multispace0))
|
||||
)(i)
|
||||
}
|
||||
|
||||
fn parse_command_name<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
|
||||
context("command", preceded(multispace0, cut(alphanumeric0)))(i)
|
||||
}
|
||||
|
||||
fn parse_line<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&str, ParsedLine, E> {
|
||||
let (i, command_name) = parse_command_name(i)?;
|
||||
println!("command name = {:?}, remaining {:?}", command_name, i);
|
||||
let (i, arguments) = parse_argument_list(i)?;
|
||||
println!("command: {} arguments: {:?}", command_name, arguments);
|
||||
|
||||
Ok((
|
||||
i,
|
||||
ParsedLine {
|
||||
command: command_name.to_string(),
|
||||
args: arguments,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub fn parse_command_line(input: &str) -> DebuggerResult<ParsedLine> {
|
||||
match parse_line::<VerboseError<&str>>(input) {
|
||||
Ok((_, line)) => Ok(line),
|
||||
Err(nom::Err::Failure(e)) | Err(nom::Err::Error(e)) => {
|
||||
Err(DebuggerError::ParsingError(convert_error(input, e)))
|
||||
}
|
||||
_ => panic!("unhandled parser error"),
|
||||
}
|
||||
}
|
Reference in a new issue