String parsing

This commit is contained in:
Timothy Warren 2020-02-07 22:55:09 -05:00
parent 72c3eecf21
commit 0993780c89

View File

@ -4,6 +4,7 @@
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
use std::collections::HashMap; use std::collections::HashMap;
use std::iter::FromIterator; use std::iter::FromIterator;
use std::{char, u16};
/// The type of JSON value /// The type of JSON value
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -194,17 +195,56 @@ impl JSON {
let mut result = String::new(); let mut result = String::new();
while self.chars[self.i] != '"' { while self.chars[self.i] != '"' {
// All the escape sequences...
if self.chars[self.i] == '\\' { if self.chars[self.i] == '\\' {
todo!(); let ch = self.chars[self.i + 1];
if ['"', '\\', '/'].contains(&ch) {
let escaped = ch.escape_default().next().unwrap_or(ch);
result.push(escaped);
self.i += 1;
} else if ['b', 'f', 'n', 'r', 't'].contains(&ch) {
let ch = match ch {
'b' => '\u{8}',
'f' => '\x0C',
'n' => '\n',
'r' => '\r',
't' => '\t',
_ => panic!("Shouldn't be possible!"),
};
result.push(ch);
self.i += 1;
} else if ch == 'u'
&& self.chars[self.i + 2].is_ascii_hexdigit()
&& self.chars[self.i + 3].is_ascii_hexdigit()
&& self.chars[self.i + 4].is_ascii_hexdigit()
&& self.chars[self.i + 5].is_ascii_hexdigit()
{
// Blech, parse out a JSON unicode (utf16) escape code. Handles surrogate pairs
// by giving you the replacement character...because...yeah
let char_str = String::from_iter(&self.chars[self.i + 2..=self.i + 5]);
let code = u16::from_str_radix(&char_str, 16)
.expect("Failed to parse unicode escape number");
let string = String::from_utf16_lossy(&[code]);
result.push_str(&string);
self.i += 5;
} }
} else {
result.push(self.chars[self.i]);
}
self.i += 1;
} }
Ok(None) self.i += 1;
Ok(Some(JSONValue::String(result)))
} }
/// See if there's a `JSONValue::Number` next in the JSON /// See if there's a `JSONValue::Number` next in the JSON
fn parse_number(&mut self) -> Result<Option<JSONValue>, ParseError> { fn parse_number(&mut self) -> Result<Option<JSONValue>, ParseError> {
Ok(None) todo!();
} }
/// See if there's a `JSONValue::True`, `JSONValue::False`, or a `JSONValue::Null` next in the JSON /// See if there's a `JSONValue::True`, `JSONValue::False`, or a `JSONValue::Null` next in the JSON
@ -281,6 +321,17 @@ mod tests {
assert_eq!('x', parser.chars[parser.i]); assert_eq!('x', parser.chars[parser.i]);
} }
#[test]
fn parse_string() {
let mut parser = JSON::new(r#""\t""#);
let res = JSON::parse_string(&mut parser);
assert_eq!(res, Ok(Some(JSONValue::String(String::from("\t")))));
let mut parser = JSON::new(r#""\u203d""#);
let res = JSON::parse_string(&mut parser);
assert_eq!(res, Ok(Some(JSONValue::String(String::from("")))));
}
#[test] #[test]
fn parse_empty_array() { fn parse_empty_array() {
let mut parser = JSON::new("[]"); let mut parser = JSON::new("[]");