| 292 | } |
| 293 | |
| 294 | fn escape(&mut self) -> Result<Node, ParseError> { |
| 295 | self.bump(); // backslash |
| 296 | let c = self.bump().ok_or(self.err("trailing backslash"))?; |
| 297 | Ok(match c { |
| 298 | 'd' => Node::Class { items: single(ClassItem::Digit), negated: false }, |
| 299 | 'D' => Node::Class { items: single(ClassItem::NotDigit), negated: false }, |
| 300 | 'w' => Node::Class { items: single(ClassItem::Word), negated: false }, |
| 301 | 'W' => Node::Class { items: single(ClassItem::NotWord), negated: false }, |
| 302 | 's' => Node::Class { items: single(ClassItem::Space), negated: false }, |
| 303 | 'S' => Node::Class { items: single(ClassItem::NotSpace), negated: false }, |
| 304 | 'b' => Node::WordBoundary, |
| 305 | 'B' => Node::NotWordBoundary, |
| 306 | 'n' => Node::Char('\n'), |
| 307 | 't' => Node::Char('\t'), |
| 308 | 'r' => Node::Char('\r'), |
| 309 | 'f' => Node::Char('\u{0C}'), |
| 310 | 'v' => Node::Char('\u{0B}'), |
| 311 | 'a' => Node::Char('\u{07}'), |
| 312 | '0' => Node::Char('\0'), |
| 313 | 'x' => Node::Char(self.read_hex(2)?), |
| 314 | 'u' => Node::Char(self.read_hex(4)?), |
| 315 | '1'..='9' => { |
| 316 | let mut n = c.to_digit(10).unwrap() as usize; |
| 317 | while let Some(d) = self.peek().and_then(|x| x.to_digit(10)) { |
| 318 | let cand = n * 10 + d as usize; |
| 319 | if cand <= self.group_count { n = cand; self.bump(); } else { break; } |
| 320 | } |
| 321 | Node::Backref(n) |
| 322 | } |
| 323 | l if l.is_ascii_alphabetic() => return Err(self.err("bad escape")), |
| 324 | other => Node::Char(other), // escaped metacharacter |
| 325 | }) |
| 326 | } |
| 327 | |
| 328 | fn read_hex(&mut self, n: usize) -> Result<char, ParseError> { |
| 329 | let mut acc: u32 = 0; |