Skip to content

Commit 48daba0

Browse files
committed
regex: Escaped literals can end ranges
1 parent e2e47d6 commit 48daba0

File tree

2 files changed

+28
-6
lines changed

2 files changed

+28
-6
lines changed

src/libregex/parse.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -375,15 +375,15 @@ impl<'a> Parser<'a> {
375375
let mut alts: Vec<Ast> = vec!();
376376

377377
if self.peek_is(1, ']') {
378-
try!(self.expect(']'))
378+
try!(self.expect(']'));
379379
ranges.push((']', ']'))
380380
}
381381
while self.peek_is(1, '-') {
382-
try!(self.expect('-'))
382+
try!(self.expect('-'));
383383
ranges.push(('-', '-'))
384384
}
385385
loop {
386-
try!(self.noteof("a closing ']' or a non-empty character class)"))
386+
try!(self.noteof("a closing ']' or a non-empty character class)"));
387387
let mut c = self.cur();
388388
match c {
389389
'[' =>
@@ -428,12 +428,23 @@ impl<'a> Parser<'a> {
428428
}
429429
return Ok(())
430430
}
431+
_ => {}
431432
}
432433

433434
if self.peek_is(1, '-') && !self.peek_is(2, ']') {
434-
try!(self.expect('-'))
435-
try!(self.noteof("not a ']'"))
436-
let c2 = self.cur();
435+
try!(self.expect('-'));
436+
// The regex can't end here.
437+
try!(self.noteof("not a ']'"));
438+
// End the range with a single character or character escape.
439+
let mut c2 = self.cur();
440+
if c2 == '\\' {
441+
match try!(self.parse_escape()) {
442+
Literal(c3, _) => c2 = c3, // allow literal escapes below
443+
ast =>
444+
return self.err(format!("Expected a literal, but got {}.",
445+
ast).as_slice()),
446+
}
447+
}
437448
if c2 < c {
438449
return self.err(format!("Invalid character class \
439450
range '{}-{}'",

src/libregex/test/tests.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ fn quoted_bracket_set() {
5353
assert_eq!(ms, vec![(0, 1), (1, 2)]);
5454
}
5555

56+
#[test]
57+
fn range_ends_with_escape() {
58+
let re = regex!(r"([\[-\x{5d}])");
59+
let ms = re.find_iter("[]").collect::<Vec<(uint, uint)>>();
60+
assert_eq!(ms, vec![(0, 1), (1, 2)]);
61+
}
62+
5663
macro_rules! replace(
5764
($name:ident, $which:ident, $re:expr,
5865
$search:expr, $replace:expr, $result:expr) => (
@@ -124,6 +131,10 @@ noparse!(fail_double_neg, "(?-i-i)")
124131
noparse!(fail_neg_empty, "(?i-)")
125132
noparse!(fail_empty_group, "()")
126133
noparse!(fail_dupe_named, "(?P<a>.)(?P<a>.)")
134+
noparse!(fail_range_end_no_class, "[a-[:lower:]]")
135+
noparse!(fail_range_end_no_begin, r"[a-\A]")
136+
noparse!(fail_range_end_no_end, r"[a-\z]")
137+
noparse!(fail_range_end_no_boundary, r"[a-\b]")
127138

128139
macro_rules! mat(
129140
($name:ident, $re:expr, $text:expr, $($loc:tt)+) => (

0 commit comments

Comments
 (0)