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' if self.reader.peek2().is_ok_and(|(_, ch2)| ch2 == b'\n') => {
118                    break;
119                }
120                _ => {
121                    // Parse unquoted string or space
122                    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    // TODO if key parse success and value parse error, should report an error.
161    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        // It maybe an include syntax, we need to peek more chars to determine.
206        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}