Skip to content

Commit

Permalink
Make ... the "default" interline syntax again.
Browse files Browse the repository at this point in the history
  • Loading branch information
ltratt committed May 17, 2024
1 parent 4e83550 commit b71e3df
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 75 deletions.
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ match parts of a line and to skip multiple lines of text. For example this

```text
...A
..?
...
D...
```

Expand Down Expand Up @@ -44,7 +44,7 @@ backtracking will not occur before the anchor). An item is either:

The interline wildcards are:

* `..?` matches until it finds a match for the line immediately after the
* `...` matches until it finds a match for the line immediately after the
interline operator, at which point the search is anchored.

* `..~` matches until it finds a match for the next group, at which point the
Expand All @@ -54,10 +54,10 @@ Consider this pattern:

```text
A
..?
...
B
C
..?
...
```

This will match successfully against the literal:
Expand All @@ -81,7 +81,7 @@ C
E
```

because the `..?` matched against the first "B", anchored the search, then
because the `...` matched against the first "B", anchored the search, then
immediately failed to match against the second "B".

In contrast the pattern:
Expand All @@ -91,15 +91,15 @@ A
..~
B
C
..?
...
```

will, through backtracing, successfully match the literal.

There are two reasons why you should default to using `..?` rather than `..~`.
Most obviously `..?` does not backtrack and has linear performance. Less
obviously `..?` prevents literals from matching when they contain multiple
similar sequences. Informally, `..?` makes for more rigorous testing: `..?` can
There are two reasons why you should default to using `...` rather than `..~`.
Most obviously `...` does not backtrack and has linear performance. Less
obviously `...` prevents literals from matching when they contain multiple
similar sequences. Informally, `...` makes for more rigorous testing: `...` can
be thought of as "the next thing that matches must look like X" whereas `..~`
says "skip things that are almost like X until you find something that is
definitely X".
Expand All @@ -113,8 +113,8 @@ use fm::FMatcher;
assert!(FMatcher::new("a").unwrap().matches("a").is_ok());
assert!(FMatcher::new(" a ").unwrap().matches("a").is_ok());
assert!(FMatcher::new("a").unwrap().matches("b").is_err());
assert!(FMatcher::new("a\n..?\nb").unwrap().matches("a\na\nb").is_ok());
assert!(FMatcher::new("a\n..?\nb").unwrap().matches("a\na\nb\nb").is_err());
assert!(FMatcher::new("a\n...\nb").unwrap().matches("a\na\nb").is_ok());
assert!(FMatcher::new("a\n...\nb").unwrap().matches("a\na\nb\nb").is_err());
```

When a match fails, the matcher returns an error indicating the line number at
Expand Down
104 changes: 41 additions & 63 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::{
use regex::Regex;

const ERROR_CONTEXT: usize = 3;
const LINE_ANCHOR_WILDCARD: &str = "..?";
const LINE_ANCHOR_WILDCARD: &str = "...";
const GROUP_ANCHOR_WILDCARD: &str = "..~";
const INTRALINE_WILDCARD: &str = "...";
const ERROR_MARKER: &str = ">>";
Expand Down Expand Up @@ -187,15 +187,6 @@ impl<'a> FMBuilder<'a> {
fn validate(&self) -> Result<(), Box<dyn Error>> {
let lines = self.ptn.lines().map(|x| x.trim()).collect::<Vec<_>>();

for (i, l) in lines.iter().enumerate() {
if *l == "..." {
return Err(Box::<dyn Error>::from(format!(
"'...' interline syntax on line {} is deprecated: use '..?' instead",
i + 1
)));
}
}

for i in 0..lines.len() {
if i < lines.len() - 1
&& (lines[i] == LINE_ANCHOR_WILDCARD || lines[i] == GROUP_ANCHOR_WILDCARD)
Expand Down Expand Up @@ -674,19 +665,19 @@ mod tests {
assert!(helper("", "\n"));
assert!(helper("a", "a"));
assert!(!helper("a", "ab"));
assert!(helper("..?", ""));
assert!(helper("..?", "a"));
assert!(helper("..?", "a\nb"));
assert!(helper("..?\na", "a"));
assert!(helper("..?\na\n..?", "a"));
assert!(helper("a\n..?", "a"));
assert!(helper("a\n..?\nd", "a\nd"));
assert!(helper("a\n..?\nd", "a\nb\nc\nd"));
assert!(!helper("a\n..?\nd", "a\nb\nc"));
assert!(helper("a\n..?\nc\n..?\ne", "a\nb\nc\nd\ne"));
assert!(helper("a\n..?\n...b", "a\nb"));
assert!(helper("a\n..?\nb...", "a\nb"));
assert!(helper("a\n..?\nb...", "a\nbc"));
assert!(helper("...", ""));
assert!(helper("...", "a"));
assert!(helper("...", "a\nb"));
assert!(helper("...\na", "a"));
assert!(helper("...\na\n...", "a"));
assert!(helper("a\n...", "a"));
assert!(helper("a\n...\nd", "a\nd"));
assert!(helper("a\n...\nd", "a\nb\nc\nd"));
assert!(!helper("a\n...\nd", "a\nb\nc"));
assert!(helper("a\n...\nc\n...\ne", "a\nb\nc\nd\ne"));
assert!(helper("a\n...\n...b", "a\nb"));
assert!(helper("a\n...\nb...", "a\nb"));
assert!(helper("a\n...\nb...", "a\nbc"));
assert!(helper("a\nb...", "a\nbc"));
assert!(!helper("a\nb...", "a\nb\nc"));
assert!(helper("a\n...b...", "a\nb"));
Expand All @@ -696,7 +687,7 @@ mod tests {
assert!(!helper("a\n...b...", "a\nxb\nc"));
assert!(!helper("a", "a\nb"));
assert!(!helper("a\nb", "a"));
assert!(!helper("a\n..?\nb", "a"));
assert!(!helper("a\n...\nb", "a"));
assert!(helper("a\n", "a\n"));
assert!(helper("a\n", "a"));
assert!(helper("a", "a\n"));
Expand Down Expand Up @@ -724,10 +715,10 @@ mod tests {
assert!(helper("a\n..~\nc\nd\n", "a\nc\ne\nc\nd"));
assert!(helper("a\n..~\nc\nd\ne", "a\nc\ne\nc\nd\ne"));
assert!(helper("a\n..~\nc\n..~", "a\nb\nc"));
assert!(helper("a\n..~\nc\n..?", "a\nb\nc"));
assert!(helper("a\n..~\nc\n...", "a\nb\nc"));
assert!(helper("a\n..~\nc\n..~\nd", "a\nb\nc\nd"));
assert!(!helper("a\n..~\nc\n..~\nd", "a\nb\nc\ne"));
assert!(helper("a\n..~\nc\n..?\nd", "a\nb\nc\nd"));
assert!(helper("a\n..~\nc\n...\nd", "a\nb\nc\nd"));
assert!(helper("a\n..~\nc\n..~\nd", "a\nb\nc\ne\nf\nd"));
assert!(helper("a\n..~\nc\nd\n..~\nd", "a\nb\nc\nd\nd"));
assert!(!helper("a\n..~\nc\nd\n..~\nd", "a\nb\nc\nd"));
Expand Down Expand Up @@ -778,22 +769,22 @@ mod tests {
assert!(helper("", ""));
assert!(helper("a", "a"));
assert!(!helper("a", "ab"));
assert!(helper("..?", ""));
assert!(helper("..?", "a"));
assert!(helper("...", ""));
assert!(helper("...", "a"));
assert!(helper("......", "a"));
assert!(!helper("......", ""));
assert!(helper("..?", "a\nb"));
assert!(helper("...", "a\nb"));
assert!(!helper("......", "a\nb"));
assert!(helper("..?\na", "a"));
assert!(helper("..?\na\n..?", "a"));
assert!(helper("a\n..?", "a"));
assert!(helper("a\n..?\nd", "a\nd"));
assert!(helper("a\n..?\nd", "a\nb\nc\nd"));
assert!(!helper("a\n..?\nd", "a\nb\nc"));
assert!(helper("a\n..?\nc\n..?\ne", "a\nb\nc\nd\ne"));
assert!(helper("a\n..?\n...b", "a\nb"));
assert!(helper("a\n..?\nb...", "a\nb"));
assert!(helper("a\n..?\nb...", "a\nbc"));
assert!(helper("...\na", "a"));
assert!(helper("...\na\n...", "a"));
assert!(helper("a\n...", "a"));
assert!(helper("a\n...\nd", "a\nd"));
assert!(helper("a\n...\nd", "a\nb\nc\nd"));
assert!(!helper("a\n...\nd", "a\nb\nc"));
assert!(helper("a\n...\nc\n...\ne", "a\nb\nc\nd\ne"));
assert!(helper("a\n...\n...b", "a\nb"));
assert!(helper("a\n...\nb...", "a\nb"));
assert!(helper("a\n...\nb...", "a\nbc"));
assert!(helper("a\nb...", "a\nbc"));
assert!(!helper("a\nb...", "a\nb\nc"));
assert!(helper("a\n...b...", "a\nb"));
Expand All @@ -812,7 +803,7 @@ mod tests {
assert!(helper("$1, $1, a", "a, a, a"));
assert!(!helper("$1, $1, a", "a, a, b"));
assert!(!helper("$1, $1, a", "a, b, a"));
assert!(helper("$1 $2\n..?\n$3 $2", "a X\nb Y\nc X"));
assert!(helper("$1 $2\n...\n$3 $2", "a X\nb Y\nc X"));
assert!(!helper("ab$a", "a"));
assert!(helper("$1\n$1...", "a\na b c"));
assert!(!helper("$1\n$1...", "a\nb b c"));
Expand Down Expand Up @@ -849,7 +840,7 @@ mod tests {
assert!(helper("$1, $1, a", "a, a, a"));
assert!(!helper("$1, $1, a", "a, a, b"));
assert!(!helper("$1, $1, a", "a, b, a"));
assert!(helper("$1 $2\n..?\n$3 $2", "a X\nb Y\nc X"));
assert!(helper("$1 $2\n...\n$3 $2", "a X\nb Y\nc X"));
assert!(!helper("ab$a", "a"));
assert!(helper("$1\n$1...", "a\na b c"));
assert!(!helper("$1\n$1...", "a\nb b c"));
Expand All @@ -869,7 +860,7 @@ mod tests {
assert!(helper("&1, &1, a", "a, a, a"));
assert!(!helper("&1, &1, a", "a, a, b"));
assert!(!helper("&1, &1, a", "a, b, a"));
assert!(helper("&1 &2\n..?\n&3 &2", "a X\nb Y\nc X"));
assert!(helper("&1 &2\n...\n&3 &2", "a X\nb Y\nc X"));
assert!(!helper("ab&a", "a"));
assert!(helper("&1\n&1...", "a\na b c"));
assert!(!helper("&1\n&1...", "a\nb b c"));
Expand All @@ -884,7 +875,7 @@ mod tests {
assert!(helper("$1 &1 $1", "a b a"));
assert!(helper("$1 &1 &1", "a b b"));
assert!(!helper("$1 &1 &1", "a b a"));
assert!(helper("$1 &2\n..?\n$3 &2", "a X\nb Y\nc X"));
assert!(helper("$1 &2\n...\n$3 &2", "a X\nb Y\nc X"));
assert!(helper("$1 &1\n$1 &1...", "a b\na b c d"));
assert!(helper("$1 &1\n$1 &1...", "a b\na b"));
assert!(!helper("$1 &1\n$1 &1...", "a b\na a c d"));
Expand Down Expand Up @@ -914,7 +905,7 @@ mod tests {
(err.ptn_line_off(), err.text_line_off())
};

assert_eq!(helper("a\n..?\nd", "a\nb\nc"), (3, 3));
assert_eq!(helper("a\n...\nd", "a\nb\nc"), (3, 3));
assert_eq!(helper("a\nb...", "a\nb\nc"), (3, 3));
assert_eq!(helper("a\n...b...", "a\nxb\nc"), (3, 3));

Expand All @@ -935,9 +926,9 @@ mod tests {
assert_eq!(helper("$1\n$1\na", "a\na\nb"), (3, 3));
assert_eq!(helper("$1\n$1\na", "a\nb\na"), (2, 2));

assert_eq!(helper("..?\nb\nc\nd\n", "a\nb\nc\n0\ne"), (4, 4));
assert_eq!(helper("..?\nc\nd\n", "a\nb\nc\n0\ne"), (3, 4));
assert_eq!(helper("..?\nd\n", "a\nb\nc\n0\ne"), (2, 5));
assert_eq!(helper("...\nb\nc\nd\n", "a\nb\nc\n0\ne"), (4, 4));
assert_eq!(helper("...\nc\nd\n", "a\nb\nc\n0\ne"), (3, 4));
assert_eq!(helper("...\nd\n", "a\nb\nc\n0\ne"), (2, 5));

assert_eq!(helper("a\n..~\nc\nd\ne", "a\nb\nc\nd"), (2, 2));
assert_eq!(helper("a\n..~\nc\nd", "a\nb\nc\ne"), (2, 2));
Expand Down Expand Up @@ -974,7 +965,7 @@ mod tests {

#[test]
fn consecutive_wildcards_disallowed() {
match FMatcher::new("..?\n..?") {
match FMatcher::new("...\n...") {
Err(e)
if e.to_string()
== "Can't have two consecutive interline wildcards lines at lines 1 and 2." =>
Expand All @@ -984,7 +975,7 @@ mod tests {
x => panic!("{x:?}"),
}

match FMatcher::new("..~\n..?") {
match FMatcher::new("..~\n...") {
Err(e)
if e.to_string()
== "Can't have two consecutive interline wildcards lines at lines 1 and 2." =>
Expand All @@ -994,7 +985,7 @@ mod tests {
x => panic!("{x:?}"),
}

match FMatcher::new("a\nb\n..?\n..~") {
match FMatcher::new("a\nb\n...\n..~") {
Err(e)
if e.to_string()
== "Can't have two consecutive interline wildcards lines at lines 3 and 4." =>
Expand All @@ -1005,19 +996,6 @@ mod tests {
}
}

#[test]
fn syntax_deprecation() {
match FMatcher::new("...") {
Err(e)
if e.to_string()
== "'...' interline syntax on line 1 is deprecated: use '..?' instead" =>
{
()
}
x => panic!("{x:?}"),
}
}

#[test]
fn wildcards_and_names() {
let ptn_re = Regex::new("\\$.+?\\b").unwrap();
Expand Down

0 comments on commit b71e3df

Please sign in to comment.