hocon_rs/parser/
object.rs

1use 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                    // Parse array
55                    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                    // Parse object
67                    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                    // Parse quoted string or multi-line string
79                    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' => {
118                    if let Ok((_, ch2)) = self.reader.peek2() {
119                        if ch2 == b'\n' && !values.is_empty() {
120                            break;
121                        } else {
122                            return Err(Error::UnexpectedToken {
123                                expected: "a valid value",
124                                found_beginning: ch,
125                            });
126                        }
127                    }
128                }
129                _ => {
130                    // Parse unquoted string or space
131                    if self.reader.starts_with_horizontal_whitespace()? {
132                        scratch.clear();
133                        self.parse_horizontal_whitespace(&mut scratch)?;
134                        let space = unsafe { str::from_utf8_unchecked(&scratch) };
135                        if space.is_empty() {
136                            prev_space = None
137                        } else {
138                            prev_space = Some(space.to_string());
139                        }
140                    } else {
141                        let unquoted = self.parse_unquoted_string()?;
142                        let v = RawValue::String(RawString::UnquotedString(unquoted));
143                        prev_space = push_value_and_space(&mut values, &mut spaces, prev_space, v);
144                    }
145                }
146            };
147        }
148        debug_assert!(!values.is_empty());
149        if values.len() == 1 {
150            let v = values.remove(0);
151            let v = if let RawValue::String(s) = v {
152                Self::resolve_unquoted_string(s)
153            } else {
154                v
155            };
156            Ok(v)
157        } else {
158            debug_assert_eq!(values.len(), spaces.len() + 1);
159            RawValue::concat(values, spaces)
160        }
161    }
162
163    // TODO if key parse success and value parse error, should report an error.
164    pub(crate) fn parse_key_value(&mut self) -> Result<(RawString, RawValue)> {
165        self.drop_whitespace()?;
166        let key = self.parse_key()?;
167        self.drop_whitespace()?;
168        let is_add_assign = self.drop_kv_separator()?;
169        self.drop_whitespace()?;
170        let mut value = self.parse_value()?;
171        if is_add_assign {
172            value = RawValue::add_assign(value)
173        }
174        Ok((key, value))
175    }
176
177    pub fn drop_kv_separator(&mut self) -> Result<bool> {
178        let ch = self.reader.peek()?;
179        match ch {
180            b':' | b'=' => {
181                self.reader.discard(1)?;
182            }
183            b'+' => {
184                let (_, ch2) = self.reader.peek2()?;
185                if ch2 != b'=' {
186                    return Err(Error::UnexpectedToken {
187                        expected: "=",
188                        found_beginning: ch2,
189                    });
190                }
191                self.reader.discard(2)?;
192                return Ok(true);
193            }
194            b'{' => {}
195            ch => {
196                return Err(Error::UnexpectedToken {
197                    expected: ": or =",
198                    found_beginning: ch,
199                });
200            }
201        }
202        Ok(false)
203    }
204
205    #[inline]
206    pub(crate) fn parse_object_field(&mut self) -> Result<ObjectField> {
207        let ch = self.reader.peek()?;
208        // It maybe an include syntax, we need to peek more chars to determine.
209        let field = if ch == b'i' && self.reader.peek_n(7)? == INCLUDE {
210            let mut inclusion = self.parse_include()?;
211            self.parse_inclusion(&mut inclusion)?;
212            ObjectField::inclusion(inclusion)
213        } else {
214            let (key, value) = self.parse_key_value()?;
215            ObjectField::key_value(key, value)
216        };
217        Ok(field)
218    }
219
220    pub(crate) fn parse_braces_omitted_object(&mut self) -> Result<RawObject> {
221        let mut fields = vec![];
222        loop {
223            self.drop_whitespace_and_comments()?;
224            let ch = self.reader.peek()?;
225            if ch == b'}' {
226                break;
227            }
228            match self.parse_object_field() {
229                Ok(field) => {
230                    fields.push(field);
231                }
232                Err(Error::Eof) => {
233                    break;
234                }
235                Err(err) => {
236                    return Err(err);
237                }
238            }
239            self.drop_whitespace_and_comments()?;
240            if self.drop_comma_separator()? {
241                break;
242            }
243        }
244        let raw_obj = RawObject::new(fields);
245        Ok(raw_obj)
246    }
247
248    pub(crate) fn parse_object(&mut self, verify_delimiter: bool) -> Result<RawObject> {
249        if verify_delimiter {
250            let ch = self.reader.peek()?;
251            if ch != b'{' {
252                return Err(Error::UnexpectedToken {
253                    expected: "{",
254                    found_beginning: ch,
255                });
256            }
257        }
258        self.reader.discard(1)?;
259        let raw_obj = self.parse_braces_omitted_object()?;
260        let ch = self.reader.peek()?;
261        if ch != b'}' {
262            return Err(Error::UnexpectedToken {
263                expected: "}",
264                found_beginning: ch,
265            });
266        }
267        self.reader.discard(1)?;
268        Ok(raw_obj)
269    }
270
271    pub(crate) fn resolve_unquoted_string(string: RawString) -> RawValue {
272        if let RawString::UnquotedString(unquoted) = string {
273            match &*unquoted {
274                "true" => RawValue::Boolean(true),
275                "false" => RawValue::Boolean(false),
276                "null" => RawValue::Null,
277                other => match serde_json::Number::from_str(other) {
278                    Ok(number) => RawValue::Number(number),
279                    Err(_) => RawValue::unquoted_string(unquoted),
280                },
281            }
282        } else {
283            RawValue::String(string)
284        }
285    }
286
287    #[allow(unused)]
288    pub(crate) fn parse_newline_comments(&mut self) -> Result<Vec<ObjectField>> {
289        let mut fields = vec![];
290        loop {
291            match self.parse_comment() {
292                Ok((ty, content)) => {
293                    let comment = Comment::new(content, ty);
294                    fields.push(ObjectField::newline_comment(comment));
295                }
296                Err(Error::Eof | Error::UnexpectedToken { .. }) => {
297                    break Ok(fields);
298                }
299                Err(err) => {
300                    return Err(err);
301                }
302            }
303        }
304    }
305}