use super::{JsonParse, JsonParseError, JsonParsingContext, Parser, array, object};
use crate::{JsonArrayBuf, JsonNumberBuf, JsonObject, JsonString, JsonValue, object::Key};
use decoded_char::DecodedChar;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Fragment {
Value(JsonValue),
BeginArray,
BeginObject((Key, usize)),
}
impl Fragment {
fn value_or_parse<C, E>(
value: Option<(JsonValue, usize)>,
parser: &mut Parser<C, E>,
context: JsonParsingContext,
) -> Result<(Self, usize), JsonParseError<E>>
where
C: Iterator<Item = Result<DecodedChar, E>>,
{
match value {
Some((value, i)) => Ok((value.into(), i)),
None => Self::parse_in(parser, context),
}
}
}
impl From<JsonValue> for Fragment {
fn from(v: JsonValue) -> Self {
Self::Value(v)
}
}
impl JsonParse for Fragment {
fn parse_in<C, E>(
parser: &mut Parser<C, E>,
context: JsonParsingContext,
) -> Result<(Self, usize), JsonParseError<E>>
where
C: Iterator<Item = Result<DecodedChar, E>>,
{
parser.skip_whitespaces()?;
let (value, i) = match parser.peek_char()? {
Some('n') => {
let ((), i) = <()>::parse_in(parser, context)?;
(JsonValue::Null, i)
}
Some('t' | 'f') => {
let (value, i) = bool::parse_in(parser, context)?;
(JsonValue::Boolean(value), i)
}
Some('0'..='9' | '-') => {
let (value, i) = JsonNumberBuf::parse_in(parser, context)?;
(JsonValue::Number(value), i)
}
Some('"') => {
let (value, i) = JsonString::parse_in(parser, context)?;
(JsonValue::String(value), i)
}
Some('[') => match array::StartFragment::parse_in(parser, context)? {
(array::StartFragment::Empty, span) => {
(JsonValue::Array(JsonArrayBuf::new()), span)
}
(array::StartFragment::NonEmpty, span) => return Ok((Self::BeginArray, span)),
},
Some('{') => match object::StartFragment::parse_in(parser, context)? {
(object::StartFragment::Empty, span) => {
(JsonValue::Object(JsonObject::new()), span)
}
(object::StartFragment::NonEmpty(key), span) => {
return Ok((Self::BeginObject(key), span));
}
},
unexpected => return Err(JsonParseError::unexpected(parser.position, unexpected)),
};
Ok((Self::Value(value), i))
}
}
impl JsonParse for JsonValue {
fn parse_in<C, E>(
parser: &mut Parser<C, E>,
context: JsonParsingContext,
) -> Result<(Self, usize), JsonParseError<E>>
where
C: Iterator<Item = Result<DecodedChar, E>>,
{
enum StackItem {
Array((JsonArrayBuf, usize)),
ArrayItem((JsonArrayBuf, usize)),
Object((JsonObject, usize)),
ObjectEntry((JsonObject, usize), (Key, usize)),
}
let mut stack: Vec<StackItem> = vec![];
let mut value: Option<(JsonValue, usize)> = None;
fn stack_context(stack: &[StackItem], root: JsonParsingContext) -> JsonParsingContext {
match stack.last() {
Some(StackItem::Array(_) | StackItem::ArrayItem(_)) => JsonParsingContext::Array,
Some(StackItem::Object(_)) => JsonParsingContext::ObjectKey,
Some(StackItem::ObjectEntry(_, _)) => JsonParsingContext::ObjectValue,
None => root,
}
}
loop {
match stack.pop() {
None => match Fragment::value_or_parse(
value.take(),
parser,
stack_context(&stack, context),
)? {
(Fragment::Value(value), i) => {
parser.skip_whitespaces()?;
break match parser.next_char()? {
(p, Some(c)) => Err(JsonParseError::unexpected(p, Some(c))),
(_, None) => Ok((value, i)),
};
}
(Fragment::BeginArray, i) => {
stack.push(StackItem::ArrayItem((JsonArrayBuf::new(), i)))
}
(Fragment::BeginObject(key), i) => {
stack.push(StackItem::ObjectEntry((JsonObject::new(), i), key))
}
},
Some(StackItem::Array((array, i))) => {
match array::ContinueFragment::parse_in(parser, i)? {
array::ContinueFragment::Item => {
stack.push(StackItem::ArrayItem((array, i)))
}
array::ContinueFragment::End => value = Some((JsonValue::Array(array), i)),
}
}
Some(StackItem::ArrayItem((mut array, i))) => {
match Fragment::value_or_parse(value.take(), parser, JsonParsingContext::Array)?
{
(Fragment::Value(value), _) => {
array.push(value);
stack.push(StackItem::Array((array, i)));
}
(Fragment::BeginArray, j) => {
stack.push(StackItem::ArrayItem((array, i)));
stack.push(StackItem::ArrayItem((JsonArrayBuf::new(), j)))
}
(Fragment::BeginObject(value_key), j) => {
stack.push(StackItem::ArrayItem((array, i)));
stack.push(StackItem::ObjectEntry((JsonObject::new(), j), value_key))
}
}
}
Some(StackItem::Object((object, i))) => {
match object::ContinueFragment::parse_in(parser, i)? {
object::ContinueFragment::Entry(key) => {
stack.push(StackItem::ObjectEntry((object, i), key))
}
object::ContinueFragment::End => {
value = Some((JsonValue::Object(object), i))
}
}
}
Some(StackItem::ObjectEntry((mut object, i), (key, e))) => {
match Fragment::value_or_parse(
value.take(),
parser,
JsonParsingContext::ObjectValue,
)? {
(Fragment::Value(value), _) => {
parser.end_fragment(e);
object.push_back(key, value);
stack.push(StackItem::Object((object, i)));
}
(Fragment::BeginArray, j) => {
stack.push(StackItem::ObjectEntry((object, i), (key, e)));
stack.push(StackItem::ArrayItem((JsonArrayBuf::new(), j)))
}
(Fragment::BeginObject(value_key), j) => {
stack.push(StackItem::ObjectEntry((object, i), (key, e)));
stack.push(StackItem::ObjectEntry((JsonObject::new(), j), value_key))
}
}
}
}
}
}
}