| 264 | } |
| 265 | |
| 266 | fn unescape_string(s: &str) -> Option<String> { |
| 267 | let mut res = String::new(); |
| 268 | let mut chars = s.chars(); |
| 269 | |
| 270 | while let Some(ch) = chars.next() { |
| 271 | if ch == '\\' { |
| 272 | match chars.next() { |
| 273 | Some(delim) => match delim { |
| 274 | '"' => res.push('"'), |
| 275 | '\\' => res.push('\\'), |
| 276 | '/' => res.push('/'), |
| 277 | 'b' => res.push('\x08'), |
| 278 | 'f' => res.push('\x0c'), |
| 279 | 'n' => res.push('\n'), |
| 280 | 'r' => res.push('\r'), |
| 281 | 't' => res.push('\t'), |
| 282 | 'u' => { |
| 283 | let codepoint = chars |
| 284 | .by_ref() |
| 285 | .take(4) |
| 286 | .collect::<String>() |
| 287 | .parse::<u32>() |
| 288 | .ok()?; |
| 289 | match std::char::from_u32(codepoint) { |
| 290 | Some(c) => res.push(c), |
| 291 | None => return None, // invalid unicode codepoint |
| 292 | } |
| 293 | } |
| 294 | _ => return None, |
| 295 | }, |
| 296 | None => return None, |
| 297 | } |
| 298 | } else { |
| 299 | res.push(ch); |
| 300 | } |
| 301 | } |
| 302 | Some(res) |
| 303 | } |
| 304 | |
| 305 | impl StringLiteral { |
| 306 | pub fn get_value(&self) -> String { |