diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..8d1ef77 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,36 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug executable 'eyes'", + "cargo": { + "args": ["build", "--bin=eyes", "--package=eyes"], + "filter": { + "name": "eyes", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in executable 'eyes'", + "cargo": { + "args": ["test", "--no-run", "--bin=eyes", "--package=eyes"], + "filter": { + "name": "eyes", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} diff --git a/Cargo.toml b/Cargo.toml index 54b79f8..b98b91e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,5 +2,6 @@ name = "eyes" version = "0.1.0" edition = "2018" +license-file="LICENSE.txt" [dependencies] diff --git a/LICENSE b/LICENSE.txt similarity index 100% rename from LICENSE rename to LICENSE.txt diff --git a/src/lib.rs b/src/lib.rs index 97f1ac1..41d9362 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,30 +1,42 @@ pub struct Parser<'a> { - _input: &'a str, - _pattern: &'a str, captures: Vec<&'a str>, } impl<'a> Parser<'a> { - pub fn new(input: &'a str, pattern: &'a str) -> Self { - let splits = pattern + pub fn new(input: &'a str, template: &'a str) -> Self { + let patterns = template .split("{}") .filter(|pat| pat != &"") .collect::>(); let mut captures = vec![input]; - for pat in splits { - captures = captures - .iter() - .map(|sub| sub.split(pat)) - .flatten() - .collect(); + for (i, pat) in patterns.iter().enumerate() { + let last = captures.pop().unwrap(); + let (mut left, mut right) = last.split_once(pat).unwrap(); + + // if the right side of the split doesn't contain the pattern, + // we don't have to check if we can expand the match + if right.contains(pat) { + let mut pattern_index = right.find(pat).unwrap() + left.len(); + let next_pattern_index = right.find(patterns[i + 1]).unwrap() + left.len(); + + while next_pattern_index > pattern_index { + let (left_side, _) = input.split_at(pattern_index + 1); + left = left_side; + let (_, right_side) = input.split_at(pattern_index + 1 + pat.len()); + right = right_side; + + pattern_index = right.find(pat).unwrap_or(input.len()) + left.len(); + } + } + + if !left.is_empty() { + captures.push(left); + } + captures.push(right); } - Self { - _input: input, - _pattern: pattern, - captures: captures[1..].to_vec(), - } + Self { captures } } pub fn captures(&self) -> Vec<&'a str> { @@ -36,15 +48,11 @@ impl<'a> Parser<'a> { macro_rules! parse { ($input: expr, $pattern: tt, $($type:ty),*) => { { - let mut parser = eyes::Parser::new($input, $pattern); - let mut captures = parser.captures(); - captures.reverse(); + let parser = $crate::Parser::new($input, $pattern); + let captures = parser.captures(); + let mut iter = captures.iter(); - ( - $({ - captures.pop().unwrap().parse::<$type>().unwrap() - },)* - ) + ($(iter.next().unwrap().parse::<$type>().unwrap()),*) } }; } @@ -53,15 +61,56 @@ macro_rules! parse { macro_rules! try_parse { ($input: expr, $pattern: tt, $($type:ty),*) => { { - let mut parser = eyes::Parser::new($input, $pattern); - let mut captures = parser.captures(); - captures.reverse(); + let parser = $crate::Parser::new($input, $pattern); + let captures = parser.captures(); + let mut iter = captures.iter(); - ( - $({ - captures.pop().unwrap().parse::<$type>() - },)* - ) + ($(iter.next().unwrap().parse::<$type>()),*) } }; } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn simple_test() { + // Test where the patterns in the template are all different + let input = "#lol @ 338,7643: 20.2x24.5"; + let template = "#{} @ {},{}: {}x{}"; + + println!("input: '{}'", input); + println!("pattern: '{}'", template); + + let (id, x, y, w, h) = parse!(input, template, String, isize, isize, f64, f64); + + println!("id: {:?}", id); + println!("x: {:?}", x); + println!("y: {:?}", y); + println!("w: {:?}", w); + println!("h: {:?}", h); + + assert_eq!((id.as_str(), x, y, w, h), ("lol", 338, 7643, 20.2, 24.5)); + } + + #[test] + fn tries_to_expand_correctly() { + let input = "turn off 660,55 through 986,197"; + let template = "{} {},{} through {},{}"; + + println!("input: '{}'", input); + println!("pattern: '{}'", template); + + let (op, x1, y1, x2, y2) = try_parse!(input, template, String, usize, usize, usize, usize); + + println!("op: {:?}", op); + println!("p1: {:?}", (&x1, &y1)); + println!("p2: {:?}", (&x2, &y2)); + + assert_eq!( + (op.unwrap().as_str(), x1, y1, x2, y2), + ("turn off", Ok(660), Ok(55), Ok(986), Ok(197)) + ); + } +} diff --git a/src/main.rs b/src/main.rs index f92ec93..8b1ddfc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,15 @@ use eyes::*; fn main() { - let input = "#loll1 @ 338,764: 20x24"; - let pattern = "#{} @ {},{}: {}x{}"; + let input = "turn off 660,55 through 986,197"; + let template = "{} {},{} through {},{}"; - println!("input: {}", input); - println!("pattern: {}", pattern); + println!("input: '{}'", input); + println!("pattern: '{}'", template); - let (id, x, y, w, h) = parse!(input, pattern, String, f64, f32, usize, isize); + let (op, x1, y1, x2, y2) = try_parse!(input, template, String, usize, usize, usize, usize); - println!("id: {:?}", id); - println!("x: {:?}", x); - println!("y: {:?}", y); - println!("w: {:?}", w); - println!("h: {:?}", h); + println!("op: {:?}", op); + println!("p1: {:?}", (x1, y1)); + println!("p2: {:?}", (x2, y2)); }