]> git.lizzy.rs Git - rust.git/commitdiff
regex: Escaped literals can end ranges
authorPiotr Czarnecki <pioczarn@gmail.com>
Fri, 24 Oct 2014 15:24:29 +0000 (16:24 +0100)
committerPiotr Czarnecki <pioczarn@gmail.com>
Fri, 24 Oct 2014 17:07:47 +0000 (18:07 +0100)
src/libregex/parse.rs
src/libregex/test/tests.rs

index 2b6aa669f3c212b628c1acc762eed6354e09a813..b7313ff6c1a1f17adac333795f4a59e2e7d9a2e6 100644 (file)
@@ -375,15 +375,15 @@ fn parse_class(&mut self) -> Result<(), Error> {
         let mut alts: Vec<Ast> = vec!();
 
         if self.peek_is(1, ']') {
-            try!(self.expect(']'))
+            try!(self.expect(']'));
             ranges.push((']', ']'))
         }
         while self.peek_is(1, '-') {
-            try!(self.expect('-'))
+            try!(self.expect('-'));
             ranges.push(('-', '-'))
         }
         loop {
-            try!(self.noteof("a closing ']' or a non-empty character class)"))
+            try!(self.noteof("a closing ']' or a non-empty character class)"));
             let mut c = self.cur();
             match c {
                 '[' =>
@@ -428,12 +428,23 @@ fn parse_class(&mut self) -> Result<(), Error> {
                     }
                     return Ok(())
                 }
+                _ => {}
             }
 
             if self.peek_is(1, '-') && !self.peek_is(2, ']') {
-                try!(self.expect('-'))
-                try!(self.noteof("not a ']'"))
-                let c2 = self.cur();
+                try!(self.expect('-'));
+                // The regex can't end here.
+                try!(self.noteof("not a ']'"));
+                // End the range with a single character or character escape.
+                let mut c2 = self.cur();
+                if c2 == '\\' {
+                    match try!(self.parse_escape()) {
+                        Literal(c3, _) => c2 = c3, // allow literal escapes below
+                        ast =>
+                            return self.err(format!("Expected a literal, but got {}.",
+                                                    ast).as_slice()),
+                    }
+                }
                 if c2 < c {
                     return self.err(format!("Invalid character class \
                                              range '{}-{}'",
index fa645c84dd86d5c98eb6bd95462c9fda38cb6ae4..4f4137265c0311730e7aaf0907e445352f6f8a53 100644 (file)
@@ -53,6 +53,13 @@ fn quoted_bracket_set() {
     assert_eq!(ms, vec![(0, 1), (1, 2)]);
 }
 
+#[test]
+fn range_ends_with_escape() {
+    let re = regex!(r"([\[-\x{5d}])");
+    let ms = re.find_iter("[]").collect::<Vec<(uint, uint)>>();
+    assert_eq!(ms, vec![(0, 1), (1, 2)]);
+}
+
 macro_rules! replace(
     ($name:ident, $which:ident, $re:expr,
      $search:expr, $replace:expr, $result:expr) => (
@@ -124,6 +131,10 @@ fn $name() {
 noparse!(fail_neg_empty, "(?i-)")
 noparse!(fail_empty_group, "()")
 noparse!(fail_dupe_named, "(?P<a>.)(?P<a>.)")
+noparse!(fail_range_end_no_class, "[a-[:lower:]]")
+noparse!(fail_range_end_no_begin, r"[a-\A]")
+noparse!(fail_range_end_no_end, r"[a-\z]")
+noparse!(fail_range_end_no_boundary, r"[a-\b]")
 
 macro_rules! mat(
     ($name:ident, $re:expr, $text:expr, $($loc:tt)+) => (