hocon_rs/parser/
object.rs1use crate::Result;
2use crate::error::Error;
3use crate::parser::HoconParser;
4use crate::parser::include::INCLUDE;
5use crate::parser::read::Read;
6use crate::parser::string::TRIPLE_DOUBLE_QUOTE;
7use crate::raw::{
8 comment::Comment, field::ObjectField, raw_object::RawObject, raw_string::RawString,
9 raw_value::RawValue,
10};
11use std::str::FromStr;
12
13#[macro_export]
14macro_rules! try_peek {
15 ($reader:expr) => {
16 match $reader.peek() {
17 Ok(ch) => ch,
18 Err($crate::error::Error::Eof) => break,
19 Err(err) => return Err(err),
20 }
21 };
22}
23
24impl<'de, R: Read<'de>> HoconParser<R> {
25 pub(crate) fn parse_key(&mut self) -> Result<RawString> {
26 self.drop_horizontal_whitespace()?;
27 self.parse_path_expression()
28 }
29
30 pub(crate) fn parse_value(&mut self) -> Result<RawValue> {
31 self.drop_whitespace()?;
32 let mut values = vec![];
33 let mut scratch = vec![];
34 let mut spaces = vec![];
35 let mut prev_space = None;
36 #[inline]
37 fn push_value_and_space(
38 values: &mut Vec<RawValue>,
39 spaces: &mut Vec<Option<String>>,
40 mut space_after_value: Option<String>,
41 v: RawValue,
42 ) -> Option<String> {
43 if !values.is_empty() {
44 spaces.push(space_after_value);
45 space_after_value = None;
46 }
47 values.push(v);
48 space_after_value
49 }
50 loop {
51 let ch = try_peek!(self.reader);
52 match ch {
53 b'[' => {
54 let max_depth = self.options.max_depth;
56 let current_depth = self.ctx.increase_depth();
57 if current_depth > max_depth {
58 return Err(Error::RecursionDepthExceeded { max_depth });
59 }
60 let array = self.parse_array(false)?;
61 self.ctx.decrease_depth();
62 let v = RawValue::Array(array);
63 prev_space = push_value_and_space(&mut values, &mut spaces, prev_space, v);
64 }
65 b'{' => {
66 let max_depth = self.options.max_depth;
68 let current_depth = self.ctx.increase_depth();
69 if current_depth > max_depth {
70 return Err(Error::RecursionDepthExceeded { max_depth });
71 }
72 let object = self.parse_object(false)?;
73 self.ctx.decrease_depth();
74 let v = RawValue::Object(object);
75 prev_space = push_value_and_space(&mut values, &mut spaces, prev_space, v);
76 }
77 b'"' => {
78 let v = if let Ok(chars) = self.reader.peek_n(3)
80 && chars == TRIPLE_DOUBLE_QUOTE
81 {
82 let multiline = self.parse_multiline_string(false)?;
83 RawValue::String(RawString::MultilineString(multiline))
84 } else {
85 let quoted = self.parse_quoted_string(false)?;
86 RawValue::String(RawString::QuotedString(quoted))
87 };
88 prev_space = push_value_and_space(&mut values, &mut spaces, prev_space, v);
89 }
90 b'$' => {
91 let substitution = self.parse_substitution()?;
92 let v = RawValue::Substitution(substitution);
93 prev_space = push_value_and_space(&mut values, &mut spaces, prev_space, v);
94 }
95 b']' | b'}' => {
96 break;
97 }
98 b',' | b'#' | b'\n' => {
99 if values.is_empty() {
100 return Err(Error::UnexpectedToken {
101 expected: "a valid value",
102 found_beginning: ch,
103 });
104 }
105 break;
106 }
107 b'/' if self.reader.peek2().is_ok_and(|(_, ch2)| ch2 == b'/') => {
108 if !values.is_empty() {
109 break;
110 } else {
111 return Err(Error::UnexpectedToken {
112 expected: "a valid value",
113 found_beginning: ch,
114 });
115 }
116 }
117 b'\r' if self.reader.peek2().is_ok_and(|(_, ch2)| ch2 == b'\n') => {
118 break;
119 }
120 _ => {
121 if self.reader.starts_with_horizontal_whitespace()? {
123 scratch.clear();
124 self.parse_horizontal_whitespace(&mut scratch)?;
125 let space = unsafe { str::from_utf8_unchecked(&scratch) };
126 if space.is_empty() {
127 prev_space = None
128 } else {
129 prev_space = Some(space.to_string());
130 }
131 } else {
132 let unquoted = self.parse_unquoted_string()?;
133 let v = RawValue::String(RawString::UnquotedString(unquoted));
134 prev_space = push_value_and_space(&mut values, &mut spaces, prev_space, v);
135 }
136 }
137 };
138 }
139 match values.len() {
140 0 => Err(Error::UnexpectedToken {
141 expected: "value",
142 found_beginning: 0,
143 }),
144 1 => {
145 let v = values.remove(0);
146 let v = if let RawValue::String(s) = v {
147 Self::resolve_unquoted_string(s)
148 } else {
149 v
150 };
151 Ok(v)
152 }
153 _ => {
154 debug_assert_eq!(values.len(), spaces.len() + 1);
155 RawValue::concat(values, spaces)
156 }
157 }
158 }
159
160 pub(crate) fn parse_key_value(&mut self) -> Result<(RawString, RawValue)> {
162 self.drop_whitespace()?;
163 let key = self.parse_key()?;
164 self.drop_whitespace()?;
165 let is_add_assign = self.drop_kv_separator()?;
166 self.drop_whitespace()?;
167 let mut value = self.parse_value()?;
168 if is_add_assign {
169 value = RawValue::add_assign(value)
170 }
171 Ok((key, value))
172 }
173
174 pub fn drop_kv_separator(&mut self) -> Result<bool> {
175 let ch = self.reader.peek()?;
176 match ch {
177 b':' | b'=' => {
178 self.reader.discard(1)?;
179 }
180 b'+' => {
181 let (_, ch2) = self.reader.peek2()?;
182 if ch2 != b'=' {
183 return Err(Error::UnexpectedToken {
184 expected: "=",
185 found_beginning: ch2,
186 });
187 }
188 self.reader.discard(2)?;
189 return Ok(true);
190 }
191 b'{' => {}
192 ch => {
193 return Err(Error::UnexpectedToken {
194 expected: ": or =",
195 found_beginning: ch,
196 });
197 }
198 }
199 Ok(false)
200 }
201
202 #[inline]
203 pub(crate) fn parse_object_field(&mut self) -> Result<ObjectField> {
204 let ch = self.reader.peek()?;
205 let field = if ch == b'i' && self.reader.peek_n(7)? == INCLUDE {
207 let mut inclusion = self.parse_include()?;
208 self.parse_inclusion(&mut inclusion)?;
209 ObjectField::inclusion(inclusion)
210 } else {
211 let (key, value) = self.parse_key_value()?;
212 ObjectField::key_value(key, value)
213 };
214 Ok(field)
215 }
216
217 pub(crate) fn parse_braces_omitted_object(&mut self) -> Result<RawObject> {
218 let mut fields = vec![];
219 loop {
220 self.drop_whitespace_and_comments()?;
221 let ch = self.reader.peek()?;
222 if ch == b'}' {
223 break;
224 }
225 match self.parse_object_field() {
226 Ok(field) => {
227 fields.push(field);
228 }
229 Err(Error::Eof) => {
230 break;
231 }
232 Err(err) => {
233 return Err(err);
234 }
235 }
236 self.drop_whitespace_and_comments()?;
237 if self.drop_comma_separator()? {
238 break;
239 }
240 }
241 let raw_obj = RawObject::new(fields);
242 Ok(raw_obj)
243 }
244
245 pub(crate) fn parse_object(&mut self, verify_delimiter: bool) -> Result<RawObject> {
246 if verify_delimiter {
247 let ch = self.reader.peek()?;
248 if ch != b'{' {
249 return Err(Error::UnexpectedToken {
250 expected: "{",
251 found_beginning: ch,
252 });
253 }
254 }
255 self.reader.discard(1)?;
256 let raw_obj = self.parse_braces_omitted_object()?;
257 let ch = self.reader.peek()?;
258 if ch != b'}' {
259 return Err(Error::UnexpectedToken {
260 expected: "}",
261 found_beginning: ch,
262 });
263 }
264 self.reader.discard(1)?;
265 Ok(raw_obj)
266 }
267
268 pub(crate) fn resolve_unquoted_string(string: RawString) -> RawValue {
269 if let RawString::UnquotedString(unquoted) = string {
270 match &*unquoted {
271 "true" => RawValue::Boolean(true),
272 "false" => RawValue::Boolean(false),
273 "null" => RawValue::Null,
274 other => match serde_json::Number::from_str(other) {
275 Ok(number) => RawValue::Number(number),
276 Err(_) => RawValue::unquoted_string(unquoted),
277 },
278 }
279 } else {
280 RawValue::String(string)
281 }
282 }
283
284 #[allow(unused)]
285 pub(crate) fn parse_newline_comments(&mut self) -> Result<Vec<ObjectField>> {
286 let mut fields = vec![];
287 loop {
288 match self.parse_comment() {
289 Ok((ty, content)) => {
290 let comment = Comment::new(content, ty);
291 fields.push(ObjectField::newline_comment(comment));
292 }
293 Err(Error::Eof | Error::UnexpectedToken { .. }) => {
294 break Ok(fields);
295 }
296 Err(err) => {
297 return Err(err);
298 }
299 }
300 }
301 }
302}