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#[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}