diff --git a/interp/src/debugger/commands/core.rs b/interp/src/debugger/commands/core.rs index 37148ef8a..5d5e9689a 100644 --- a/interp/src/debugger/commands/core.rs +++ b/interp/src/debugger/commands/core.rs @@ -299,6 +299,37 @@ impl From<(Vec, Option, PrintMode)> for PrintTuple { } } +/// ParseNodes enum is used to represent what child to traverse with respect to +/// the current ControlIdx. +/// Body defines that we should go into the body of a while or repeat. +/// Offset defines which child to go to. +/// If defines whether we should go to the true or false branch next +#[derive(Debug, PartialEq, Clone)] +pub enum ParseNodes { + Body, + Offset(u32), + If(bool), +} +pub struct ParsePath { + nodes: Vec, +} + +impl ParsePath { + pub fn new(nodes: Vec) -> ParsePath { + ParsePath { nodes } + } + + pub fn get_path(&self) -> Vec { + self.nodes.clone() + } +} + +impl FromIterator for ParsePath { + fn from_iter>(iter: I) -> Self { + ParsePath::new(iter.into_iter().collect()) + } +} + // Different types of printing commands pub enum PrintCommand { Normal, diff --git a/interp/src/debugger/commands/mod.rs b/interp/src/debugger/commands/mod.rs index 452108f4e..19f20de74 100644 --- a/interp/src/debugger/commands/mod.rs +++ b/interp/src/debugger/commands/mod.rs @@ -1,6 +1,7 @@ //! This module contains the structures for the debugger commands pub(crate) mod command_parser; pub mod core; +mod path_parser; pub use command_parser::parse_command; pub use core::Command; diff --git a/interp/src/debugger/commands/path_parser.pest b/interp/src/debugger/commands/path_parser.pest new file mode 100644 index 000000000..f95eaff14 --- /dev/null +++ b/interp/src/debugger/commands/path_parser.pest @@ -0,0 +1,13 @@ +root = { "." } + +separator = { "-" } + +body = { "b" } + +num = { ASCII_DIGIT+ } + +branch = {"t" | "f"} + +clause = { separator ~ (body | num | branch) } + +path = { SOI ~ root ~ clause* ~ EOI } diff --git a/interp/src/debugger/commands/path_parser.rs b/interp/src/debugger/commands/path_parser.rs new file mode 100644 index 000000000..5739da65b --- /dev/null +++ b/interp/src/debugger/commands/path_parser.rs @@ -0,0 +1,116 @@ +use super::{core::ParseNodes, ParsePath}; + +use pest_consume::{match_nodes, Error, Parser}; + +type ParseResult = std::result::Result>; +type Node<'i> = pest_consume::Node<'i, Rule, ()>; + +// include the grammar file so that Cargo knows to rebuild this file on grammar changes +const _GRAMMAR: &str = include_str!("path_parser.pest"); + +#[derive(Parser)] +#[grammar = "debugger/commands/path_parser.pest"] + +pub struct PathParser; + +#[pest_consume::parser] +impl PathParser { + fn EOI(_input: Node) -> ParseResult<()> { + Ok(()) + } + + fn root(_input: Node) -> ParseResult<()> { + Ok(()) + } + + fn body(_input: Node) -> ParseResult<()> { + Ok(()) + } + + fn separator(_input: Node) -> ParseResult<()> { + Ok(()) + } + + fn num(input: Node) -> ParseResult { + input + .as_str() + .parse::() + .map_err(|_| input.error("Expected non-negative number")) + } + + fn branch(input: Node) -> ParseResult { + let b = input.as_str(); + let result = b != "f"; + Ok(result) + } + + fn clause(input: Node) -> ParseResult { + Ok(match_nodes!(input.into_children(); + [separator(_), num(n)] => ParseNodes::Offset(n), + [separator(_), body(_)] => ParseNodes::Body, + [separator(_), branch(b)] => ParseNodes::If(b) + )) + } + + fn path(input: Node) -> ParseResult { + Ok(match_nodes!(input.into_children(); + [root(_), clause(c).., EOI(_)] => ParsePath::from_iter(c), + )) + } +} + +// Parse the path +#[allow(dead_code)] +pub fn parse_path(input_str: &str) -> Result>> { + let entries = PathParser::parse(Rule::path, input_str)?; + let entry = entries.single()?; + + PathParser::path(entry).map_err(Box::new) +} + +#[cfg(test)] +#[test] +fn root() { + let path = parse_path(".").unwrap(); + dbg!(path.get_path()); + assert_eq!(path.get_path(), Vec::new()) +} + +#[test] +fn body() { + let path = parse_path(".-b").unwrap(); + dbg!(path.get_path()); + assert_eq!(path.get_path(), vec![ParseNodes::Body]) +} + +#[test] +fn branch() { + let path = parse_path(".-f").unwrap(); + dbg!(path.get_path()); + assert_eq!(path.get_path(), vec![ParseNodes::If(false)]) +} + +#[test] +fn offset() { + let path = parse_path(".-0-1").unwrap(); + dbg!(path.get_path()); + assert_eq!( + path.get_path(), + vec![ParseNodes::Offset(0), ParseNodes::Offset(1)] + ) +} + +#[test] +fn multiple() { + let path = parse_path(".-0-1-b-t").unwrap(); + dbg!(path.get_path()); + assert_eq!( + path.get_path(), + vec![ + ParseNodes::Offset(0), + ParseNodes::Offset(1), + ParseNodes::Body, + ParseNodes::If(true) + ] + ) +}