Skip to main content

json_syntax/parse/
value.rs

1use super::{JsonParse, JsonParseError, JsonParsingContext, Parser, array, object};
2use crate::{JsonArrayBuf, JsonNumberBuf, JsonObject, JsonString, JsonValue, object::Key};
3use decoded_char::DecodedChar;
4
5/// Value fragment.
6#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
7pub enum Fragment {
8	Value(JsonValue),
9	BeginArray,
10	BeginObject((Key, usize)),
11}
12
13impl Fragment {
14	fn value_or_parse<C, E>(
15		value: Option<(JsonValue, usize)>,
16		parser: &mut Parser<C, E>,
17		context: JsonParsingContext,
18	) -> Result<(Self, usize), JsonParseError<E>>
19	where
20		C: Iterator<Item = Result<DecodedChar, E>>,
21	{
22		match value {
23			Some((value, i)) => Ok((value.into(), i)),
24			None => Self::parse_in(parser, context),
25		}
26	}
27}
28
29impl From<JsonValue> for Fragment {
30	fn from(v: JsonValue) -> Self {
31		Self::Value(v)
32	}
33}
34
35impl JsonParse for Fragment {
36	fn parse_in<C, E>(
37		parser: &mut Parser<C, E>,
38		context: JsonParsingContext,
39	) -> Result<(Self, usize), JsonParseError<E>>
40	where
41		C: Iterator<Item = Result<DecodedChar, E>>,
42	{
43		parser.skip_whitespaces()?;
44
45		let (value, i) = match parser.peek_char()? {
46			Some('n') => {
47				let ((), i) = <()>::parse_in(parser, context)?;
48				(JsonValue::Null, i)
49			}
50			Some('t' | 'f') => {
51				let (value, i) = bool::parse_in(parser, context)?;
52				(JsonValue::Boolean(value), i)
53			}
54			Some('0'..='9' | '-') => {
55				let (value, i) = JsonNumberBuf::parse_in(parser, context)?;
56				(JsonValue::Number(value), i)
57			}
58			Some('"') => {
59				let (value, i) = JsonString::parse_in(parser, context)?;
60				(JsonValue::String(value), i)
61			}
62			Some('[') => match array::StartFragment::parse_in(parser, context)? {
63				(array::StartFragment::Empty, span) => {
64					(JsonValue::Array(JsonArrayBuf::new()), span)
65				}
66				(array::StartFragment::NonEmpty, span) => return Ok((Self::BeginArray, span)),
67			},
68			Some('{') => match object::StartFragment::parse_in(parser, context)? {
69				(object::StartFragment::Empty, span) => {
70					(JsonValue::Object(JsonObject::new()), span)
71				}
72				(object::StartFragment::NonEmpty(key), span) => {
73					return Ok((Self::BeginObject(key), span));
74				}
75			},
76			unexpected => return Err(JsonParseError::unexpected(parser.position, unexpected)),
77		};
78
79		Ok((Self::Value(value), i))
80	}
81}
82
83impl JsonParse for JsonValue {
84	fn parse_in<C, E>(
85		parser: &mut Parser<C, E>,
86		context: JsonParsingContext,
87	) -> Result<(Self, usize), JsonParseError<E>>
88	where
89		C: Iterator<Item = Result<DecodedChar, E>>,
90	{
91		enum StackItem {
92			Array((JsonArrayBuf, usize)),
93			ArrayItem((JsonArrayBuf, usize)),
94			Object((JsonObject, usize)),
95			ObjectEntry((JsonObject, usize), (Key, usize)),
96		}
97
98		let mut stack: Vec<StackItem> = vec![];
99		let mut value: Option<(JsonValue, usize)> = None;
100
101		fn stack_context(stack: &[StackItem], root: JsonParsingContext) -> JsonParsingContext {
102			match stack.last() {
103				Some(StackItem::Array(_) | StackItem::ArrayItem(_)) => JsonParsingContext::Array,
104				Some(StackItem::Object(_)) => JsonParsingContext::ObjectKey,
105				Some(StackItem::ObjectEntry(_, _)) => JsonParsingContext::ObjectValue,
106				None => root,
107			}
108		}
109
110		loop {
111			match stack.pop() {
112				None => match Fragment::value_or_parse(
113					value.take(),
114					parser,
115					stack_context(&stack, context),
116				)? {
117					(Fragment::Value(value), i) => {
118						parser.skip_whitespaces()?;
119						break match parser.next_char()? {
120							(p, Some(c)) => Err(JsonParseError::unexpected(p, Some(c))),
121							(_, None) => Ok((value, i)),
122						};
123					}
124					(Fragment::BeginArray, i) => {
125						stack.push(StackItem::ArrayItem((JsonArrayBuf::new(), i)))
126					}
127					(Fragment::BeginObject(key), i) => {
128						stack.push(StackItem::ObjectEntry((JsonObject::new(), i), key))
129					}
130				},
131				Some(StackItem::Array((array, i))) => {
132					match array::ContinueFragment::parse_in(parser, i)? {
133						array::ContinueFragment::Item => {
134							stack.push(StackItem::ArrayItem((array, i)))
135						}
136						array::ContinueFragment::End => value = Some((JsonValue::Array(array), i)),
137					}
138				}
139				Some(StackItem::ArrayItem((mut array, i))) => {
140					match Fragment::value_or_parse(value.take(), parser, JsonParsingContext::Array)?
141					{
142						(Fragment::Value(value), _) => {
143							array.push(value);
144							stack.push(StackItem::Array((array, i)));
145						}
146						(Fragment::BeginArray, j) => {
147							stack.push(StackItem::ArrayItem((array, i)));
148							stack.push(StackItem::ArrayItem((JsonArrayBuf::new(), j)))
149						}
150						(Fragment::BeginObject(value_key), j) => {
151							stack.push(StackItem::ArrayItem((array, i)));
152							stack.push(StackItem::ObjectEntry((JsonObject::new(), j), value_key))
153						}
154					}
155				}
156				Some(StackItem::Object((object, i))) => {
157					match object::ContinueFragment::parse_in(parser, i)? {
158						object::ContinueFragment::Entry(key) => {
159							stack.push(StackItem::ObjectEntry((object, i), key))
160						}
161						object::ContinueFragment::End => {
162							value = Some((JsonValue::Object(object), i))
163						}
164					}
165				}
166				Some(StackItem::ObjectEntry((mut object, i), (key, e))) => {
167					match Fragment::value_or_parse(
168						value.take(),
169						parser,
170						JsonParsingContext::ObjectValue,
171					)? {
172						(Fragment::Value(value), _) => {
173							parser.end_fragment(e);
174							object.push_back(key, value);
175							stack.push(StackItem::Object((object, i)));
176						}
177						(Fragment::BeginArray, j) => {
178							stack.push(StackItem::ObjectEntry((object, i), (key, e)));
179							stack.push(StackItem::ArrayItem((JsonArrayBuf::new(), j)))
180						}
181						(Fragment::BeginObject(value_key), j) => {
182							stack.push(StackItem::ObjectEntry((object, i), (key, e)));
183							stack.push(StackItem::ObjectEntry((JsonObject::new(), j), value_key))
184						}
185					}
186				}
187			}
188		}
189	}
190}