Skip to main content

toml/de/parser/
document.rs

1use serde_spanned::Spanned;
2
3use crate::alloc_prelude::*;
4use crate::de::DeString;
5use crate::de::DeValue;
6use crate::de::parser::key::on_key;
7use crate::de::parser::prelude::*;
8use crate::de::parser::value::value;
9use crate::de::{DeArray, DeTable};
10use crate::map::Entry;
11
12/// ```abnf
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/// ```abnf
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 = !path.is_empty();
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 = dotted && !parent_table.is_implicit();
228        if mixed_table_types {
229            #[cfg(feature = "debug")]
230            trace(
231                &format!("dotted={dotted}"),
232                anstyle::AnsiColor::Red.on_default(),
233            );
234            #[cfg(feature = "debug")]
235            trace(
236                &format!("parent_table.is_implicit={}", parent_table.is_implicit()),
237                anstyle::AnsiColor::Red.on_default(),
238            );
239            let key_span = get_key_span(&key);
240            errors.report_error(ParseError::new("duplicate key").with_unexpected(key_span));
241            return;
242        }
243        let key_span = get_key_span(&key);
244        match parent_table.entry(key) {
245            Entry::Vacant(o) => {
246                o.insert(value);
247            }
248            Entry::Occupied(existing) => {
249                // "Since tables cannot be defined more than once, redefining such tables using a [table] header is not allowed"
250                let old_span = get_key_span(existing.key());
251                errors.report_error(
252                    ParseError::new("duplicate key")
253                        .with_unexpected(key_span)
254                        .with_context(old_span),
255                );
256            }
257        }
258    }
259
260    fn finish_table(&mut self, errors: &mut dyn ErrorSink) {
261        #[cfg(feature = "debug")]
262        let _scope = TraceScope::new("document::finish_table");
263        let prev_table = core::mem::take(&mut self.current_table);
264        if let Some(header) = self.current_header.take() {
265            let Some(key) = &header.key else {
266                return;
267            };
268            let header_span = header.span.start()..header.span.end();
269            let prev_table = Spanned::new(header_span.clone(), DeValue::Table(prev_table));
270
271            let parent_key = &header.path;
272            let dotted = false;
273            let Some(parent_table) = descend_path(&mut self.root, parent_key, dotted, errors)
274            else {
275                return;
276            };
277            #[cfg(feature = "debug")]
278            trace(
279                &format!("key={key}",),
280                anstyle::AnsiColor::Blue.on_default(),
281            );
282            if header.is_array {
283                let entry = parent_table.entry(key.clone()).or_insert_with(|| {
284                    let mut array = DeArray::new();
285                    array.set_array_of_tables(true);
286                    Spanned::new(header_span, DeValue::Array(array))
287                });
288                let Some(array) = entry
289                    .as_mut()
290                    .as_array_mut()
291                    .filter(|a| a.is_array_of_tables())
292                else {
293                    #[cfg(feature = "debug")]
294                    trace(
295                        "is_array_of_tables=false",
296                        anstyle::AnsiColor::Red.on_default(),
297                    );
298                    let key_span = get_key_span(key);
299                    let old_span = entry.span();
300                    let old_span = toml_parser::Span::new_unchecked(old_span.start, old_span.end);
301                    errors.report_error(
302                        ParseError::new("duplicate key")
303                            .with_unexpected(key_span)
304                            .with_context(old_span),
305                    );
306                    return;
307                };
308                array.push(prev_table);
309            } else {
310                let existing = parent_table.insert(key.clone(), prev_table);
311                debug_assert!(existing.is_none());
312            }
313        } else {
314            self.root = prev_table;
315        }
316    }
317
318    fn start_table(&mut self, header: TableHeader<'i>, errors: &mut dyn ErrorSink) {
319        if !header.is_array {
320            // 1. Look up the table on start to ensure the duplicate_key error points to the right line
321            // 2. Ensure any child tables from an implicit table are preserved
322            let root = &mut self.root;
323            if let (Some(parent_table), Some(key)) =
324                (descend_path(root, &header.path, false, errors), &header.key)
325            {
326                if let Some((old_key, old_value)) = parent_table.remove_entry(key) {
327                    match old_value.into_inner() {
328                        DeValue::Table(t) if t.is_implicit() && !t.is_dotted() => {
329                            self.current_table = t;
330                        }
331                        // 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.
332                        old_value => {
333                            #[cfg(feature = "debug")]
334                            if let DeValue::Table(t) = &old_value {
335                                trace(
336                                    &format!("t.dotted={}", t.is_dotted()),
337                                    anstyle::AnsiColor::Red.on_default(),
338                                );
339                                trace(
340                                    &format!("t.is_implicit={}", t.is_implicit()),
341                                    anstyle::AnsiColor::Red.on_default(),
342                                );
343                            } else {
344                                trace(
345                                    &format!("old_value.type_str={}", old_value.type_str()),
346                                    anstyle::AnsiColor::Red.on_default(),
347                                );
348                            }
349                            let old_span = get_key_span(&old_key);
350                            let key_span = get_key_span(key);
351                            errors.report_error(
352                                ParseError::new("duplicate key")
353                                    .with_unexpected(key_span)
354                                    .with_context(old_span),
355                            );
356
357                            if let DeValue::Table(t) = old_value {
358                                self.current_table = t;
359                            }
360                        }
361                    }
362                }
363            }
364        }
365
366        self.current_position += 1;
367        self.current_table.set_implicit(false);
368        self.current_table.set_dotted(false);
369        self.current_header = Some(header);
370    }
371}
372
373fn descend_path<'t, 'i>(
374    mut table: &'t mut DeTable<'i>,
375    path: &[Spanned<DeString<'i>>],
376    dotted: bool,
377    errors: &mut dyn ErrorSink,
378) -> Option<&'t mut DeTable<'i>> {
379    #[cfg(feature = "debug")]
380    let _scope = TraceScope::new("document::descend_path");
381    #[cfg(feature = "debug")]
382    trace(
383        &format!(
384            "path={:?}",
385            path.iter().map(|k| k.get_ref()).collect::<Vec<_>>()
386        ),
387        anstyle::AnsiColor::Blue.on_default(),
388    );
389    for key in path.iter() {
390        #[cfg(feature = "debug")]
391        trace(
392            &format!("path[_]={:?}", key.get_ref()),
393            anstyle::AnsiColor::Blue.on_default(),
394        );
395        table = match table.entry(key.clone()) {
396            Entry::Vacant(entry) => {
397                let mut new_table = DeTable::new();
398                new_table.set_implicit(true);
399                new_table.set_dotted(dotted);
400
401                let value = DeValue::Table(new_table);
402                let value = Spanned::new(key.span(), value);
403                let value = entry.insert(value);
404                value.as_mut().as_table_mut().unwrap()
405            }
406            Entry::Occupied(entry) => {
407                let spanned = entry.into_mut();
408                let old_span = spanned.span();
409                match spanned.as_mut() {
410                    DeValue::Array(array) => {
411                        if !array.is_array_of_tables() {
412                            let old_span =
413                                toml_parser::Span::new_unchecked(old_span.start, old_span.end);
414                            let key_span = get_key_span(key);
415                            errors.report_error(
416                                ParseError::new(
417                                    "cannot extend value of type array with a dotted key",
418                                )
419                                .with_unexpected(key_span)
420                                .with_context(old_span),
421                            );
422                            return None;
423                        }
424
425                        debug_assert!(!array.is_empty());
426
427                        let index = array.len() - 1;
428                        let last_child = array.get_mut(index).unwrap();
429
430                        match last_child.as_mut() {
431                            DeValue::Table(table) => table,
432                            existing => {
433                                let old_span =
434                                    toml_parser::Span::new_unchecked(old_span.start, old_span.end);
435                                let key_span = get_key_span(key);
436                                errors.report_error(
437                                    ParseError::new(format!(
438                                        "cannot extend value of type {} with a dotted key",
439                                        existing.type_str()
440                                    ))
441                                    .with_unexpected(key_span)
442                                    .with_context(old_span),
443                                );
444                                return None;
445                            }
446                        }
447                    }
448                    DeValue::Table(sweet_child_of_mine) => {
449                        if sweet_child_of_mine.is_inline() {
450                            let key_span = get_key_span(key);
451                            errors.report_error(
452                                ParseError::new(
453                                    "cannot extend value of type inline table with a dotted key",
454                                )
455                                .with_unexpected(key_span),
456                            );
457                            return None;
458                        }
459                        if dotted && sweet_child_of_mine.is_implicit() {
460                            // Since tables cannot be defined more than once, redefining such tables using a
461                            // [table] header is not allowed. Likewise, using dotted keys to redefine tables
462                            // already defined in [table] form is not allowed.
463                            sweet_child_of_mine.set_dotted(true);
464                        }
465                        // Since tables cannot be defined more than once, redefining such tables using a
466                        // [table] header is not allowed. Likewise, using dotted keys to redefine tables
467                        // already defined in [table] form is not allowed.
468                        let mixed_table_types = dotted && !sweet_child_of_mine.is_implicit();
469                        if mixed_table_types {
470                            #[cfg(feature = "debug")]
471                            trace(
472                                &format!("dotted={dotted}"),
473                                anstyle::AnsiColor::Red.on_default(),
474                            );
475                            #[cfg(feature = "debug")]
476                            trace(
477                                &format!(
478                                    "sweet_child_of_mine.is_implicit={}",
479                                    sweet_child_of_mine.is_implicit()
480                                ),
481                                anstyle::AnsiColor::Red.on_default(),
482                            );
483                            let key_span = get_key_span(key);
484                            errors.report_error(
485                                ParseError::new("duplicate key").with_unexpected(key_span),
486                            );
487                            return None;
488                        }
489                        sweet_child_of_mine
490                    }
491                    existing => {
492                        let old_span =
493                            toml_parser::Span::new_unchecked(old_span.start, old_span.end);
494                        let key_span = get_key_span(key);
495                        errors.report_error(
496                            ParseError::new(format!(
497                                "cannot extend value of type {} with a dotted key",
498                                existing.type_str()
499                            ))
500                            .with_unexpected(key_span)
501                            .with_context(old_span),
502                        );
503                        return None;
504                    }
505                }
506            }
507        };
508    }
509    Some(table)
510}
511
512fn get_key_span(key: &Spanned<DeString<'_>>) -> toml_parser::Span {
513    let key_span = key.span();
514    toml_parser::Span::new_unchecked(key_span.start, key_span.end)
515}