toml/de/parser/
document.rs

1use serde_spanned::Spanned;
2
3use crate::alloc_prelude::*;
4use crate::de::parser::key::on_key;
5use crate::de::parser::prelude::*;
6use crate::de::parser::value::value;
7use crate::de::DeString;
8use crate::de::DeValue;
9use crate::de::{DeArray, DeTable};
10use crate::map::Entry;
11
12/// ```bnf
13/// ;; TOML
14///
15/// toml = expression *( newline expression )
16///
17/// expression = ( ( ws comment ) /
18///                ( ws keyval ws [ comment ] ) /
19///                ( ws table ws [ comment ] ) /
20///                  ws )
21/// ```
22pub(crate) fn document<'i>(
23    input: &mut Input<'_>,
24    source: toml_parser::Source<'i>,
25    errors: &mut dyn ErrorSink,
26) -> Spanned<DeTable<'i>> {
27    #[cfg(feature = "debug")]
28    let _scope = TraceScope::new("document::document");
29    let mut state = State::default();
30    while let Some(event) = input.next_token() {
31        match event.kind() {
32            EventKind::InlineTableOpen
33            | EventKind::InlineTableClose
34            | EventKind::ArrayOpen
35            | EventKind::ArrayClose
36            | EventKind::Scalar
37            | EventKind::ValueSep
38            | EventKind::Error
39            | EventKind::KeySep
40            | EventKind::KeyValSep
41            | EventKind::StdTableClose
42            | EventKind::ArrayTableClose => {
43                #[cfg(feature = "debug")]
44                trace(
45                    &format!("unexpected {event:?}"),
46                    anstyle::AnsiColor::Red.on_default(),
47                );
48                continue;
49            }
50            EventKind::StdTableOpen | EventKind::ArrayTableOpen => {
51                state.finish_table(errors);
52
53                let header = on_table(event, input, source, errors);
54
55                state.start_table(header, errors);
56            }
57            EventKind::SimpleKey => {
58                let (path, key) = on_key(event, input, source, errors);
59                let Some(key) = key else {
60                    break;
61                };
62                let Some(next_event) = input.next_token() else {
63                    break;
64                };
65                let keyval_event = if next_event.kind() == EventKind::Whitespace {
66                    let Some(next_event) = input.next_token() else {
67                        break;
68                    };
69                    next_event
70                } else {
71                    next_event
72                };
73                if keyval_event.kind() != EventKind::KeyValSep {
74                    break;
75                }
76
77                if input
78                    .first()
79                    .map(|e| e.kind() == EventKind::Whitespace)
80                    .unwrap_or(false)
81                {
82                    let _ = input.next_token();
83                }
84                let value = value(input, source, errors);
85
86                state.capture_key_value(path, key, value, errors);
87            }
88            EventKind::Whitespace | EventKind::Comment | EventKind::Newline => {
89                state.capture_trailing(event);
90            }
91        }
92    }
93
94    state.finish_table(errors);
95
96    let span = Default::default();
97    Spanned::new(span, state.root)
98}
99
100/// ```bnf
101/// ;; Standard Table
102///
103/// std-table = std-table-open key *( table-key-sep key) std-table-close
104///
105/// ;; Array Table
106///
107/// array-table = array-table-open key *( table-key-sep key) array-table-close
108/// ```
109fn on_table<'i>(
110    open_event: &toml_parser::parser::Event,
111    input: &mut Input<'_>,
112    source: toml_parser::Source<'i>,
113    errors: &mut dyn ErrorSink,
114) -> TableHeader<'i> {
115    #[cfg(feature = "debug")]
116    let _scope = TraceScope::new("document::on_table");
117    let is_array = open_event.kind() == EventKind::ArrayTableOpen;
118    let mut current_path = None;
119    let mut current_key = None;
120    let mut current_span = open_event.span();
121    let mut current_prefix = None;
122    let mut current_suffix = None;
123
124    while let Some(event) = input.next_token() {
125        match event.kind() {
126            EventKind::InlineTableOpen
127            | EventKind::InlineTableClose
128            | EventKind::ArrayOpen
129            | EventKind::ArrayClose
130            | EventKind::Scalar
131            | EventKind::ValueSep
132            | EventKind::Error
133            | EventKind::KeySep
134            | EventKind::KeyValSep
135            | EventKind::StdTableOpen
136            | EventKind::ArrayTableOpen
137            | EventKind::Comment
138            | EventKind::Newline => {
139                #[cfg(feature = "debug")]
140                trace(
141                    &format!("unexpected {event:?}"),
142                    anstyle::AnsiColor::Red.on_default(),
143                );
144                continue;
145            }
146            EventKind::ArrayTableClose | EventKind::StdTableClose => {
147                current_span = current_span.append(event.span());
148                break;
149            }
150            EventKind::SimpleKey => {
151                current_prefix.get_or_insert_with(|| event.span().before());
152                let (path, key) = on_key(event, input, source, errors);
153                current_path = Some(path);
154                current_key = key;
155                current_suffix.get_or_insert_with(|| event.span().after());
156            }
157            EventKind::Whitespace => {
158                if current_key.is_some() {
159                    current_suffix = Some(event.span());
160                } else {
161                    current_prefix = Some(event.span());
162                }
163            }
164        }
165    }
166
167    TableHeader {
168        path: current_path.unwrap_or_default(),
169        key: current_key,
170        span: current_span,
171        is_array,
172    }
173}
174
175struct TableHeader<'i> {
176    path: Vec<Spanned<DeString<'i>>>,
177    key: Option<Spanned<DeString<'i>>>,
178    span: toml_parser::Span,
179    is_array: bool,
180}
181
182#[derive(Default)]
183struct State<'i> {
184    root: DeTable<'i>,
185    current_table: DeTable<'i>,
186    current_header: Option<TableHeader<'i>>,
187    current_position: usize,
188}
189
190impl<'i> State<'i> {
191    fn capture_trailing(&mut self, _event: &toml_parser::parser::Event) {}
192
193    fn capture_key_value(
194        &mut self,
195        path: Vec<Spanned<DeString<'i>>>,
196        key: Spanned<DeString<'i>>,
197        value: Spanned<DeValue<'i>>,
198        errors: &mut dyn ErrorSink,
199    ) {
200        #[cfg(feature = "debug")]
201        let _scope = TraceScope::new("document::capture_key_value");
202        #[cfg(feature = "debug")]
203        trace(
204            &format!(
205                "path={:?}",
206                path.iter().map(|k| k.get_ref()).collect::<Vec<_>>()
207            ),
208            anstyle::AnsiColor::Blue.on_default(),
209        );
210        #[cfg(feature = "debug")]
211        trace(
212            &format!("key={key}",),
213            anstyle::AnsiColor::Blue.on_default(),
214        );
215        #[cfg(feature = "debug")]
216        trace(
217            &format!("value={value:?}",),
218            anstyle::AnsiColor::Blue.on_default(),
219        );
220
221        let dotted = true;
222        let Some(parent_table) = descend_path(&mut self.current_table, &path, dotted, errors)
223        else {
224            return;
225        };
226        // "Likewise, using dotted keys to redefine tables already defined in [table] form is not allowed"
227        let mixed_table_types = parent_table.is_dotted() == path.is_empty();
228        if mixed_table_types {
229            let key_span = get_key_span(&key);
230            errors.report_error(ParseError::new("duplicate key").with_unexpected(key_span));
231            return;
232        }
233        let key_span = get_key_span(&key);
234        match parent_table.entry(key) {
235            Entry::Vacant(o) => {
236                o.insert(value);
237            }
238            Entry::Occupied(existing) => {
239                // "Since tables cannot be defined more than once, redefining such tables using a [table] header is not allowed"
240                let old_span = get_key_span(existing.key());
241                errors.report_error(
242                    ParseError::new("duplicate key")
243                        .with_unexpected(key_span)
244                        .with_context(old_span),
245                );
246            }
247        }
248    }
249
250    fn finish_table(&mut self, errors: &mut dyn ErrorSink) {
251        #[cfg(feature = "debug")]
252        let _scope = TraceScope::new("document::finish_table");
253        let prev_table = core::mem::take(&mut self.current_table);
254        if let Some(header) = self.current_header.take() {
255            let Some(key) = &header.key else {
256                return;
257            };
258            let header_span = header.span.start()..header.span.end();
259            let prev_table = Spanned::new(header_span.clone(), DeValue::Table(prev_table));
260
261            let parent_key = &header.path;
262            let dotted = false;
263            let Some(parent_table) = descend_path(&mut self.root, parent_key, dotted, errors)
264            else {
265                return;
266            };
267            #[cfg(feature = "debug")]
268            trace(
269                &format!("key={key}",),
270                anstyle::AnsiColor::Blue.on_default(),
271            );
272            if header.is_array {
273                let entry = parent_table.entry(key.clone()).or_insert_with(|| {
274                    let mut array = DeArray::new();
275                    array.set_array_of_tables(true);
276                    Spanned::new(header_span, DeValue::Array(array))
277                });
278                let Some(array) = entry
279                    .as_mut()
280                    .as_array_mut()
281                    .filter(|a| a.is_array_of_tables())
282                else {
283                    let key_span = get_key_span(key);
284                    let old_span = entry.span();
285                    let old_span = toml_parser::Span::new_unchecked(old_span.start, old_span.end);
286                    errors.report_error(
287                        ParseError::new("duplicate key")
288                            .with_unexpected(key_span)
289                            .with_context(old_span),
290                    );
291                    return;
292                };
293                array.push(prev_table);
294            } else {
295                let existing = parent_table.insert(key.clone(), prev_table);
296                debug_assert!(existing.is_none());
297            }
298        } else {
299            self.root = prev_table;
300        }
301    }
302
303    fn start_table(&mut self, header: TableHeader<'i>, errors: &mut dyn ErrorSink) {
304        if !header.is_array {
305            // 1. Look up the table on start to ensure the duplicate_key error points to the right line
306            // 2. Ensure any child tables from an implicit table are preserved
307            let root = &mut self.root;
308            if let (Some(parent_table), Some(key)) =
309                (descend_path(root, &header.path, false, errors), &header.key)
310            {
311                if let Some((old_key, old_value)) = parent_table.remove_entry(key) {
312                    match old_value.into_inner() {
313                        DeValue::Table(t) if t.is_implicit() && !t.is_dotted() => {
314                            self.current_table = t;
315                        }
316                        // Since tables cannot be defined more than once, redefining such tables using a [table] header is not allowed. Likewise, using dotted keys to redefine tables already defined in [table] form is not allowed.
317                        old_value => {
318                            let old_span = get_key_span(&old_key);
319                            let key_span = get_key_span(key);
320                            errors.report_error(
321                                ParseError::new("duplicate key")
322                                    .with_unexpected(key_span)
323                                    .with_context(old_span),
324                            );
325
326                            if let DeValue::Table(t) = old_value {
327                                self.current_table = t;
328                            }
329                        }
330                    }
331                }
332            }
333        }
334
335        self.current_position += 1;
336        self.current_table.set_implicit(false);
337        self.current_table.set_dotted(false);
338        self.current_header = Some(header);
339    }
340}
341
342fn descend_path<'t, 'i>(
343    mut table: &'t mut DeTable<'i>,
344    path: &[Spanned<DeString<'i>>],
345    dotted: bool,
346    errors: &mut dyn ErrorSink,
347) -> Option<&'t mut DeTable<'i>> {
348    #[cfg(feature = "debug")]
349    let _scope = TraceScope::new("document::descend_path");
350    #[cfg(feature = "debug")]
351    trace(
352        &format!(
353            "path={:?}",
354            path.iter().map(|k| k.get_ref()).collect::<Vec<_>>()
355        ),
356        anstyle::AnsiColor::Blue.on_default(),
357    );
358    for key in path.iter() {
359        table = match table.entry(key.clone()) {
360            Entry::Vacant(entry) => {
361                let mut new_table = DeTable::new();
362                new_table.set_implicit(true);
363                new_table.set_dotted(dotted);
364
365                let value = DeValue::Table(new_table);
366                let value = Spanned::new(key.span(), value);
367                let value = entry.insert(value);
368                value.as_mut().as_table_mut().unwrap()
369            }
370            Entry::Occupied(entry) => {
371                let spanned = entry.into_mut();
372                let old_span = spanned.span();
373                match spanned.as_mut() {
374                    DeValue::Array(ref mut array) => {
375                        if !array.is_array_of_tables() {
376                            let old_span =
377                                toml_parser::Span::new_unchecked(old_span.start, old_span.end);
378                            let key_span = get_key_span(key);
379                            errors.report_error(
380                                ParseError::new(
381                                    "cannot extend value of type array with a dotted key",
382                                )
383                                .with_unexpected(key_span)
384                                .with_context(old_span),
385                            );
386                            return None;
387                        }
388
389                        debug_assert!(!array.is_empty());
390
391                        let index = array.len() - 1;
392                        let last_child = array.get_mut(index).unwrap();
393
394                        match last_child.as_mut() {
395                            DeValue::Table(table) => table,
396                            existing => {
397                                let old_span =
398                                    toml_parser::Span::new_unchecked(old_span.start, old_span.end);
399                                let key_span = get_key_span(key);
400                                errors.report_error(
401                                    ParseError::new(format!(
402                                        "cannot extend value of type {} with a dotted key",
403                                        existing.type_str()
404                                    ))
405                                    .with_unexpected(key_span)
406                                    .with_context(old_span),
407                                );
408                                return None;
409                            }
410                        }
411                    }
412                    DeValue::Table(ref mut sweet_child_of_mine) => {
413                        if sweet_child_of_mine.is_inline() {
414                            let key_span = get_key_span(key);
415                            errors.report_error(
416                                ParseError::new(
417                                    "cannot extend value of type inline table with a dotted key",
418                                )
419                                .with_unexpected(key_span),
420                            );
421                            return None;
422                        }
423                        // Since tables cannot be defined more than once, redefining such tables using a
424                        // [table] header is not allowed. Likewise, using dotted keys to redefine tables
425                        // already defined in [table] form is not allowed.
426                        if dotted && !sweet_child_of_mine.is_implicit() {
427                            let key_span = get_key_span(key);
428                            errors.report_error(
429                                ParseError::new("duplicate key").with_unexpected(key_span),
430                            );
431                            return None;
432                        }
433                        sweet_child_of_mine
434                    }
435                    existing => {
436                        let old_span =
437                            toml_parser::Span::new_unchecked(old_span.start, old_span.end);
438                        let key_span = get_key_span(key);
439                        errors.report_error(
440                            ParseError::new(format!(
441                                "cannot extend value of type {} with a dotted key",
442                                existing.type_str()
443                            ))
444                            .with_unexpected(key_span)
445                            .with_context(old_span),
446                        );
447                        return None;
448                    }
449                }
450            }
451        };
452    }
453    Some(table)
454}
455
456fn get_key_span(key: &Spanned<DeString<'_>>) -> toml_parser::Span {
457    let key_span = key.span();
458    toml_parser::Span::new_unchecked(key_span.start, key_span.end)
459}