| 232 | } |
| 233 | |
| 234 | fn class(&mut self) -> Result<Node, ParseError> { |
| 235 | self.bump(); // open bracket |
| 236 | let negated = if self.peek() == Some('^') { self.bump(); true } else { false }; |
| 237 | let mut items = Vec::new(); |
| 238 | if self.peek() == Some(']') { items.push(ClassItem::Ch(']')); self.bump(); } |
| 239 | loop { |
| 240 | match self.peek() { |
| 241 | None => return Err(self.err("unterminated character set")), |
| 242 | Some(']') => { self.bump(); break; } |
| 243 | Some('\\') => { self.bump(); items.push(self.class_escape()?); } |
| 244 | Some(c) => { |
| 245 | self.bump(); |
| 246 | let is_range = self.peek() == Some('-') |
| 247 | && self.at(1).is_some() |
| 248 | && self.at(1) != Some(']'); |
| 249 | if is_range { |
| 250 | self.bump(); // dash |
| 251 | let end = if self.peek() == Some('\\') { |
| 252 | self.bump(); |
| 253 | match self.class_escape()? { |
| 254 | ClassItem::Ch(e) => e, |
| 255 | _ => return Err(self.err("bad character range")), |
| 256 | } |
| 257 | } else { |
| 258 | self.bump().unwrap() |
| 259 | }; |
| 260 | if (end as u32) < (c as u32) { return Err(self.err("bad character range")); } |
| 261 | items.push(ClassItem::Range(c, end)); |
| 262 | } else { |
| 263 | items.push(ClassItem::Ch(c)); |
| 264 | } |
| 265 | } |
| 266 | } |
| 267 | } |
| 268 | Ok(Node::Class { items, negated }) |
| 269 | } |
| 270 | |
| 271 | fn class_escape(&mut self) -> Result<ClassItem, ParseError> { |
| 272 | let c = self.bump().ok_or(self.err("trailing backslash"))?; |