diff --git a/Cargo.lock b/Cargo.lock index 367cfae..664c9f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,8 +6,10 @@ version = 3 name = "advent_of_code_2022" version = "0.1.0" dependencies = [ + "nom", "once_cell", "regex", + "thiserror", ] [[package]] @@ -25,12 +27,46 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "once_cell" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + [[package]] name = "regex" version = "1.7.0" @@ -47,3 +83,40 @@ name = "regex-syntax" version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "syn" +version = "2.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/Cargo.toml b/Cargo.toml index 551c369..92627cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,4 +40,6 @@ path="src/day07/solve.rs" [dependencies] regex="1" -once_cell = "1.16.0" +once_cell = "1.16" +nom = "7.1" +thiserror = "1.0" diff --git a/src/day07/parser.rs b/src/day07/parser.rs index 4a05093..f26b534 100644 --- a/src/day07/parser.rs +++ b/src/day07/parser.rs @@ -3,6 +3,11 @@ use crate::file_tree::*; use once_cell::sync::Lazy; use regex::Regex; +static IS_COMMAND_REGEX: Lazy = Lazy::new(|| Regex::new(r"^\$").unwrap()); +static PARSE_CD_REGEX: Lazy = Lazy::new(|| Regex::new(r"^\$ cd (\S*)$").unwrap()); +static PARSE_LS_ENTRY_REGEX: Lazy = + Lazy::new(|| Regex::new(r"^([[:alnum:]]*) (\S*)$").unwrap()); + #[derive(Debug, PartialEq, Eq)] pub enum Command { CdRoot, @@ -21,136 +26,151 @@ pub struct ParseFile { size: usize, name: String, } + +//parses a single line +pub fn parse_to_commands(input: &str) -> Vec { + let mut ret = Vec::new(); + let mut lines = input.lines().peekable(); + while lines.peek().is_some() { + let line = lines.next().unwrap(); + if line == "$ ls" { + ret.push(Command::Ls(parse_ls(&mut lines))); + } else { + let captures = PARSE_CD_REGEX + .captures(line) + .unwrap_or_else(|| panic!("invalid line {}", line)); + + ret.push(match &captures[1] { + ".." => Command::CdUp, + "/" => Command::CdRoot, + s => Command::Cd(s.to_string()), + }) + } + } + ret +} + +fn parse_ls(lines: &mut std::iter::Peekable>) -> Vec { + let mut ret: Vec = Vec::new(); + while lines.peek().is_some() { + // if the next line is a command, then we are at the end of the ls listing. + let line = lines.peek().expect("no next line"); + if IS_COMMAND_REGEX.is_match(line) { + break; + } + let captures = PARSE_LS_ENTRY_REGEX + .captures(line) + .unwrap_or_else(|| panic!("invalid line {}", line)); + ret.push(match &captures[1] { + "dir" => LsEntry::Dir(captures[2].to_string()), + s => LsEntry::File(ParseFile { + size: str::parse(&captures[1]).unwrap_or_else(|_| panic!("invalid line {}", line)), + name: captures[2].to_string(), + }), + }); + lines.next(); + } + ret +} + pub fn parse(input: &str) -> Dir { unimplemented!() } -pub fn parse_to_tree(input: Vec) -> Dir { +pub fn commands_to_tree(input: Vec) -> Dir { unimplemented!() } -//parses a single line -pub fn parse_to_commands(input: &str) -> Vec { - static PARSE_COMMAND_REGEX: Lazy = Lazy::new(|| Regex::new(r"^$").unwrap()); - unimplemented!() -} +#[cfg(test)] +mod tests { + use super::*; -// #[cfg(test)] -// mod tests { -// use super::*; -// -// /* #[test] -// fn test_parse() { -// let input = "$ cd / -// $ ls -// dir a -// 14848514 b.txt -// 8504156 c.dat -// dir d -// $ cd a -// $ ls -// dir e -// 29116 f -// 2557 g -// 62596 h.lst -// $ cd e -// $ ls -// 584 i -// $ cd .. -// $ cd .. -// $ cd d -// $ ls -// 4060174 j -// 8033020 d.log -// 5626152 d.ext -// 7214296 k"; -// assert_eq!(parse(input), 0); -// } */ -// -// #[test] -// fn test_parse_to_commands() { -// let input = "$ cd / -// $ ls -// dir a -// 14848514 b.txt -// 8504156 c.dat -// dir d -// $ cd a -// $ ls -// dir e -// 29116 f -// 2557 g -// 62596 h.lst -// $ cd e -// $ ls -// 584 i -// $ cd .. -// $ cd .. -// $ cd d -// $ ls -// 4060174 j -// 8033020 d.log -// 5626152 d.ext -// 7214296 k"; -// assert_eq!( -// parse_to_commands(input), -// vec![ -// Command::CdRoot, -// Command::Ls(vec![ -// LsEntry::Dir(String::from("a")), -// LsEntry::File(ParseFile { -// size: 14848514, -// name: String::from("b.txt") -// }), -// LsEntry::File(ParseFile { -// size: 8504156, -// name: String::from("c.dat") -// }), -// LsEntry::Dir(String::from("d")) -// ]), -// Command::Cd(String::from("a")), -// Command::Ls(vec![ -// LsEntry::Dir(String::from("e")), -// LsEntry::File(ParseFile { -// size: 29116, -// name: String::from("f") -// }), -// LsEntry::File(ParseFile { -// size: 2557, -// name: String::from("g") -// }), -// LsEntry::File(ParseFile { -// size: 62596, -// name: String::from("h.lst") -// }), -// ]), -// Command::Cd(String::from("e")), -// Command::Ls(vec![LsEntry::File(ParseFile { -// size: 484, -// name: String::from("i") -// }),]), -// Command::CdUp, -// Command::CdUp, -// Command::Cd(String::from("d")), -// Command::Ls(vec![ -// LsEntry::File(ParseFile { -// size: 4060174, -// name: String::from("j") -// }), -// LsEntry::File(ParseFile { -// size: 8033020, -// name: String::from("d.log") -// }), -// LsEntry::File(ParseFile { -// size: 5626152, -// name: String::from("d.ext") -// }), -// LsEntry::File(ParseFile { -// size: 7214296, -// name: String::from("k") -// }), -// ]), -// ] -// ) -// } -// } + #[test] + fn test_parse_to_commands() { + let input = concat!( + "$ cd /\n", + "$ ls\n", + "dir a\n", + "14848514 b.txt\n", + "8504156 c.dat\n", + "dir d\n", + "$ cd a\n", + "$ ls\n", + "dir e\n", + "29116 f\n", + "2557 g\n", + "62596 h.lst\n", + "$ cd e\n", + "$ ls\n", + "584 i\n", + "$ cd ..\n", + "$ cd ..\n", + "$ cd d\n", + "$ ls\n", + "4060174 j\n", + "8033020 d.log\n", + "5626152 d.ext\n", + "7214296 k" + ); + assert_eq!( + parse_to_commands(input), + vec![ + Command::CdRoot, + Command::Ls(vec![ + LsEntry::Dir(String::from("a")), + LsEntry::File(ParseFile { + size: 14848514, + name: String::from("b.txt") + }), + LsEntry::File(ParseFile { + size: 8504156, + name: String::from("c.dat") + }), + LsEntry::Dir(String::from("d")) + ]), + Command::Cd(String::from("a")), + Command::Ls(vec![ + LsEntry::Dir(String::from("e")), + LsEntry::File(ParseFile { + size: 29116, + name: String::from("f") + }), + LsEntry::File(ParseFile { + size: 2557, + name: String::from("g") + }), + LsEntry::File(ParseFile { + size: 62596, + name: String::from("h.lst") + }), + ]), + Command::Cd(String::from("e")), + Command::Ls(vec![LsEntry::File(ParseFile { + size: 584, + name: String::from("i") + }),]), + Command::CdUp, + Command::CdUp, + Command::Cd(String::from("d")), + Command::Ls(vec![ + LsEntry::File(ParseFile { + size: 4060174, + name: String::from("j") + }), + LsEntry::File(ParseFile { + size: 8033020, + name: String::from("d.log") + }), + LsEntry::File(ParseFile { + size: 5626152, + name: String::from("d.ext") + }), + LsEntry::File(ParseFile { + size: 7214296, + name: String::from("k") + }), + ]), + ] + ) + } +}