toml/de/parser/
inline_table.rs

1use serde_spanned::Spanned;
2
3use crate::alloc_prelude::*;
4use crate::de::parser::array::on_array;
5use crate::de::parser::key::on_key;
6use crate::de::parser::prelude::*;
7use crate::de::parser::value::on_scalar;
8use crate::de::DeString;
9use crate::de::DeTable;
10use crate::de::DeValue;
11use crate::map::Entry;
12
13/// ```abnf
14/// ;; Inline Table
15///
16/// inline-table = inline-table-open [ inline-table-keyvals ] ws-comment-newline inline-table-close
17/// ```
18pub(crate) fn on_inline_table<'i>(
19    open_event: &toml_parser::parser::Event,
20    input: &mut Input<'_>,
21    source: toml_parser::Source<'i>,
22    errors: &mut dyn ErrorSink,
23) -> Spanned<DeValue<'i>> {
24    #[cfg(feature = "debug")]
25    let _scope = TraceScope::new("inline_table::on_inline_table");
26    let mut result = DeTable::new();
27    result.set_inline(true);
28    let mut close_span = open_event.span();
29
30    let mut state = State::default();
31    while let Some(event) = input.next_token() {
32        close_span = event.span();
33        match event.kind() {
34            EventKind::StdTableOpen
35            | EventKind::ArrayTableOpen
36            | EventKind::StdTableClose
37            | EventKind::ArrayClose
38            | EventKind::ArrayTableClose
39            | EventKind::KeySep => {
40                #[cfg(feature = "debug")]
41                trace(
42                    &format!("unexpected {event:?}"),
43                    anstyle::AnsiColor::Red.on_default(),
44                );
45                break;
46            }
47            EventKind::Error => {
48                #[cfg(feature = "debug")]
49                trace(
50                    &format!("unexpected {event:?}"),
51                    anstyle::AnsiColor::Red.on_default(),
52                );
53                continue;
54            }
55            EventKind::SimpleKey => {
56                let (path, key) = on_key(event, input, source, errors);
57                state.capture_key(event, path, key);
58            }
59            EventKind::KeyValSep => {
60                state.finish_key(event);
61            }
62            EventKind::InlineTableOpen => {
63                let value = on_inline_table(event, input, source, errors);
64                state.capture_value(event, value);
65            }
66            EventKind::ArrayOpen => {
67                let value = on_array(event, input, source, errors);
68                state.capture_value(event, value);
69            }
70            EventKind::Scalar => {
71                let value = on_scalar(event, source, errors);
72                state.capture_value(event, value);
73            }
74            EventKind::ValueSep => {
75                state.finish_value(event, &mut result, errors);
76            }
77            EventKind::Whitespace | EventKind::Comment | EventKind::Newline => {
78                state.whitespace(event);
79            }
80            EventKind::InlineTableClose => {
81                state.finish_value(event, &mut result, errors);
82                state.close(open_event, event, &mut result);
83                break;
84            }
85        }
86    }
87
88    let span = open_event.span().start()..close_span.end();
89
90    Spanned::new(span, DeValue::Table(result))
91}
92
93#[derive(Default)]
94struct State<'i> {
95    current_key: Option<(Vec<Spanned<DeString<'i>>>, Spanned<DeString<'i>>)>,
96    seen_keyval_sep: bool,
97    current_value: Option<Spanned<DeValue<'i>>>,
98}
99
100impl<'i> State<'i> {
101    fn whitespace(&mut self, _event: &toml_parser::parser::Event) {}
102
103    fn capture_key(
104        &mut self,
105        _event: &toml_parser::parser::Event,
106        path: Vec<Spanned<DeString<'i>>>,
107        key: Option<Spanned<DeString<'i>>>,
108    ) {
109        #[cfg(feature = "debug")]
110        let _scope = TraceScope::new("inline_table::capture_key");
111        if let Some(key) = key {
112            self.current_key = Some((path, key));
113        }
114    }
115
116    fn finish_key(&mut self, _event: &toml_parser::parser::Event) {
117        #[cfg(feature = "debug")]
118        let _scope = TraceScope::new("inline_table::finish_key");
119        self.seen_keyval_sep = true;
120    }
121
122    fn capture_value(&mut self, _event: &toml_parser::parser::Event, value: Spanned<DeValue<'i>>) {
123        #[cfg(feature = "debug")]
124        let _scope = TraceScope::new("inline_table::capture_value");
125        self.current_value = Some(value);
126    }
127
128    fn finish_value(
129        &mut self,
130        _event: &toml_parser::parser::Event,
131        result: &mut DeTable<'i>,
132        errors: &mut dyn ErrorSink,
133    ) {
134        #[cfg(feature = "debug")]
135        let _scope = TraceScope::new("inline_table::finish_value");
136        self.seen_keyval_sep = false;
137        if let (Some((path, key)), Some(value)) =
138            (self.current_key.take(), self.current_value.take())
139        {
140            let Some(table) = descend_path(result, &path, true, errors) else {
141                return;
142            };
143
144            // "Likewise, using dotted keys to redefine tables already defined in [table] form is not allowed"
145            let mixed_table_types = table.is_dotted() == path.is_empty();
146            if mixed_table_types {
147                let key_span = get_key_span(&key);
148                errors.report_error(ParseError::new("duplicate key").with_unexpected(key_span));
149            } else {
150                let key_span = get_key_span(&key);
151                match table.entry(key) {
152                    Entry::Vacant(o) => {
153                        o.insert(value);
154                    }
155                    Entry::Occupied(o) => {
156                        let old_span = get_key_span(o.key());
157                        errors.report_error(
158                            ParseError::new("duplicate key")
159                                .with_unexpected(key_span)
160                                .with_context(old_span),
161                        );
162                    }
163                }
164            }
165        }
166    }
167
168    fn close(
169        &mut self,
170        _open_event: &toml_parser::parser::Event,
171        _close_event: &toml_parser::parser::Event,
172        _result: &mut DeTable<'i>,
173    ) {
174        #[cfg(feature = "debug")]
175        let _scope = TraceScope::new("inline_table::close");
176    }
177}
178
179fn descend_path<'a, 'i>(
180    mut table: &'a mut DeTable<'i>,
181    path: &'a [Spanned<DeString<'i>>],
182    dotted: bool,
183    errors: &mut dyn ErrorSink,
184) -> Option<&'a mut DeTable<'i>> {
185    #[cfg(feature = "debug")]
186    let _scope = TraceScope::new("inline_table::descend_path");
187    #[cfg(feature = "debug")]
188    trace(
189        &format!(
190            "key={:?}",
191            path.iter().map(|k| k.get_ref()).collect::<Vec<_>>()
192        ),
193        anstyle::AnsiColor::Blue.on_default(),
194    );
195    for key in path.iter() {
196        table = match table.entry(key.clone()) {
197            Entry::Vacant(entry) => {
198                let mut new_table = DeTable::new();
199                new_table.set_implicit(true);
200                new_table.set_dotted(dotted);
201                new_table.set_inline(true);
202                let value = DeValue::Table(new_table);
203                let value = Spanned::new(key.span(), value);
204                let value = entry.insert(value);
205                value.as_mut().as_table_mut().unwrap()
206            }
207            Entry::Occupied(entry) => {
208                let spanned = entry.into_mut();
209                match spanned.as_mut() {
210                    DeValue::Table(ref mut sweet_child_of_mine) => {
211                        // Since tables cannot be defined more than once, redefining such tables using a
212                        // [table] header is not allowed. Likewise, using dotted keys to redefine tables
213                        // already defined in [table] form is not allowed.
214                        if dotted && !sweet_child_of_mine.is_implicit() {
215                            let key_span = get_key_span(key);
216                            errors.report_error(
217                                ParseError::new("duplicate key").with_unexpected(key_span),
218                            );
219                            return None;
220                        }
221                        sweet_child_of_mine
222                    }
223                    item => {
224                        let key_span = get_key_span(key);
225                        errors.report_error(
226                            ParseError::new(format!(
227                                "cannot extend value of type {} with a dotted key",
228                                item.type_str()
229                            ))
230                            .with_unexpected(key_span),
231                        );
232                        return None;
233                    }
234                }
235            }
236        };
237    }
238    Some(table)
239}
240
241fn get_key_span(key: &Spanned<DeString<'_>>) -> toml_parser::Span {
242    let key_span = key.span();
243    toml_parser::Span::new_unchecked(key_span.start, key_span.end)
244}