json_syntax/parse/
value.rs

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