(&mut self)
| 302 | } |
| 303 | |
| 304 | fn parse_pattern_token(&mut self) -> Result<PatternToken, String> { |
| 305 | self.skip_whitespace(); |
| 306 | if self.consume_literal("\"") { |
| 307 | let mut out = String::new(); |
| 308 | while let Some(c) = self.bump() { |
| 309 | match c { |
| 310 | '\\' => { |
| 311 | if let Some(n) = self.bump() { |
| 312 | out.push(n); |
| 313 | } else { |
| 314 | break; |
| 315 | } |
| 316 | } |
| 317 | '"' => { |
| 318 | return Ok(PatternToken { |
| 319 | text: out, |
| 320 | quoted: true, |
| 321 | }) |
| 322 | } |
| 323 | _ => out.push(c), |
| 324 | } |
| 325 | } |
| 326 | Err("unterminated string literal".into()) |
| 327 | } else { |
| 328 | let start = self.i; |
| 329 | while let Some(c) = self.peek() { |
| 330 | if c.is_whitespace() || c == ')' { |
| 331 | break; |
| 332 | } |
| 333 | // Everything else belongs to the token (including ':', '*', etc.) |
| 334 | self.bump(); |
| 335 | } |
| 336 | if self.i == start { |
| 337 | Err("expected pattern".into()) |
| 338 | } else { |
| 339 | Ok(PatternToken { |
| 340 | text: self.s[start..self.i].to_string(), |
| 341 | quoted: false, |
| 342 | }) |
| 343 | } |
| 344 | } |
| 345 | } |
| 346 | |
| 347 | fn consume_keyword(&mut self, keyword: &str) -> bool { |
| 348 | let save = self.i; |
no test coverage detected