(&self, line: &mut std::str::Chars<'a>)
| 203 | |
| 204 | impl<'cx, 'tcx> Builder<'cx, 'tcx> { |
| 205 | fn lex_word<'a>(&self, line: &mut std::str::Chars<'a>) -> Option<Token<'a, 'cx, 'tcx>> { |
| 206 | loop { |
| 207 | let start = line.as_str(); |
| 208 | match line.next()? { |
| 209 | // skip over leading whitespace |
| 210 | ch if ch.is_whitespace() => continue, |
| 211 | // lex a string |
| 212 | '"' => { |
| 213 | let mut cooked = String::new(); |
| 214 | loop { |
| 215 | match line.next() { |
| 216 | None => { |
| 217 | self.err("Unterminated string in instruction"); |
| 218 | return None; |
| 219 | } |
| 220 | Some('"') => break, |
| 221 | Some('\\') => { |
| 222 | let escape = match line.next() { |
| 223 | None => { |
| 224 | self.err("Unterminated string in instruction"); |
| 225 | return None; |
| 226 | } |
| 227 | Some('n') => '\n', |
| 228 | Some('r') => '\r', |
| 229 | Some('t') => '\t', |
| 230 | Some('0') => '\0', |
| 231 | Some('\\') => '\\', |
| 232 | Some('\'') => '\'', |
| 233 | Some('"') => '"', |
| 234 | Some(escape) => { |
| 235 | self.err(&format!("invalid escape '\\{escape}'")); |
| 236 | return None; |
| 237 | } |
| 238 | }; |
| 239 | cooked.push(escape); |
| 240 | } |
| 241 | Some(ch) => { |
| 242 | cooked.push(ch); |
| 243 | } |
| 244 | } |
| 245 | } |
| 246 | break Some(Token::String(cooked)); |
| 247 | } |
| 248 | // lex a word |
| 249 | _ => { |
| 250 | let end = loop { |
| 251 | let end = line.as_str(); |
| 252 | match line.next() { |
| 253 | Some(ch) if !ch.is_whitespace() => continue, |
| 254 | _ => break end, |
| 255 | } |
| 256 | }; |
| 257 | let word = &start[..(start.len() - end.len())]; |
| 258 | break Some(Token::Word(word)); |
| 259 | } |
| 260 | } |
| 261 | } |
| 262 | } |
no test coverage detected