json-parser/src/lib.rs

184 lines
4.3 KiB
Rust

use std::collections::HashMap;
use std::iter::FromIterator;
use crate::ParseError::UnexpectedEndOfInput;
#[derive(Debug, PartialEq)]
pub enum JSONValue {
Object(HashMap<String, JSONValue>),
Array(Vec<JSONValue>),
String(String),
Number(f64),
True,
False,
Null,
}
#[derive(Debug)]
pub enum ParseError {
UnexpectedEndOfInput(String),
ExpectedEndOfInput(String),
ExpectedObjectKey(String),
ExpectedToken(String),
UnexpectedToken(String),
ExpectedDigit(String),
ExpectedEscapeChar(String),
ExpectedUnicodeEscape(String),
}
#[derive(Debug)]
pub struct JSON {
chars: Vec<char>,
i: usize
}
pub type JSONResult = Result<JSONValue, ParseError>;
type PartialResult = Result<Option<JSONValue>, ParseError>;
impl JSON {
fn new(json: &str) -> Self {
JSON {
chars: json.chars().collect(),
i: 0
}
}
fn parse_value(&mut self) -> JSONResult {
self.skip_whitespace();
let mut types = self.parse_string()?.into_iter()
.chain(self.parse_number()?.into_iter())
.chain(self.parse_object()?.into_iter())
.chain(self.parse_array()?.into_iter())
.chain(self.parse_keyword("true", JSONValue::True)?.into_iter())
.chain(self.parse_keyword("false", JSONValue::False)?.into_iter())
.chain(self.parse_keyword("null", JSONValue::Null)?.into_iter());
match types.next() {
Some(val) => Ok(val),
None => Err(UnexpectedEndOfInput(String::new()))
}
}
fn parse_object(&mut self) -> PartialResult {
if self.chars[self.i] != '{' {
return Ok(None);
}
self.i += 1;
self.skip_whitespace();
let mut result: HashMap<String, JSONValue> = HashMap::new();
let mut initial = true;
// if it is not '}',
// we take the path of string -> whitespace -> ':' -> value -> ...
while self.chars[self.i] != '}' {
if initial == false {
self.eat_char(',')?;
self.skip_whitespace();
}
let key = match self.parse_string()? {
Some(value) => match value {
JSONValue::String(s) => s,
_ => panic!("parse_string returned non-string value"),
},
None => String::new()
};
self.skip_whitespace();
self.eat_char(':')?;
let value = self.parse_value()?;
result.insert(key, value);
initial = false;
}
// Move to the next character: '}'
self.i += 1;
Ok(Some(JSONValue::Object(result)))
}
fn parse_array(&mut self) -> PartialResult {
if self.chars[self.i] != '[' {
return Ok(None);
}
self.i += 1;
self.skip_whitespace();
let mut result: Vec<JSONValue> = vec![];
let mut initial = true;
while self.chars[self.i] != ']' {
if initial == false {
self.eat_char(',')?;
}
let value = self.parse_value()?;
result.push(value);
initial = false;
}
// move to next character: ']'
self.i += 1;
Ok(Some(JSONValue::Array(result)))
}
fn parse_string(&mut self) -> PartialResult {
todo!();
}
fn parse_number(&mut self) -> PartialResult {
todo!();
}
fn parse_keyword(&mut self, search: &str, value: JSONValue) -> PartialResult {
let slice = &String::from_iter(&self.chars[self.i..self.i+search.len()]);
if slice == search {
self.i += search.len();
return Ok(Some(value));
}
Ok(None)
}
fn skip_whitespace(&mut self) {
while self.chars[self.i].is_ascii_whitespace() {
self.i += 1;
}
}
fn eat_char(&mut self, ch: char) -> Result<(), ParseError> {
if self.chars[self.i] != ch {
let msg = format!(r#"Expected "{}"."#, ch);
return Err(ParseError::ExpectedToken(msg));
}
self.i += 1;
Ok(())
}
pub fn parse(json: &str) -> JSONResult {
JSON::new(json).parse_value()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}