about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorPiotr Czarnecki <pioczarn@gmail.com>2014-10-24 16:24:29 +0100
committerPiotr Czarnecki <pioczarn@gmail.com>2014-10-24 18:07:47 +0100
commit48daba088b0f353cc4fdaba144da7a2c1b1de87f (patch)
treea8199cb09a26454ec55cde8606f3ce44f14f1d6f /src
parente2e47d6eb5425cd860137d632c1b8688e5e74241 (diff)
downloadrust-48daba088b0f353cc4fdaba144da7a2c1b1de87f.tar.gz
rust-48daba088b0f353cc4fdaba144da7a2c1b1de87f.zip
regex: Escaped literals can end ranges
Diffstat (limited to 'src')
-rw-r--r--src/libregex/parse.rs23
-rw-r--r--src/libregex/test/tests.rs11
2 files changed, 28 insertions, 6 deletions
diff --git a/src/libregex/parse.rs b/src/libregex/parse.rs
index 2b6aa669f3c..b7313ff6c1a 100644
--- a/src/libregex/parse.rs
+++ b/src/libregex/parse.rs
@@ -375,15 +375,15 @@ impl<'a> Parser<'a> {
         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 @@ impl<'a> Parser<'a> {
                     }
                     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 '{}-{}'",
diff --git a/src/libregex/test/tests.rs b/src/libregex/test/tests.rs
index fa645c84dd8..4f4137265c0 100644
--- a/src/libregex/test/tests.rs
+++ b/src/libregex/test/tests.rs
@@ -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 @@ noparse!(fail_double_neg, "(?-i-i)")
 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)+) => (